HWND CDefTermHk::AllocHiddenConsole(bool bTempForVS) { // функция AttachConsole есть только в WinXP и выше AttachConsole_t _AttachConsole = GetAttachConsoleProc(); if (!_AttachConsole) { LogHookingStatus(L"Can't create hidden console, function does not exist"); return NULL; } LogHookingStatus(L"AllocHiddenConsole"); ReloadSettings(); _ASSERTEX(isDefTermEnabled() && (gbIsNetVsHost || bTempForVS)); if (!isDefTermEnabled()) { // Disabled in settings or registry LogHookingStatus(L"Application skipped by settings"); return NULL; } HANDLE hSrvProcess = NULL; DWORD nAttachPID = bTempForVS ? 0 : gnSelfPID; DWORD nSrvPID = StartConsoleServer(nAttachPID, true, &hSrvProcess); if (!nSrvPID) { // Failed to start process? return NULL; } _ASSERTEX(hSrvProcess!=NULL); HWND hCreatedCon = NULL; // Do while server process is alive DWORD nStart = GetTickCount(), nMaxDelta = 30000, nDelta = 0; DWORD nWait = WaitForSingleObject(hSrvProcess, 0); while (nWait != WAIT_OBJECT_0) { if (_AttachConsole(nSrvPID)) { hCreatedCon = GetRealConsoleWindow(); if (hCreatedCon) break; } nWait = WaitForSingleObject(hSrvProcess, 150); nDelta = (GetTickCount() - nStart); if (nDelta > nMaxDelta) break; } return hCreatedCon; }
gboolean GlibUtils_AttachConsole(void) { typedef BOOL (WINAPI *AttachConsoleFn)(DWORD); gboolean ret = TRUE; AttachConsoleFn _AttachConsole; BOOL reopenStdout; BOOL reopenStderr; if (GetConsoleWindow() != NULL) { goto exit; } reopenStdout = !GlibUtilsIsRedirected(STD_OUTPUT_HANDLE); reopenStderr = !GlibUtilsIsRedirected(STD_ERROR_HANDLE); if (!reopenStdout && !reopenStderr) { goto exit; } _AttachConsole = (AttachConsoleFn) GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "AttachConsole"); if ((_AttachConsole != NULL && _AttachConsole(ATTACH_PARENT_PROCESS)) || AllocConsole()) { FILE *fptr; if (reopenStdout) { fptr = _wfreopen(L"CONOUT$", L"a", stdout); if (fptr == NULL) { g_warning("_wfreopen failed for stdout/CONOUT$: %d (%s)", errno, strerror(errno)); ret = FALSE; } } if (reopenStderr) { fptr = _wfreopen(L"CONOUT$", L"a", stderr); if (fptr == NULL) { g_warning("_wfreopen failed for stderr/CONOUT$: %d (%s)", errno, strerror(errno)); ret = FALSE; } else { setvbuf(fptr, NULL, _IONBF, 0); } } } else { ret = FALSE; } exit: if (!ret) { g_warning("Console redirection unavailable."); } return ret; }
bool AttachServerConsole() { bool lbAttachRc = false; DWORD nErrCode; HWND hCurCon = GetRealConsoleWindow(); if (hCurCon == NULL && gnServerPID != 0) { // функция есть только в WinXP и выше AttachConsole_t _AttachConsole = GetAttachConsoleProc(); if (_AttachConsole) { lbAttachRc = (_AttachConsole(gnServerPID) != 0); if (!lbAttachRc) { nErrCode = GetLastError(); _ASSERTE(nErrCode==0 && lbAttachRc); } } } return lbAttachRc; }
void OpenConsole() { COORD csize; CONSOLE_SCREEN_BUFFER_INFO csbiInfo; SMALL_RECT srect; char buf[256]; //dont do anything if we're already attached if (hConsole) return; //attach to an existing console (if we can; this is circuitous because AttachConsole wasnt added until XP) //remember to abstract this late bound function notion if we end up having to do this anywhere else bool attached = false; HMODULE lib = LoadLibrary("kernel32.dll"); if(lib) { typedef BOOL (WINAPI *_TAttachConsole)(DWORD dwProcessId); _TAttachConsole _AttachConsole = (_TAttachConsole)GetProcAddress(lib,"AttachConsole"); if(_AttachConsole) { if(_AttachConsole(-1)) attached = true; } FreeLibrary(lib); } //if we failed to attach, then alloc a new console if(!attached) { AllocConsole(); } hConsole = GetStdHandle(STD_OUTPUT_HANDLE); //redirect stdio long lStdHandle = (long)hConsole; int hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); if(hConHandle == -1) return; //this fails from a visual studio command prompt FILE *fp = _fdopen( hConHandle, "w" ); *stdout = *fp; //and stderr *stderr = *fp; memset(buf,0,256); sprintf(buf,"%s OUTPUT", DESMUME_NAME_AND_VERSION); SetConsoleTitle(TEXT(buf)); csize.X = 60; csize.Y = 800; SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), csize); GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbiInfo); srect = csbiInfo.srWindow; srect.Right = srect.Left + 99; srect.Bottom = srect.Top + 64; SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &srect); SetConsoleCP(GetACP()); SetConsoleOutputCP(GetACP()); if(attached) printlog("\n"); printlog("%s\n",DESMUME_NAME_AND_VERSION); printlog("- compiled: %s %s\n\n",__DATE__,__TIME__); }
// запустить через ShellExecuteEx в скрытом режиме // (см. шаманство с консолью) static BOOL ExecuteHide( CPath& path, DWORD* out_exitcode, CSimpleString* strOut ) { HANDLE hSaveStdin = NULL; HANDLE hSaveStdout = NULL; HANDLE hChildStdoutRdDup = NULL; HANDLE hChildStdoutWr = NULL; try { // подключаем консоль STARTUPINFOA si = { sizeof(STARTUPINFOA) }; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; PROCESS_INFORMATION pi = { 0 }; char command_line[] = "cmd"; ::CreateProcessA( NULL, // не используем имя файла, все в строке запуска command_line, // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable TRUE, // Set handle inheritance to FALSE 0, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // STARTUPINFO &pi ); // PROCESS_INFORMATION // задержка чтобы консоль успела создаться ::WaitForSingleObject( pi.hProcess, 100 ); BOOL hResult = FALSE; HMODULE hLib = LoadLibraryA("Kernel32.dll"); if ( hLib != NULL ) { typedef BOOL (STDAPICALLTYPE *ATTACHCONSOLE)( DWORD dwProcessId ); ATTACHCONSOLE _AttachConsole = NULL; _AttachConsole = (ATTACHCONSOLE)GetProcAddress( hLib, "AttachConsole" ); if ( _AttachConsole ) hResult = _AttachConsole( pi.dwProcessId ); FreeLibrary( hLib ); } if ( hResult == FALSE ) AllocConsole(); TerminateProcess( pi.hProcess, 0 ); CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); HANDLE hChildStdinRd; HANDLE hChildStdinWr; HANDLE hChildStdinWrDup; HANDLE hChildStdoutRd; // Set the bInheritHandle flag so pipe handles are inherited. SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; BOOL fSuccess; // The steps for redirecting child process's STDOUT: // 1. Save current STDOUT, to be restored later. // 2. Create anonymous pipe to be STDOUT for child process. // 3. Set STDOUT of the parent process to be write handle to // the pipe, so it is inherited by the child process. // 4. Create a noninheritable duplicate of the read handle and // close the inheritable read handle. // Save the handle to the current STDOUT. hSaveStdout = GetStdHandle( STD_OUTPUT_HANDLE ); // Create a pipe for the child process's STDOUT. if ( !CreatePipe( &hChildStdoutRd, &hChildStdoutWr, &saAttr, 0 ) ) throw(1); // Set a write handle to the pipe to be STDOUT. if ( !SetStdHandle( STD_OUTPUT_HANDLE, hChildStdoutWr ) ) throw(1); // Create noninheritable read handle and close the inheritable read // handle. fSuccess = DuplicateHandle( GetCurrentProcess(), hChildStdoutRd, GetCurrentProcess(), &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS ); if( fSuccess == FALSE ) throw(1); CloseHandle( hChildStdoutRd ); // The steps for redirecting child process's STDIN: // 1. Save current STDIN, to be restored later. // 2. Create anonymous pipe to be STDIN for child process. // 3. Set STDIN of the parent to be the read handle to the // pipe, so it is inherited by the child process. // 4. Create a noninheritable duplicate of the write handle, // and close the inheritable write handle. // Save the handle to the current STDIN. hSaveStdin = GetStdHandle( STD_INPUT_HANDLE ); // Create a pipe for the child process's STDIN. if ( !CreatePipe( &hChildStdinRd, &hChildStdinWr, &saAttr, 0 ) ) throw(1); // Set a read handle to the pipe to be STDIN. if ( !SetStdHandle( STD_INPUT_HANDLE, hChildStdinRd ) ) throw(1); // Duplicate the write handle to the pipe so it is not inherited. fSuccess = DuplicateHandle( GetCurrentProcess(), hChildStdinWr, GetCurrentProcess(), &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS ); if ( fSuccess == FALSE ) throw(1); CloseHandle( hChildStdinWr ); } catch (...) { return FALSE; } // Now create the child process. SHELLEXECUTEINFOA shinf = { sizeof(SHELLEXECUTEINFOA) }; shinf.lpFile = path.GetPath(); shinf.lpParameters = path.GetFileParams(); //shinf.lpDirectory = path.GetDirectory(); shinf.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS; shinf.nShow = SW_HIDE; BOOL bSuccess = ::ShellExecuteExA( &shinf ); if ( bSuccess && shinf.hInstApp <= (HINSTANCE)32 ) bSuccess = FALSE; HANDLE hProcess = shinf.hProcess; try { if ( bSuccess == FALSE || hProcess == NULL ) throw(1); if ( hChildStdoutWr != NULL ) { CloseHandle( hChildStdoutWr ); hChildStdoutWr = NULL; } // After process creation, restore the saved STDIN and STDOUT. if ( hSaveStdin != NULL ) { if ( !SetStdHandle( STD_INPUT_HANDLE, hSaveStdin ) ) throw(1); CloseHandle( hSaveStdin ); hSaveStdin = NULL; } if ( hSaveStdout != NULL ) { if ( !SetStdHandle( STD_OUTPUT_HANDLE, hSaveStdout ) ) throw(1); CloseHandle( hSaveStdout ); hSaveStdout = NULL; } if ( hChildStdoutRdDup != NULL ) { // Read output from the child process, and write to parent's STDOUT. const int BUFSIZE = 1024; DWORD dwRead; CMemBuffer< char, BUFSIZE > bufStr; // строковой буфер CMemBuffer< char, BUFSIZE > bufCmdLine; // строковой буфер for (;;) { if( ReadFile( hChildStdoutRdDup, bufCmdLine.GetBuffer(), BUFSIZE, &dwRead, NULL ) == FALSE || dwRead == 0 ) { DWORD exit_code = 0; if ( ::GetExitCodeProcess( hProcess, &exit_code ) == FALSE || exit_code != STILL_ACTIVE ) { break; } else { continue; } } bufCmdLine[ dwRead ] = '\0'; ::OemToAnsi( bufCmdLine.GetBuffer(), bufStr.GetBuffer() ); strOut->Append( bufStr.GetBuffer() ); } CloseHandle( hChildStdoutRdDup ); hChildStdoutRdDup = NULL; } FreeConsole(); } catch (...) { if ( hChildStdoutWr != NULL ) CloseHandle( hChildStdoutWr ); if ( hSaveStdin != NULL ) CloseHandle( hSaveStdin ); if ( hSaveStdout != NULL ) CloseHandle( hSaveStdout ); if ( hChildStdoutRdDup != NULL ) CloseHandle( hChildStdoutRdDup ); if ( bSuccess == FALSE || hProcess == NULL ) return FALSE; } ::GetExitCodeProcess( hProcess, out_exitcode ); CloseHandle( hProcess ); return TRUE; }