Mike Williams wrote:
> On 09/08/2007 14:49, Ilya Bobir wrote:
>
>> Mike Williams wrote:
>>
>>> Hi
>>>
>>> [...]
>>>
>>> Yep, I submitted a patch along these lines. Unfortunately, I still
>>> don't think it's a solution. I still managed to end up with a rogue
>>> sticky command prompt. This was on XP SP2 so using GetConsoleWindow() -
>>> looks like a bug in Windows where the message is getting lost when the
>>> system is loaded. Unless there is a deeper darker Windows way of
>>> ensuring messages don't get lost.
>>>
>>>
>> I don't think this is a bug. According to MSDN
>> (http://msdn2.microsoft.com/en-us/library/ms683175.aspx)
>> GetConsoleWindow() is supposed to return the handle of the console of
>> the calling process. GVim has no console so, GetConsoleWindow() will
>> return NULL.
>>
>> Whenever a console process is started it needs a console. If parent
>> process does not have one then a new console will be automatically
>> allocated and associated with the child process.
>> I think that looking for the console created for the child process is
>> actually incorrect approach to the problem and thus it does not work
>> reliably.
>>
>> If you what a child process to interact with a console your process
>> controls you need to create one in your parent process and ensure that
>> child process uses your console.
>> If child process does not explicitly detaches from the parent console
>> than by default everything should be as easy as: AllocConsole(),
>> GetConsoleWindow(), [HideWindow()], CreateProcess().
>>
>
> The code in if_cscope does AllocConsole-GetConsoleWindow-HideWindow.
Sorry, should have read the code. =)
>
> What I am wondering is if under a suitable load, the call to
> GetConsoleWindow fails to return a handle due to the console not having
> been created - I cannot see any other reason why the command prompt
> window would remain other than no handle was returned (unless the
> message to hide gets lost).
>
> As I said, I have added some code locally to track what is happening and
> will see what happens on my machine over the next week. I haven't ruled
> out user error just yet. ;-) The problem was regular but not predictable.
>
>
>> It may be possible, to do without the console altogether.
>> The STARTUPINFO structure that is passed into the CreateProcess() call
>> has 3 field that may be filled with input/output handles for the new
>> process (HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError;).
>> I think that if the parent process will create 3 pipes and will pass
>> appropriate ends of the pipes to the child process, then the child will
>> not have to allocate a console.
>>
>
> Sounds like a cunning plan, which I did start looking into. Part of the
> issue is that the connection to cscope is created via a call to
> spawnlp() and it was getting into more than I could solve in a couple of
> hours one evening.
>
> IIRC the cscope code was originally unix only and has been hacked to add
> Win32 support where necessary to be able to use the original posix calls
> (many apologies to whoever if I am doing them a disservice) which makes
> changing how the connection is done under windows non-trivial. It would
> be nice to use CreateProcess to avoid the call to spawnlp() altogether,
> but note that CREATE_NO_WINDOW cannot be used with Win ME/9x so it is
> not a complete solution - they will still need the window title hide
> hack to remove the console.
> [...]
>
It does work on NT. But CreateProcess(..., CREATE_NO_WINDOW, ...) is
needed. An example implementation is attached.
As code in cs_create_connection() already differentiate between Unix and
Windows platforms why not add another #ifdef and provide proper console
support for the NT?
Maybe replacing 10 #ifdef's with just one can even make code more
readable, besides adding new functionality.
And regarding the Win9x: I've found that WaitForInputIdle() call can be
of use.
How long does it take cscope to start accepting user input?
According to the description of this function it is the function the
parent process should call before communicating with a child process. I
think that complete console allocation can be considered a part of
process initialization.
This function is available starting from Windows 95.
So, the code should be change to do all the console staff after the
cscope process is launched and after the WaitForInputIdle() call for the
process will return.
--~--~---------~--~----~------------~-------~--~----~
You received this message from the "vim_dev" maillist.
For more information, visit http://www.vim.org/maillist.php
-~----------~----~----~----~------~----~------~--~---
CXX = cl
CXXFLAGS = /EHsc /ZI
cons_bin = cons.exe
main_bin = main.exe
cons_src = cons.cpp
main_src = main.cpp
main_libs = user32.lib
all: $(cons_bin) $(main_bin)
$(cons_bin): $(cons_src) Makefile
$(CXX) $(CXXFLAGS) /Fe$@ $(cons_src)
$(main_bin): $(main_src) Makefile
$(CXX) $(CXXFLAGS) /Fe$@ $(main_src) $(main_libs)
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
cout << "Press Enter when done" << endl;
string s;
getline(cin, s);
return 0;
}
#include <windows.h>
int WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
)
{
SECURITY_ATTRIBUTES sa;
HANDLE read_stdin, write_stdin, read_stdout, write_stdout, read_stderr,
write_stderr;
DWORD err = 0;
ZeroMemory(&sa, sizeof(sa));
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
if (!CreatePipe(&read_stdin, &write_stdin, &sa, 0)) {
err = GetLastError();
return 1;
}
SetHandleInformation(write_stdin, HANDLE_FLAG_INHERIT, 0);
DWORD mode = PIPE_NOWAIT;
if (!SetNamedPipeHandleState(write_stdin, &mode, 0, 0)) {
err = GetLastError();
return 1;
}
if (!CreatePipe(&read_stdout, &write_stdout, &sa, 0)) {
err = GetLastError();
return 1;
}
SetHandleInformation(read_stdout, HANDLE_FLAG_INHERIT, 0);
if (!SetNamedPipeHandleState(read_stdout, &mode, 0, 0)) {
err = GetLastError();
return 1;
}
if (!CreatePipe(&read_stderr, &write_stderr, &sa, 0)) {
err = GetLastError();
return 1;
}
SetHandleInformation(read_stderr, HANDLE_FLAG_INHERIT, 0);
if (!SetNamedPipeHandleState(read_stderr, &mode, 0, 0)) {
err = GetLastError();
return 1;
}
STARTUPINFO startupInfo;
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags = STARTF_USESTDHANDLES;
startupInfo.hStdInput = read_stdin;
startupInfo.hStdOutput = write_stdout;
startupInfo.hStdError = write_stderr;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcess("cons.exe", /* lpApplicationName */
0, /* lpCommandLine */
0, /* lpProcessAttributes */
0, /* lpThreadAttributes */
TRUE, /* bInheritHandles */
CREATE_NO_WINDOW, /* dwCreationFlags */
0, /* lpEnvironment */
0, /* lpCurrentDirectory */
&startupInfo, /* lpStartupInfo */
&pi /* lpProcessInformation */
)) {
err = GetLastError();
return 1;
}
CloseHandle(pi.hThread);
HANDLE childProcess = pi.hProcess;
char buf[10240];
bool enterSent = false;
while (true) {
if (!enterSent) {
char *text = "\n";
DWORD written = 0;
if (WriteFile(write_stdin, text, strlen(text), &written, 0))
enterSent = true;
}
DWORD read = 0;
if (!ReadFile(read_stdout, buf, sizeof(buf), &read, 0)) {
err = GetLastError();
if (err != ERROR_NO_DATA)
break;
} else if (read == 0)
/* EOF for stdout */
break;
else
MessageBox(0, buf, "Console stdout text", MB_OK);
read = 0;
if (!ReadFile(read_stderr, buf, sizeof(buf), &read, 0)) {
err = GetLastError();
if (err != ERROR_NO_DATA)
break;
} else if (read == 0)
/* EOF for stderr */
break;
else
MessageBox(0, buf, "Console stderr text", MB_OK);
if (WaitForSingleObject(childProcess, 0) == WAIT_OBJECT_0)
break;
Sleep(100);
}
CloseHandle(write_stdin);
CloseHandle(read_stdout);
CloseHandle(read_stderr);
CloseHandle(childProcess);
return 0;
}