BOOL WINAPI PlugServerCommand(LPVOID pInst, CESERVER_REQ* pIn, CESERVER_REQ* &ppReply, DWORD &pcbReplySize, DWORD &pcbMaxReplySize, LPARAM lParam) { BOOL lbRc = FALSE; BOOL fSuccess = FALSE; MSectionThread SCT(csTabs); if (pIn->hdr.cbSize < sizeof(CESERVER_REQ_HDR) || /*in.nSize < cbRead ||*/ pIn->hdr.nVersion != CESERVER_REQ_VER) { gpPlugServer->BreakConnection(pInst); return FALSE; } UINT nDataSize = pIn->hdr.cbSize - sizeof(CESERVER_REQ_HDR); // Все данные из пайпа получены, обрабатываем команду и возвращаем (если нужно) результат switch (pIn->hdr.nCmd) { case CMD_LANGCHANGE: { _ASSERTE(nDataSize>=4); //-V112 // LayoutName: "00000409", "00010409", ... // А HKL от него отличается, так что передаем DWORD // HKL в x64 выглядит как: "0x0000000000020409", "0xFFFFFFFFF0010409" DWORD hkl = pIn->dwData[0]; DWORD dwLastError = 0; HKL hkl1 = NULL, hkl2 = NULL; if (hkl) { WCHAR szLoc[10]; _wsprintf(szLoc, SKIPLEN(countof(szLoc)) L"%08x", hkl); hkl1 = LoadKeyboardLayout(szLoc, KLF_ACTIVATE|KLF_REORDER|KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS); hkl2 = ActivateKeyboardLayout(hkl1, KLF_SETFORPROCESS|KLF_REORDER); if (!hkl2) dwLastError = GetLastError(); else fSuccess = TRUE; } pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD)*2; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = fSuccess; ppReply->dwData[1] = fSuccess ? ((DWORD)(LONG)(LONG_PTR)hkl2) : dwLastError; } break; } // CMD_LANGCHANGE #if 0 case CMD_DEFFONT: { // исключение - асинхронный, результат не требуется SetConsoleFontSizeTo(FarHwnd, 4, 6); MoveWindow(FarHwnd, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), 1); // чтобы убрать возможные полосы прокрутки... break; } CMD_DEFFONT #endif case CMD_REQTABS: case CMD_SETWINDOW: { MSectionLock SC; SC.Lock(csTabs, FALSE, 1000); DWORD nSetWindowWait = (DWORD)-1; if (pIn->hdr.nCmd == CMD_SETWINDOW) { ResetEvent(ghSetWndSendTabsEvent); // Для FAR2 - сброс QSearch выполняется в том же макро, в котором актирируется окно if (gFarVersion.dwVerMajor == 1 && pIn->dwData[1]) { // А вот для FAR1 - нужно шаманить Plugin()->ProcessCommand(CMD_CLOSEQSEARCH, TRUE/*bReqMainThread*/, pIn->dwData/*хоть и не нужно?*/); } // Пересылается 2 DWORD BOOL bCmdRc = Plugin()->ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->dwData); DEBUGSTRCMD(L"Plugin: PlugServerThreadCommand: CMD_SETWINDOW waiting...\n"); WARNING("Почему для FAR1 не ждем? Есть возможность заблокироваться в 1.7 или что?"); if ((gFarVersion.dwVerMajor >= 2) && bCmdRc) { DWORD nTimeout = 2000; #ifdef _DEBUG if (IsDebuggerPresent()) nTimeout = 120000; #endif nSetWindowWait = WaitForSingleObject(ghSetWndSendTabsEvent, nTimeout); } if (nSetWindowWait == WAIT_TIMEOUT) { gbForceSendTabs = TRUE; DEBUGSTRCMD(L"Plugin: PlugServerThreadCommand: CMD_SETWINDOW timeout !!!\n"); } else { DEBUGSTRCMD(L"Plugin: PlugServerThreadCommand: CMD_SETWINDOW finished\n"); } } if (gpTabs && (nSetWindowWait != WAIT_TIMEOUT)) { //fSuccess = WriteFile(hPipe, gpTabs, gpTabs->hdr.cbSize, &cbWritten, NULL); pcbReplySize = gpTabs->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { memmove(ppReply->Data, gpTabs->Data, pcbReplySize - sizeof(ppReply->hdr)); lbRc = TRUE; } } SC.Unlock(); break; } // CMD_REQTABS, CMD_SETWINDOW case CMD_FARSETCHANGED: { // Установить переменные окружения // Плагин это получает в ответ на CECMD_RESOURCES, посланное в GUI при загрузке плагина _ASSERTE(nDataSize>=8); FAR_REQ_FARSETCHANGED *pFarSet = (FAR_REQ_FARSETCHANGED*)pIn->Data; cmd_FarSetChanged(pFarSet); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = TRUE; } //_ASSERTE(nDataSize<sizeof(gsMonitorEnvVar)); //gbMonitorEnvVar = false; //// Плагин FarCall "нарушает" COMSPEC (копирует содержимое запускаемого процесса) //bool lbOk = false; //if (nDataSize<sizeof(gsMonitorEnvVar)) //{ // memcpy(gsMonitorEnvVar, pszName, nDataSize); // lbOk = true; //} //UpdateEnvVar(pszName); ////while (*pszName && *pszValue) { //// const wchar_t* pszChanged = pszValue; //// // Для ConEmuOutput == AUTO выбирается по версии ФАРа //// if (!lstrcmpi(pszName, L"ConEmuOutput") && !lstrcmp(pszChanged, L"AUTO")) { //// if (gFarVersion.dwVerMajor==1) //// pszChanged = L"ANSI"; //// else //// pszChanged = L"UNICODE"; //// } //// // Если в pszValue пустая строка - удаление переменной //// SetEnvironmentVariableW(pszName, (*pszChanged != 0) ? pszChanged : NULL); //// // //// pszName = pszValue + lstrlenW(pszValue) + 1; //// if (*pszName == 0) break; //// pszValue = pszName + lstrlenW(pszName) + 1; ////} //gbMonitorEnvVar = lbOk; break; } // CMD_FARSETCHANGED case CMD_DRAGFROM: { #ifdef _DEBUG BOOL *pbClickNeed = (BOOL*)pIn->Data; COORD *crMouse = (COORD *)(pbClickNeed+1); #endif Plugin()->ProcessCommand(CMD_LEFTCLKSYNC, TRUE/*bReqMainThread*/, pIn->Data); CESERVER_REQ* pCmdRet = NULL; Plugin()->ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->Data, &pCmdRet); if (pCmdRet) { //fSuccess = WriteFile(hPipe, pCmdRet, pCmdRet->hdr.cbSize, &cbWritten, NULL); pcbReplySize = pCmdRet->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; memmove(ppReply->Data, pCmdRet->Data, pCmdRet->hdr.cbSize - sizeof(ppReply->hdr)); } Free(pCmdRet); } break; } // CMD_DRAGFROM case CMD_EMENU: { COORD *crMouse = (COORD *)pIn->Data; #ifdef _DEBUG const wchar_t *pszUserMacro = (wchar_t*)(crMouse+1); #endif DWORD ClickArg[2] = {(DWORD)TRUE, (DWORD)MAKELONG(crMouse->X, crMouse->Y)}; // Выделить файл под курсором DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_LEFTCLKSYNC) begin\n"); BOOL lb1 = Plugin()->ProcessCommand(CMD_LEFTCLKSYNC, TRUE/*bReqMainThread*/, ClickArg/*pIn->Data*/); DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_LEFTCLKSYNC) done\n"); // А теперь, собственно вызовем меню DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_EMENU) begin\n"); BOOL lb2 = Plugin()->ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->Data); DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_EMENU) done\n"); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD)*2; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = lb1; ppReply->dwData[1] = lb1; } break; } // CMD_EMENU case CMD_ACTIVEWNDTYPE: { int nWindowType = -1; //CESERVER_REQ Out; //ExecutePrepareCmd(&Out, CMD_ACTIVEWNDTYPE, sizeof(CESERVER_REQ_HDR)+sizeof(DWORD)); if (gFarVersion.dwVerMajor>=2) nWindowType = Plugin()->GetActiveWindowType(); //fSuccess = WriteFile(hPipe, &Out, Out.hdr.cbSize, &cbWritten, NULL); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = nDataSize; } break; } // CMD_ACTIVEWNDTYPE case CECMD_ATTACH2GUI: { BOOL bAttached = Plugin()->Attach2Gui(); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = bAttached; } break; } // CECMD_ATTACH2GUI default: { CESERVER_REQ* pCmdRet = NULL; BOOL lbCmd = Plugin()->ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->Data, &pCmdRet); if (pCmdRet) { //fSuccess = WriteFile(hPipe, pCmdRet, pCmdRet->hdr.cbSize, &cbWritten, NULL); pcbReplySize = pCmdRet->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; memmove(ppReply->Data, pCmdRet->Data, pCmdRet->hdr.cbSize - sizeof(ppReply->hdr)); } Free(pCmdRet); } } // default } // switch (pIn->hdr.nCmd) return lbRc; }
BOOL WINAPI PlugServerCommand(LPVOID pInst, CESERVER_REQ* pIn, CESERVER_REQ* &ppReply, DWORD &pcbReplySize, DWORD &pcbMaxReplySize, LPARAM lParam) { BOOL lbRc = FALSE; //HANDLE hPipe = (HANDLE)ahPipe; //CESERVER_REQ *pIn=NULL; //BYTE cbBuffer[64]; // Для большей части команд нам хватит //DWORD cbRead = 0, cbWritten = 0, dwErr = 0; BOOL fSuccess = FALSE; MSectionThread SCT(csTabs); // Send a message to the pipe server and read the response. //fSuccess = ReadFile(hPipe, cbBuffer, sizeof(cbBuffer), &cbRead, NULL); //dwErr = GetLastError(); //if (!fSuccess && (dwErr != ERROR_MORE_DATA)) //{ // _ASSERTE("ReadFile(pipe) failed"==NULL); // CloseHandle(hPipe); // return 0; //} //pIn = (CESERVER_REQ*)cbBuffer; // Пока cast, если нужно больше - выделим память //_ASSERTE(pIn->hdr.cbSize>=sizeof(CESERVER_REQ_HDR) && cbRead>=sizeof(CESERVER_REQ_HDR)); //_ASSERTE(pIn->hdr.nVersion == CESERVER_REQ_VER); if (pIn->hdr.cbSize < sizeof(CESERVER_REQ_HDR) || /*in.nSize < cbRead ||*/ pIn->hdr.nVersion != CESERVER_REQ_VER) { //CloseHandle(hPipe); gpPlugServer->BreakConnection(pInst); return FALSE; } //int nAllSize = pIn->hdr.cbSize; //pIn = (CESERVER_REQ*)Alloc(nAllSize,1); //_ASSERTE(pIn!=NULL); //if (!pIn) //{ // CloseHandle(hPipe); // return 0; //} //memmove(pIn, cbBuffer, cbRead); //_ASSERTE(pIn->hdr.nVersion==CESERVER_REQ_VER); //LPBYTE ptrData = ((LPBYTE)pIn)+cbRead; //nAllSize -= cbRead; //while(nAllSize>0) //{ // //_tprintf(TEXT("%s\n"), chReadBuf); // // Break if TransactNamedPipe or ReadFile is successful // if (fSuccess) // break; // // Read from the pipe if there is more data in the message. // fSuccess = ReadFile( // hPipe, // pipe handle // ptrData, // buffer to receive reply // nAllSize, // size of buffer // &cbRead, // number of bytes read // NULL); // not overlapped // // Exit if an error other than ERROR_MORE_DATA occurs. // if (!fSuccess && ((dwErr = GetLastError()) != ERROR_MORE_DATA)) // break; // ptrData += cbRead; // nAllSize -= cbRead; //} //TODO("Может возникнуть ASSERT, если консоль была закрыта в процессе чтения"); //_ASSERTE(nAllSize==0); //if (nAllSize>0) //{ // if (((LPVOID)cbBuffer) != ((LPVOID)pIn)) // Free(pIn); // CloseHandle(hPipe); // return 0; // удалось считать не все данные //} UINT nDataSize = pIn->hdr.cbSize - sizeof(CESERVER_REQ_HDR); // Все данные из пайпа получены, обрабатываем команду и возвращаем (если нужно) результат //fSuccess = WriteFile( hPipe, pOut, pOut->nSize, &cbWritten, NULL); if (pIn->hdr.nCmd == CMD_LANGCHANGE) { _ASSERTE(nDataSize>=4); //-V112 // LayoutName: "00000409", "00010409", ... // А HKL от него отличается, так что передаем DWORD // HKL в x64 выглядит как: "0x0000000000020409", "0xFFFFFFFFF0010409" DWORD hkl = pIn->dwData[0]; DWORD dwLastError = 0; HKL hkl1 = NULL, hkl2 = NULL; if (hkl) { WCHAR szLoc[10]; _wsprintf(szLoc, SKIPLEN(countof(szLoc)) L"%08x", hkl); hkl1 = LoadKeyboardLayout(szLoc, KLF_ACTIVATE|KLF_REORDER|KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS); hkl2 = ActivateKeyboardLayout(hkl1, KLF_SETFORPROCESS|KLF_REORDER); if (!hkl2) dwLastError = GetLastError(); else fSuccess = TRUE; } pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD)*2; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = fSuccess; ppReply->dwData[1] = fSuccess ? ((DWORD)(LONG)(LONG_PTR)hkl2) : dwLastError; } } //} else if (pIn->hdr.nCmd == CMD_DEFFONT) { // // исключение - асинхронный, результат не требуется // SetConsoleFontSizeTo(FarHwnd, 4, 6); // MoveWindow(FarHwnd, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), 1); // чтобы убрать возможные полосы прокрутки... else if (pIn->hdr.nCmd == CMD_REQTABS || pIn->hdr.nCmd == CMD_SETWINDOW) { MSectionLock SC; SC.Lock(csTabs, FALSE, 1000); DWORD nSetWindowWait = (DWORD)-1; if (pIn->hdr.nCmd == CMD_SETWINDOW) { ResetEvent(ghSetWndSendTabsEvent); // Для FAR2 - сброс QSearch выполняется в том же макро, в котором актирируется окно if (gFarVersion.dwVerMajor == 1 && pIn->dwData[1]) { // А вот для FAR1 - нужно шаманить ProcessCommand(CMD_CLOSEQSEARCH, TRUE/*bReqMainThread*/, pIn->dwData/*хоть и не нужно?*/); } // Пересылается 2 DWORD BOOL bCmdRc = ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->dwData); DEBUGSTRCMD(L"Plugin: PlugServerThreadCommand: CMD_SETWINDOW waiting...\n"); WARNING("Почему для FAR1 не ждем? Есть возможность заблокироваться в 1.7 или что?"); if ((gFarVersion.dwVerMajor >= 2) && bCmdRc) { DWORD nTimeout = 2000; #ifdef _DEBUG if (IsDebuggerPresent()) nTimeout = 120000; #endif nSetWindowWait = WaitForSingleObject(ghSetWndSendTabsEvent, nTimeout); } DEBUGSTRCMD(L"Plugin: PlugServerThreadCommand: CMD_SETWINDOW finished\n"); } if (gpTabs) { //fSuccess = WriteFile(hPipe, gpTabs, gpTabs->hdr.cbSize, &cbWritten, NULL); pcbReplySize = gpTabs->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { memmove(ppReply->Data, gpTabs->Data, pcbReplySize - sizeof(ppReply->hdr)); lbRc = TRUE; } } SC.Unlock(); } else if (pIn->hdr.nCmd == CMD_FARSETCHANGED) { // Установить переменные окружения // Плагин это получает в ответ на CECMD_RESOURCES, посланное в GUI при загрузке плагина _ASSERTE(nDataSize>=8); FAR_REQ_FARSETCHANGED *pFarSet = (FAR_REQ_FARSETCHANGED*)pIn->Data; cmd_FarSetChanged(pFarSet); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = TRUE; } //_ASSERTE(nDataSize<sizeof(gsMonitorEnvVar)); //gbMonitorEnvVar = false; //// Плагин FarCall "нарушает" COMSPEC (копирует содержимое запускаемого процесса) //bool lbOk = false; //if (nDataSize<sizeof(gsMonitorEnvVar)) //{ // memcpy(gsMonitorEnvVar, pszName, nDataSize); // lbOk = true; //} //UpdateEnvVar(pszName); ////while (*pszName && *pszValue) { //// const wchar_t* pszChanged = pszValue; //// // Для ConEmuOutput == AUTO выбирается по версии ФАРа //// if (!lstrcmpi(pszName, L"ConEmuOutput") && !lstrcmp(pszChanged, L"AUTO")) { //// if (gFarVersion.dwVerMajor==1) //// pszChanged = L"ANSI"; //// else //// pszChanged = L"UNICODE"; //// } //// // Если в pszValue пустая строка - удаление переменной //// SetEnvironmentVariableW(pszName, (*pszChanged != 0) ? pszChanged : NULL); //// // //// pszName = pszValue + lstrlenW(pszValue) + 1; //// if (*pszName == 0) break; //// pszValue = pszName + lstrlenW(pszName) + 1; ////} //gbMonitorEnvVar = lbOk; } else if (pIn->hdr.nCmd == CMD_DRAGFROM) { #ifdef _DEBUG BOOL *pbClickNeed = (BOOL*)pIn->Data; COORD *crMouse = (COORD *)(pbClickNeed+1); #endif ProcessCommand(CMD_LEFTCLKSYNC, TRUE/*bReqMainThread*/, pIn->Data); CESERVER_REQ* pCmdRet = NULL; ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->Data, &pCmdRet); if (pCmdRet) { //fSuccess = WriteFile(hPipe, pCmdRet, pCmdRet->hdr.cbSize, &cbWritten, NULL); pcbReplySize = pCmdRet->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; memmove(ppReply->Data, pCmdRet->Data, pCmdRet->hdr.cbSize - sizeof(ppReply->hdr)); } Free(pCmdRet); } //if (gpCmdRet && gpCmdRet == pCmdRet) //{ // Free(gpCmdRet); // gpCmdRet = NULL; gpData = NULL; gpCursor = NULL; //} } else if (pIn->hdr.nCmd == CMD_EMENU) { COORD *crMouse = (COORD *)pIn->Data; #ifdef _DEBUG const wchar_t *pszUserMacro = (wchar_t*)(crMouse+1); #endif DWORD ClickArg[2] = {TRUE, MAKELONG(crMouse->X, crMouse->Y)}; // Выделить файл под курсором DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_LEFTCLKSYNC) begin\n"); BOOL lb1 = ProcessCommand(CMD_LEFTCLKSYNC, TRUE/*bReqMainThread*/, ClickArg/*pIn->Data*/); DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_LEFTCLKSYNC) done\n"); // А теперь, собственно вызовем меню DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_EMENU) begin\n"); BOOL lb2 = ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->Data); DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_EMENU) done\n"); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD)*2; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = lb1; ppReply->dwData[1] = lb1; } } else if (pIn->hdr.nCmd == CMD_ACTIVEWNDTYPE) { int nWindowType = -1; //CESERVER_REQ Out; //ExecutePrepareCmd(&Out, CMD_ACTIVEWNDTYPE, sizeof(CESERVER_REQ_HDR)+sizeof(DWORD)); if (gFarVersion.dwVerMajor>=2) nWindowType = GetActiveWindowType(); //fSuccess = WriteFile(hPipe, &Out, Out.hdr.cbSize, &cbWritten, NULL); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = nDataSize; } } else { CESERVER_REQ* pCmdRet = NULL; BOOL lbCmd = ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->Data, &pCmdRet); if (pCmdRet) { //fSuccess = WriteFile(hPipe, pCmdRet, pCmdRet->hdr.cbSize, &cbWritten, NULL); pcbReplySize = pCmdRet->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; memmove(ppReply->Data, pCmdRet->Data, pCmdRet->hdr.cbSize - sizeof(ppReply->hdr)); } Free(pCmdRet); } //if (gpCmdRet && gpCmdRet == pCmdRet) { // Free(gpCmdRet); // gpCmdRet = NULL; gpData = NULL; gpCursor = NULL; //} } //// Освободить память //if (((LPVOID)cbBuffer) != ((LPVOID)pIn)) // Free(pIn); //CloseHandle(hPipe); return lbRc; }
//// Эта функция пайп не закрывает! //void CGuiServer::GuiServerThreadCommand(HANDLE hPipe) BOOL CGuiServer::GuiServerCommand(LPVOID pInst, CESERVER_REQ* pIn, CESERVER_REQ* &ppReply, DWORD &pcbReplySize, DWORD &pcbMaxReplySize, LPARAM lParam) { BOOL lbRc = FALSE; CGuiServer* pGSrv = (CGuiServer*)lParam; if (!pGSrv) { _ASSERTE(((CGuiServer*)lParam)!=NULL); pGSrv = &gpConEmu->m_GuiServer; } if (pIn->hdr.bAsync) pGSrv->mp_GuiServer->BreakConnection(pInst); gpSetCls->debugLogCommand(pIn, TRUE, timeGetTime(), 0, pGSrv ? pGSrv->ms_ServerPipe : NULL); #ifdef _DEBUG UINT nDataSize = pIn->hdr.cbSize - sizeof(CESERVER_REQ_HDR); #endif // Все данные из пайпа получены, обрабатываем команду и возвращаем (если нужно) результат #ifdef ALLOW_WINE_MSG if (gbIsWine) { wchar_t szMsg[128]; msprintf(szMsg, countof(szMsg), L"CGuiServer::GuiServerCommand.\nGUI TID=%u\nSrcPID=%u, SrcTID=%u, Cmd=%u", GetCurrentThreadId(), pIn->hdr.nSrcPID, pIn->hdr.nSrcThreadId, pIn->hdr.nCmd); MessageBox(szMsg, MB_ICONINFORMATION); } #endif switch (pIn->hdr.nCmd) { case CECMD_NEWCMD: { // Приходит из другой копии ConEmu.exe, когда она запущена с ключом /single, /showhide, /showhideTSA DEBUGSTRCMD(L"GUI recieved CECMD_NEWCMD\n"); LPCWSTR pszCommand = pIn->NewCmd.GetCommand(); _ASSERTE(pszCommand!=NULL && "Must be at least empty string but NOT NULL"); if (pIn->NewCmd.isAdvLogging && !gpSetCls->isAdvLogging) { gpSetCls->isAdvLogging = pIn->NewCmd.isAdvLogging; gpConEmu->CreateLog(); } if (gpSetCls->isAdvLogging && (pIn->NewCmd.isAdvLogging > gpSetCls->isAdvLogging)) { wchar_t szLogLevel[80]; _wsprintf(szLogLevel, SKIPLEN(countof(szLogLevel)) L"Changing log level! Old=%u, New=%u", (UINT)gpSetCls->isAdvLogging, (UINT)pIn->NewCmd.isAdvLogging); gpConEmu->LogString(szLogLevel); gpSetCls->isAdvLogging = pIn->NewCmd.isAdvLogging; } if (gpSetCls->isAdvLogging) { size_t cchAll = 120 + _tcslen(pIn->NewCmd.szConEmu) + _tcslen(pIn->NewCmd.szCurDir) + _tcslen(pszCommand); wchar_t* pszInfo = (wchar_t*)malloc(cchAll*sizeof(*pszInfo)); if (pszInfo) { _wsprintf(pszInfo, SKIPLEN(cchAll) L"CECMD_NEWCMD: Wnd=x%08X, Act=%u, ConEmu=%s, Dir=%s, Cmd=%s", (DWORD)(DWORD_PTR)pIn->NewCmd.hFromConWnd, pIn->NewCmd.ShowHide, pIn->NewCmd.szConEmu, pIn->NewCmd.szCurDir, pszCommand); gpConEmu->LogString(pszInfo); free(pszInfo); } } BOOL bAccepted = FALSE; if (pIn->NewCmd.szConEmu[0]) { bAccepted = (lstrcmpi(gpConEmu->ms_ConEmuExeDir, pIn->NewCmd.szConEmu) == 0); } else { bAccepted = TRUE; } if (bAccepted) { bool bCreateTab = (pIn->NewCmd.ShowHide == sih_None || pIn->NewCmd.ShowHide == sih_StartDetached) // Issue 1275: When minimized into TSA (on all VCon are closed) we need to restore and run new tab || (pszCommand[0] && !CVConGroup::isVConExists(0)); RConStartArgs rTest; if (pszCommand[0]) { rTest.pszSpecialCmd = lstrdup(pszCommand); rTest.ProcessNewConArg(); } bool bSkipActivation = false; // Может быть пусто if (bCreateTab && pszCommand[0]) { RConStartArgs *pArgs = new RConStartArgs; // New tab must be started with same credentials that calling tab if others was not specified { if (!rTest.HasInheritedArgs()) { CVConGuard VCon; if ((pIn->NewCmd.hFromConWnd || pIn->NewCmd.hFromDcWnd) && CVConGroup::GetVConByHWND(pIn->NewCmd.hFromConWnd, pIn->NewCmd.hFromDcWnd, &VCon)) { const RConStartArgs& r = VCon->RCon()->GetArgs(); if (r.HasInheritedArgs()) { pArgs->AssignInheritedArgs(&r); } } } } pArgs->Detached = (pIn->NewCmd.ShowHide == sih_StartDetached) ? crb_On : crb_Off; pArgs->pszSpecialCmd = lstrdup(pszCommand); if (pIn->NewCmd.szCurDir[0] == 0) { _ASSERTE(pIn->NewCmd.szCurDir[0] != 0); } else { pArgs->pszStartupDir = lstrdup(pIn->NewCmd.szCurDir); } LPCWSTR pszStrings = pIn->NewCmd.GetEnvStrings(); if (pszStrings && pIn->NewCmd.cchEnvStrings) { size_t cbBytes = pIn->NewCmd.cchEnvStrings*sizeof(*pArgs->pszEnvStrings); pArgs->pszEnvStrings = (wchar_t*)malloc(cbBytes); if (pArgs->pszEnvStrings) { memmove(pArgs->pszEnvStrings, pszStrings, cbBytes); pArgs->cchEnvStrings = pIn->NewCmd.cchEnvStrings; } } if (gpSetCls->IsMulti() || CVConGroup::isDetached()) { gpConEmu->PostCreateCon(pArgs); } else { // Если хотят в одном окне - только одну консоль gpConEmu->CreateWnd(pArgs); SafeDelete(pArgs); // New window created? Don't activate this one. bSkipActivation = true; } } else { _ASSERTE(pIn->NewCmd.ShowHide==sih_ShowMinimize || pIn->NewCmd.ShowHide==sih_ShowHideTSA || pIn->NewCmd.ShowHide==sih_Show); } // gh#151: Do animation after starting tab creation if (!bSkipActivation && (rTest.BackgroundTab != crb_On)) { gpConEmu->DoMinimizeRestore(bCreateTab ? sih_SetForeground : pIn->NewCmd.ShowHide); } } pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(BYTE); lbRc = ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize); if (lbRc) { ppReply->Data[0] = bAccepted; } break; } //CECMD_NEWCMD case CECMD_TABSCMD: { // 0: спрятать/показать табы, 1: перейти на следующую, 2: перейти на предыдущую, 3: commit switch DEBUGSTRCMD(L"GUI recieved CECMD_TABSCMD\n"); _ASSERTE(nDataSize>=1); DWORD nTabCmd = pIn->Data[0]; gpConEmu->TabCommand((ConEmuTabCommand)nTabCmd); pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(BYTE); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->Data[0] = TRUE; } break; } // CECMD_TABSCMD case CECMD_ATTACH2GUI: { // Получен запрос на Attach из сервера MCHKHEAP; CESERVER_REQ_SRVSTARTSTOPRET Ret = {}; lbRc = CVConGroup::AttachRequested(pIn->StartStop.hWnd, &(pIn->StartStop), Ret); pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_SRVSTARTSTOPRET)+(Ret.cchEnvCommands*sizeof(wchar_t)); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { SafeFree(Ret.pszCommands); goto wrap; } if (lbRc) { _ASSERTE(sizeof(ppReply->SrvStartStopRet) == sizeof(Ret)); memmove(&ppReply->SrvStartStopRet, &Ret, sizeof(Ret)); // Environment strings (inherited from parent console) if (Ret.cchEnvCommands && Ret.pszCommands) { memmove(ppReply->SrvStartStopRet.szCommands, Ret.pszCommands, Ret.cchEnvCommands*sizeof(wchar_t)); ppReply->SrvStartStopRet.cchEnvCommands = Ret.cchEnvCommands; } else { ppReply->SrvStartStopRet.cchEnvCommands = 0; } SafeFree(Ret.pszCommands); _ASSERTE((ppReply->StartStopRet.nBufferHeight == 0) || ((int)ppReply->StartStopRet.nBufferHeight > (pIn->StartStop.sbi.srWindow.Bottom-pIn->StartStop.sbi.srWindow.Top))); } MCHKHEAP; break; } // CECMD_ATTACH2GUI case CECMD_SRVSTARTSTOP: { MCHKHEAP; // SRVSTART не приходит если запускается cmd под админом или из Win+G bool lbAllocated = false; if (pIn->SrvStartStop.Started == srv_Started) { // Запущен процесс сервера HWND hConWnd = (HWND)pIn->dwData[1]; _ASSERTE(hConWnd && IsWindow(hConWnd)); DWORD nStartTick = timeGetTime(); struct MsgSrvStartedArg { HWND hConWnd; DWORD nSrcPID; DWORD dwKeybLayout; DWORD timeStart; DWORD timeRecv; DWORD timeFin; CESERVER_REQ_SRVSTARTSTOPRET Ret; //111002 - вернуть должен HWND окна отрисовки (дочернее окно ConEmu) static LRESULT OnSrvStarted(LPARAM lParam) { MsgSrvStartedArg *pArg = (MsgSrvStartedArg*)lParam; HWND hWndDC = NULL; DWORD nServerPID = pArg->nSrcPID; HWND hWndCon = pArg->hConWnd; DWORD dwKeybLayout = pArg->dwKeybLayout; pArg->timeRecv = timeGetTime(); DWORD t1, t2; int iFound = -1; hWndDC = CVConGroup::DoSrvCreated(nServerPID, hWndCon, dwKeybLayout, t1, t2, iFound, pArg->Ret); UNREFERENCED_PARAMETER(dwKeybLayout); UNREFERENCED_PARAMETER(hWndCon); pArg->timeFin = timeGetTime(); if (hWndDC == NULL) { _ASSERTE(hWndDC!=NULL); } else { #ifdef _DEBUG DWORD nRecvDur = pArg->timeRecv - pArg->timeStart; DWORD nProcDur = pArg->timeFin - pArg->timeRecv; #define MSGSTARTED_TIMEOUT 10000 if ((nRecvDur > MSGSTARTED_TIMEOUT) || (nProcDur > MSGSTARTED_TIMEOUT)) { _ASSERTE((nRecvDur <= MSGSTARTED_TIMEOUT) && (nProcDur <= MSGSTARTED_TIMEOUT)); } #endif } return (LRESULT)hWndDC; }; } arg = {hConWnd, pIn->hdr.nSrcPID, pIn->SrvStartStop.dwKeybLayout, nStartTick}; gpConEmu->CallMainThread(true, arg.OnSrvStarted, (LPARAM)&arg); HWND hWndDC = arg.Ret.Info.hWndDc; HWND hWndBack = arg.Ret.Info.hWndBack; _ASSERTE(hWndDC!=NULL); #ifdef _DEBUG DWORD dwErr = GetLastError(), nEndTick = timeGetTime(), nDelta = nEndTick - nStartTick; if (hWndDC && nDelta >= EXECUTE_CMD_WARN_TIMEOUT) { if (!IsDebuggerPresent()) { //_ASSERTE(nDelta <= EXECUTE_CMD_WARN_TIMEOUT || (pIn->hdr.nCmd == CECMD_CMDSTARTSTOP && nDelta <= EXECUTE_CMD_WARN_TIMEOUT2)); _ASSERTEX(nDelta <= EXECUTE_CMD_WARN_TIMEOUT); } } #endif pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_SRVSTARTSTOPRET)+(arg.Ret.cchEnvCommands*sizeof(wchar_t)); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { SafeFree(arg.Ret.pszCommands); goto wrap; } lbAllocated = true; _ASSERTE(sizeof(ppReply->SrvStartStopRet) == sizeof(arg.Ret)); memmove(&ppReply->SrvStartStopRet, &arg.Ret, sizeof(arg.Ret)); // Environment strings (inherited from parent console) if (arg.Ret.cchEnvCommands && arg.Ret.pszCommands) { memmove(ppReply->SrvStartStopRet.szCommands, arg.Ret.pszCommands, arg.Ret.cchEnvCommands*sizeof(wchar_t)); ppReply->SrvStartStopRet.cchEnvCommands = arg.Ret.cchEnvCommands; } else { ppReply->SrvStartStopRet.cchEnvCommands = 0; } SafeFree(arg.Ret.pszCommands); } else if (pIn->SrvStartStop.Started == srv_Stopped) { // Процесс сервера завершается CRealConsole* pRCon = NULL; CVConGuard VCon; for (size_t i = 0;; i++) { if (!CVConGroup::GetVCon(i, &VCon)) break; pRCon = VCon->RCon(); if (pRCon && (pRCon->GetServerPID(true) == pIn->hdr.nSrcPID || pRCon->GetServerPID(false) == pIn->hdr.nSrcPID)) { break; } pRCon = NULL; } gpConEmu->mn_ShellExitCode = pIn->SrvStartStop.nShellExitCode; if (pRCon) pRCon->OnServerClosing(pIn->hdr.nSrcPID, &pIn->SrvStartStop.nShellExitCode); //pIn->dwData[0] = 1; } else { _ASSERTE((pIn->dwData[0] == 1) || (pIn->dwData[0] == 101)); } MCHKHEAP; if (!lbAllocated) { pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_SRVSTARTSTOPRET); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; } lbRc = TRUE; //// Отправляем //fSuccess = WriteFile( // hPipe, // handle to pipe // pOut, // buffer to write from // pOut->hdr.cbSize, // number of bytes to write // &cbWritten, // number of bytes written // NULL); // not overlapped I/O //ExecuteFreeResult(pOut); break; } // CECMD_SRVSTARTSTOP case CECMD_ASSERT: { DWORD nBtn = MessageBox(NULL, pIn->AssertInfo.szDebugInfo, pIn->AssertInfo.szTitle, pIn->AssertInfo.nBtns); pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = nBtn; } //ExecutePrepareCmd(&pIn->hdr, CECMD_ASSERT, sizeof(CESERVER_REQ_HDR) + sizeof(DWORD)); //pIn->dwData[0] = nBtn; //// Отправляем //fSuccess = WriteFile( // hPipe, // handle to pipe // pIn, // buffer to write from // pIn->hdr.cbSize, // number of bytes to write // &cbWritten, // number of bytes written // NULL); // not overlapped I/O break; } // CECMD_ASSERT case CECMD_ATTACHGUIAPP: { pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_ATTACHGUIAPP); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; ppReply->AttachGuiApp = pIn->AttachGuiApp; //CESERVER_REQ Out; //ExecutePrepareCmd(&Out.hdr, CECMD_ATTACHGUIAPP, sizeof(CESERVER_REQ_HDR)+sizeof(Out.AttachGuiApp)); //Out.AttachGuiApp = pIn->AttachGuiApp; #ifdef SHOW_GUIATTACH_START if (pIn->AttachGuiApp.hWindow == NULL) { wchar_t szDbg[1024]; _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"AttachGuiApp requested from:\n%s\nPID=%u", pIn->AttachGuiApp.sAppFilePathName, pIn->AttachGuiApp.nPID); //MBoxA(szDbg); MessageBox(NULL, szDbg, L"ConEmu", MB_SYSTEMMODAL); } #endif // Уведомить ожидающую вкладку CRealConsole* pRCon = CVConGroup::AttachRequestedGui(pIn->AttachGuiApp.nServerPID, pIn->AttachGuiApp.sAppFilePathName, pIn->AttachGuiApp.nPID); if (pRCon) { CVConGuard VCon(pRCon->VCon()); RECT rcPrev = ppReply->AttachGuiApp.rcWindow; HWND hBack = pRCon->VCon()->GetBack(); //// Размер должен быть независим от возможности наличия прокрутки в VCon //GetWindowRect(hBack, &ppReply->AttachGuiApp.rcWindow); //ppReply->AttachGuiApp.rcWindow.right -= ppReply->AttachGuiApp.rcWindow.left; //ppReply->AttachGuiApp.rcWindow.bottom -= ppReply->AttachGuiApp.rcWindow.top; //ppReply->AttachGuiApp.rcWindow.left = ppReply->AttachGuiApp.rcWindow.top = 0; ////MapWindowPoints(NULL, hBack, (LPPOINT)&ppReply->AttachGuiApp.rcWindow, 2); //pRCon->CorrectGuiChildRect(ppReply->AttachGuiApp.nStyle, ppReply->AttachGuiApp.nStyleEx, ppReply->AttachGuiApp.rcWindow); // Уведомить RCon и ConEmuC, что гуй подцепился // Вызывается два раза. Первый (при запуске exe) ahGuiWnd==NULL, второй - после фактического создания окна pRCon->SetGuiMode(pIn->AttachGuiApp.nFlags, pIn->AttachGuiApp.hAppWindow, pIn->AttachGuiApp.Styles.nStyle, pIn->AttachGuiApp.Styles.nStyleEx, pIn->AttachGuiApp.sAppFilePathName, pIn->AttachGuiApp.nPID, pIn->hdr.nBits, rcPrev); ppReply->AttachGuiApp.nFlags = agaf_Success | (pRCon->isActive(false) ? 0 : agaf_Inactive); ppReply->AttachGuiApp.nServerPID = pRCon->GetServerPID(); ppReply->AttachGuiApp.nPID = ppReply->AttachGuiApp.nServerPID; ppReply->AttachGuiApp.hConEmuDc = pRCon->GetView(); ppReply->AttachGuiApp.hConEmuBack = hBack; ppReply->AttachGuiApp.hConEmuWnd = ghWnd; ppReply->AttachGuiApp.hAppWindow = pIn->AttachGuiApp.hAppWindow; ppReply->AttachGuiApp.hSrvConWnd = pRCon->ConWnd(); ppReply->AttachGuiApp.hkl = (DWORD)(LONG)(LONG_PTR)GetKeyboardLayout(gpConEmu->mn_MainThreadId); ZeroStruct(ppReply->AttachGuiApp.Styles.Shifts); CRealConsole::CorrectGuiChildRect(pIn->AttachGuiApp.Styles.nStyle, pIn->AttachGuiApp.Styles.nStyleEx, ppReply->AttachGuiApp.Styles.Shifts, pIn->AttachGuiApp.sAppFilePathName); } else { ppReply->AttachGuiApp.nFlags = agaf_Fail; _ASSERTE(FALSE && "No one tab is waiting for ChildGui process"); } lbRc = TRUE; //// Отправляем //fSuccess = WriteFile( // hPipe, // handle to pipe // &Out, // buffer to write from // Out.hdr.cbSize, // number of bytes to write // &cbWritten, // number of bytes written // NULL); // not overlapped I/O break; } // CECMD_ATTACHGUIAPP case CECMD_GUICLIENTSHIFT: { pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(GuiStylesAndShifts); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; ppReply->GuiAppShifts = pIn->GuiAppShifts; ZeroStruct(ppReply->GuiAppShifts.Shifts); CRealConsole::CorrectGuiChildRect(pIn->GuiAppShifts.nStyle, pIn->GuiAppShifts.nStyleEx, ppReply->GuiAppShifts.Shifts, pIn->GuiAppShifts.szExeName); lbRc = TRUE; break; } // CECMD_GUICLIENTSHIFT case CECMD_GUIMACRO: { // Допустимо, если GuiMacro пытаются выполнить извне CVConGuard VCon; CVConGroup::GetActiveVCon(&VCon); DWORD nFarPluginPID = VCon->RCon()->GetFarPID(true); LPWSTR pszResult = ConEmuMacro::ExecuteMacro(pIn->GuiMacro.sMacro, VCon->RCon(), (nFarPluginPID==pIn->hdr.nSrcPID), &pIn->GuiMacro); int nLen = pszResult ? _tcslen(pszResult) : 0; pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_GUIMACRO)+nLen*sizeof(wchar_t); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { SafeFree(pszResult); goto wrap; } if (pszResult) { lstrcpy(ppReply->GuiMacro.sMacro, pszResult); ppReply->GuiMacro.nSucceeded = 1; free(pszResult); } else { ppReply->GuiMacro.sMacro[0] = 0; ppReply->GuiMacro.nSucceeded = 0; } lbRc = TRUE; break; } // CECMD_GUIMACRO case CECMD_CMDSTARTSTOP: { CRealServer* pRSrv = NULL; CVConGuard VCon; DWORD nSrvPID = pIn->hdr.nSrcPID; DWORD nMonitorTID = (pIn->DataSize() >= sizeof(pIn->StartStop)) ? pIn->StartStop.dwAID : 0; if (CVConGroup::GetVConBySrvPID(nSrvPID, nMonitorTID, &VCon)) pRSrv = &VCon->RCon()->m_RConServer; if (pRSrv) { CESERVER_REQ* pOut = pRSrv->cmdStartStop(pInst, pIn, pIn->DataSize()); if (pOut) { DWORD nDataSize = pOut->DataSize(); pcbReplySize = pOut->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pOut->hdr.nCmd, pcbReplySize)) { if (nDataSize > 0) { memmove(ppReply->Data, pOut->Data, nDataSize); } lbRc = TRUE; } ExecuteFreeResult(pOut); } } break; } // CECMD_CMDSTARTSTOP //case CECMD_DEFTERMSTARTED: //{ // if (gpConEmu->mp_DefTrm) // gpConEmu->mp_DefTrm->OnDefTermStarted(pIn); // pcbReplySize = sizeof(CESERVER_REQ_HDR); // if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) // goto wrap; // lbRc = TRUE; // break; //} // CECMD_DEFTERMSTARTED default: _ASSERTE(FALSE && "Command was not handled in CGuiServer::GuiServerCommand"); } //// Освободить память //if (pIn && (LPVOID)pIn != (LPVOID)&in) //{ // free(pIn); pIn = NULL; //} wrap: return lbRc; }
//Arguments: // hConWnd - Хэндл КОНСОЛЬНОГО окна (по нему формируется имя пайпа для GUI) // pIn - выполняемая команда // nTimeout- таймаут подключения //Returns: // CESERVER_REQ. Его необходимо освободить через free(...); //WARNING!!! // Эта процедура не может получить с сервера более 600 байт данных! // В заголовке hOwner в дебаге может быть отображена ошибка CESERVER_REQ* ExecuteCmd(const wchar_t* szPipeName, CESERVER_REQ* pIn, DWORD nWaitPipe, HWND hOwner, BOOL bAsyncNoResult, DWORD nServerPID, BOOL bIgnoreAbsence /*= FALSE*/) { CESERVER_REQ* pOut = NULL; HANDLE hPipe = NULL; BYTE cbReadBuf[600]; // чтобы CESERVER_REQ_OUTPUTFILE поместился wchar_t szErr[MAX_PATH*2]; szErr[0] = 0; BOOL fSuccess = FALSE; DWORD cbRead = 0, /*dwMode = 0,*/ dwErr = 0; int nAllSize; LPBYTE ptrData; #ifdef _DEBUG bool bIsAltSrvCmd; wchar_t szDbgPrefix[64], szDbgResult[64], *pszDbgMsg = NULL; #endif if (!pIn || !szPipeName) { _ASSERTE(pIn && szPipeName); pOut = NULL; goto wrap; } #ifdef _DEBUG _wsprintf(szDbgPrefix, SKIPLEN(countof(szDbgPrefix)) L">> ExecCmd: PID=%5u TID=%5u Cmd=%3u ", GetCurrentProcessId(), GetCurrentThreadId(), pIn->hdr.nCmd); pszDbgMsg = lstrmerge(szDbgPrefix, szPipeName, L"\n"); if (pszDbgMsg) { DEBUGSTRCMD(pszDbgMsg); free(pszDbgMsg); } #endif pIn->hdr.bAsync = bAsyncNoResult; _ASSERTE(pIn->hdr.nSrcPID && pIn->hdr.nSrcThreadId); _ASSERTE(pIn->hdr.cbSize >= sizeof(pIn->hdr)); hPipe = ExecuteOpenPipe(szPipeName, szErr, NULL/*Сюда хорошо бы имя модуля подкрутить*/, nServerPID, nWaitPipe, FALSE, NULL, bIgnoreAbsence); if (hPipe == NULL || hPipe == INVALID_HANDLE_VALUE) { #ifdef _DEBUG dwErr = GetLastError(); // в заголовке "чисто" запущенного фара появляются отладочные(?) сообщения // по идее - не должны, т.к. все должно быть через мэппинг // *** _ASSERTEX(hPipe != NULL && hPipe != INVALID_HANDLE_VALUE); - no need in assert, it was already shown #ifdef CONEMU_MINIMAL SetConsoleTitle(szErr); #else if (hOwner) { if (hOwner == myGetConsoleWindow()) SetConsoleTitle(szErr); else SetWindowText(hOwner, szErr); } #endif #endif pOut = NULL; goto wrap; } #ifdef _DEBUG bIsAltSrvCmd = (pIn->hdr.nCmd==CECMD_ALTBUFFER || pIn->hdr.nCmd==CECMD_ALTBUFFERSTATE || pIn->hdr.nCmd==CECMD_SETCONSCRBUF || pIn->hdr.nCmd == CECMD_LOCKSTATION || pIn->hdr.nCmd == CECMD_UNLOCKSTATION); _ASSERTE(pIn->hdr.nSrcThreadId==GetCurrentThreadId() || (bIsAltSrvCmd && pIn->hdr.nSrcPID!=GetCurrentProcessId())); #endif if (bAsyncNoResult) { // Если нас не интересует возврат и нужно сразу вернуться fSuccess = WriteFile(hPipe, pIn, pIn->hdr.cbSize, &cbRead, NULL); #ifdef _DEBUG dwErr = GetLastError(); _ASSERTE(fSuccess && (cbRead == pIn->hdr.cbSize)); #endif // -- Do not close hPipe, otherwise the reader may fail with that packet // -- with error ‘pipe was closed before end’. // -- Handle leak, yeah, however this is rarely used op. // -- Must be refactored, but not so critical... // -- CloseHandle(hPipe); pOut = NULL; goto wrap; } else { WARNING("При Overlapped часто виснет в этом месте."); // Send a message to the pipe server and read the response. fSuccess = TransactNamedPipe( hPipe, // pipe handle (LPVOID)pIn, // message to server pIn->hdr.cbSize, // message length cbReadBuf, // buffer to receive reply sizeof(cbReadBuf), // size of read buffer &cbRead, // bytes read NULL); // not overlapped dwErr = GetLastError(); //CloseHandle(hPipe); if (!fSuccess && (dwErr != ERROR_MORE_DATA)) { //_ASSERTE(fSuccess || (dwErr == ERROR_MORE_DATA)); CloseHandle(hPipe); pOut = NULL; goto wrap; } } if (cbRead < sizeof(CESERVER_REQ_HDR)) { CloseHandle(hPipe); pOut = NULL; goto wrap; } pOut = (CESERVER_REQ*)cbReadBuf; // temporary if (pOut->hdr.cbSize < cbRead) { CloseHandle(hPipe); if (pOut->hdr.cbSize) { _ASSERTE(pOut->hdr.cbSize == 0 || pOut->hdr.cbSize >= cbRead); DEBUGSTR(L"!!! Wrong nSize received from GUI server !!!\n"); } pOut = NULL; goto wrap; } if (pOut->hdr.nVersion != CESERVER_REQ_VER) { CloseHandle(hPipe); DEBUGSTR(L"!!! Wrong nVersion received from GUI server !!!\n"); pOut = NULL; goto wrap; } nAllSize = pOut->hdr.cbSize; pOut = (CESERVER_REQ*)malloc(nAllSize); _ASSERTE(pOut); if (!pOut) { CloseHandle(hPipe); _ASSERTE(pOut == NULL); goto wrap; } memmove(pOut, cbReadBuf, cbRead); ptrData = ((LPBYTE)pOut)+cbRead; nAllSize -= cbRead; while (nAllSize>0) { // Break if TransactNamedPipe or ReadFile is successful if (fSuccess) break; // Read from the pipe if there is more data in the message. fSuccess = ReadFile( hPipe, // pipe handle ptrData, // buffer to receive reply nAllSize, // size of buffer &cbRead, // number of bytes read NULL); // not overlapped // Exit if an error other than ERROR_MORE_DATA occurs. if (!fSuccess && ((dwErr = GetLastError()) != ERROR_MORE_DATA)) break; ptrData += cbRead; nAllSize -= cbRead; } CloseHandle(hPipe); if (pOut && (pOut->hdr.nCmd != pIn->hdr.nCmd)) { _ASSERTE(pOut->hdr.nCmd == pIn->hdr.nCmd); if (pOut->hdr.nCmd == 0) { ExecuteFreeResult(pOut); pOut = NULL; } } wrap: #ifdef _DEBUG if (pOut) _wsprintf(szDbgResult, SKIPLEN(countof(szDbgResult)) L"- Data=%5u Err=%u\n", pOut->DataSize(), dwErr); else lstrcpyn(szDbgResult, L"[NULL]\n", countof(szDbgResult)); pszDbgMsg = lstrmerge(szDbgPrefix, szDbgResult); if (pszDbgMsg) { DEBUGSTRCMD(pszDbgMsg); free(pszDbgMsg); } #endif return pOut; }
//// Эта функция пайп не закрывает! //void CGuiServer::GuiServerThreadCommand(HANDLE hPipe) BOOL CGuiServer::GuiServerCommand(LPVOID pInst, CESERVER_REQ* pIn, CESERVER_REQ* &ppReply, DWORD &pcbReplySize, DWORD &pcbMaxReplySize, LPARAM lParam) { BOOL lbRc = FALSE; CGuiServer* pGSrv = (CGuiServer*)lParam; if (!pGSrv) { _ASSERTE(((CGuiServer*)lParam)!=NULL); pGSrv = &gpConEmu->m_GuiServer; } if (pIn->hdr.bAsync) pGSrv->mp_GuiServer->BreakConnection(pInst); gpSetCls->debugLogCommand(pIn, TRUE, timeGetTime(), 0, pGSrv ? pGSrv->ms_ServerPipe : NULL); #ifdef _DEBUG UINT nDataSize = pIn->hdr.cbSize - sizeof(CESERVER_REQ_HDR); #endif // Все данные из пайпа получены, обрабатываем команду и возвращаем (если нужно) результат #ifdef ALLOW_WINE_MSG if (gbIsWine) { wchar_t szMsg[128]; msprintf(szMsg, countof(szMsg), L"CGuiServer::GuiServerCommand.\nGUI TID=%u\nSrcPID=%u, SrcTID=%u, Cmd=%u", GetCurrentThreadId(), pIn->hdr.nSrcPID, pIn->hdr.nSrcThreadId, pIn->hdr.nCmd); MessageBox(szMsg, MB_ICONINFORMATION); } #endif switch (pIn->hdr.nCmd) { case CECMD_NEWCMD: { // Приходит из другой копии ConEmu.exe, когда она запущена с ключом /single, /showhide, /showhideTSA DEBUGSTRCMD(L"GUI recieved CECMD_NEWCMD\n"); if (pIn->NewCmd.isAdvLogging && !gpSetCls->isAdvLogging) { gpSetCls->isAdvLogging = pIn->NewCmd.isAdvLogging; gpConEmu->CreateLog(); } if (gpSetCls->isAdvLogging && (pIn->NewCmd.isAdvLogging > gpSetCls->isAdvLogging)) { wchar_t szLogLevel[80]; _wsprintf(szLogLevel, SKIPLEN(countof(szLogLevel)) L"Changing log level! Old=%u, New=%u", (UINT)gpSetCls->isAdvLogging, (UINT)pIn->NewCmd.isAdvLogging); gpConEmu->LogString(szLogLevel); gpSetCls->isAdvLogging = pIn->NewCmd.isAdvLogging; } if (gpSetCls->isAdvLogging) { size_t cchAll = 120 + _tcslen(pIn->NewCmd.szConEmu) + _tcslen(pIn->NewCmd.szCurDir) + _tcslen(pIn->NewCmd.szCommand); wchar_t* pszInfo = (wchar_t*)malloc(cchAll*sizeof(*pszInfo)); if (pszInfo) { _wsprintf(pszInfo, SKIPLEN(cchAll) L"CECMD_NEWCMD: Wnd=x%08X, Act=%u, ConEmu=%s, Dir=%s, Cmd=%s", (DWORD)(DWORD_PTR)pIn->NewCmd.hFromConWnd, pIn->NewCmd.ShowHide, pIn->NewCmd.szConEmu, pIn->NewCmd.szCurDir, pIn->NewCmd.szCommand); gpConEmu->LogString(pszInfo); free(pszInfo); } } BOOL bAccepted = FALSE; if (pIn->NewCmd.szConEmu[0]) { bAccepted = (lstrcmpi(gpConEmu->ms_ConEmuExeDir, pIn->NewCmd.szConEmu) == 0); } else { bAccepted = TRUE; } if (bAccepted) { bool bCreateTab = (pIn->NewCmd.ShowHide == sih_None || pIn->NewCmd.ShowHide == sih_StartDetached) // Issue 1275: When minimized into TSA (on all VCon are closed) we need to restore and run new tab || (pIn->NewCmd.szCommand[0] && !CVConGroup::isVConExists(0)); gpConEmu->DoMinimizeRestore(bCreateTab ? sih_SetForeground : pIn->NewCmd.ShowHide); // Может быть пусто if (bCreateTab && pIn->NewCmd.szCommand[0]) { RConStartArgs *pArgs = new RConStartArgs; pArgs->Detached = (pIn->NewCmd.ShowHide == sih_StartDetached) ? crb_On : crb_Off; pArgs->pszSpecialCmd = lstrdup(pIn->NewCmd.szCommand); if (pIn->NewCmd.szCurDir[0] == 0) { _ASSERTE(pIn->NewCmd.szCurDir[0] != 0); } else { pArgs->pszStartupDir = lstrdup(pIn->NewCmd.szCurDir); } if (gpSetCls->IsMulti() || CVConGroup::isDetached()) { gpConEmu->PostCreateCon(pArgs); } else { // Если хотят в одном окне - только одну консоль gpConEmu->CreateWnd(pArgs); SafeDelete(pArgs); } } else { _ASSERTE(pIn->NewCmd.ShowHide==sih_ShowMinimize || pIn->NewCmd.ShowHide==sih_ShowHideTSA || pIn->NewCmd.ShowHide==sih_Show); } } pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(BYTE); lbRc = ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize); if (lbRc) { ppReply->Data[0] = bAccepted; } break; } //CECMD_NEWCMD case CECMD_TABSCMD: { // 0: спрятать/показать табы, 1: перейти на следующую, 2: перейти на предыдущую, 3: commit switch DEBUGSTRCMD(L"GUI recieved CECMD_TABSCMD\n"); _ASSERTE(nDataSize>=1); DWORD nTabCmd = pIn->Data[0]; gpConEmu->TabCommand((ConEmuTabCommand)nTabCmd); pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(BYTE); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->Data[0] = TRUE; } break; } // CECMD_TABSCMD #if 0 case CECMD_GETALLTABS: { int nConCount = gpConEmu->GetConCount(); int nActiveCon = gpConEmu->ActiveConNum(); size_t cchMax = nConCount*16; size_t cchCount = 0; CVirtualConsole* pVCon; CESERVER_REQ_GETALLTABS::TabInfo* pTabs = (CESERVER_REQ_GETALLTABS::TabInfo*)calloc(cchMax, sizeof(*pTabs)); for (int V = 0; (pVCon = gpConEmu->GetVCon(V)) != NULL; V++) { if (!pTabs) { _ASSERTE(pTabs!=NULL); break; } CRealConsole* pRCon = pVCon->RCon(); if (!pRCon) continue; ConEmuTab tab; wchar_t szModified[4]; for (int T = 0; pRCon->GetTab(T, &tab); T++) { if (cchCount >= cchMax) { pTabs = (CESERVER_REQ_GETALLTABS::TabInfo*)realloc(pTabs, (cchMax+32)*sizeof(*pTabs)); if (!pTabs) { _ASSERTE(pTabs!=NULL); break; } cchMax += 32; _ASSERTE(cchCount<cchMax); } pTabs[cchCount].ActiveConsole == (V == nActiveCon); pTabs[cchCount].ActiveTab == (tab.Current != 0); pTabs[cchCount].Disabled = ((tab.Type & fwt_Disabled) == fwt_Disabled); pTabs[cchCount].ConsoleIdx = V; pTabs[cchCount].TabIdx = T; // Text wcscpy_c(szModified, tab.Modified ? L" * " : L" "); if (V == nActiveCon) { if (T < 9) _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/&%i]%s", V+1, T+1, szModified); else if (T == 9) _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/1&0]%s", V+1, szModified); else _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/%i]%s", V+1, T+1, szModified); } else { _wsprintf(pTabs[cchCount].Title, SKIPLEN(countof(pTabs[cchCount].Title)) L"[%i/%i]%s", V+1, T+1, szModified); } cchCount++; } } if (cchCount && pTabs) { pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_GETALLTABS)+((cchCount-1)*sizeof(CESERVER_REQ_GETALLTABS::TabInfo)); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->GetAllTabs.Count = cchCount; memmove(ppReply->GetAllTabs.Tabs, pTabs, cchCount*sizeof(*pTabs)); } } SafeFree(pTabs); break; } // CECMD_GETALLTABS case CECMD_ACTIVATETAB: { BOOL lbTabOk = FALSE; CVirtualConsole *pVCon = gpConEmu->GetVCon(pIn->dwData[0]); if (pVCon && pVCon->RCon()) { lbTabOk = pVCon->RCon()->ActivateFarWindow(pIn->dwData[1]); } pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = lbTabOk; } break; } // CECMD_ACTIVATETAB #endif case CECMD_ATTACH2GUI: { MCHKHEAP; // Получен запрос на Attach из сервера pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_SRVSTARTSTOPRET); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; //CESERVER_REQ* pOut = ExecuteNewCmd(CECMD_ATTACH2GUI, sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_STARTSTOPRET)); CVConGroup::AttachRequested(pIn->StartStop.hWnd, &(pIn->StartStop), &(ppReply->SrvStartStopRet)); _ASSERTE((ppReply->StartStopRet.nBufferHeight == 0) || ((int)ppReply->StartStopRet.nBufferHeight > (pIn->StartStop.sbi.srWindow.Bottom-pIn->StartStop.sbi.srWindow.Top))); MCHKHEAP; lbRc = TRUE; //ExecuteFreeResult(pOut); break; } // CECMD_ATTACH2GUI case CECMD_SRVSTARTSTOP: { MCHKHEAP; // SRVSTART не приходит если запускается cmd под админом pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_SRVSTARTSTOPRET); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; if (pIn->SrvStartStop.Started == srv_Started) { // Запущен процесс сервера HWND hConWnd = (HWND)pIn->dwData[1]; _ASSERTE(hConWnd && IsWindow(hConWnd)); DWORD nStartTick = timeGetTime(); //LRESULT l = 0; //DWORD_PTR dwRc = 0; //2010-05-21 Поскольку это критично - лучше ждать до упора, хотя может быть DeadLock? //l = SendMessageTimeout(ghWnd, gpConEmu->mn_MsgSrvStarted, (WPARAM)hConWnd, pIn->hdr.nSrcPID, // SMTO_BLOCK, 5000, &dwRc); //111002 - вернуть должен HWND окна отрисовки (дочернее окно ConEmu) MsgSrvStartedArg arg = {hConWnd, pIn->hdr.nSrcPID, pIn->SrvStartStop.dwKeybLayout, nStartTick}; SendMessage(ghWnd, gpConEmu->mn_MsgSrvStarted, 0, (LPARAM)&arg); HWND hWndDC = arg.hWndDc; HWND hWndBack = arg.hWndBack; _ASSERTE(hWndDC!=NULL); #ifdef _DEBUG DWORD dwErr = GetLastError(), nEndTick = timeGetTime(), nDelta = nEndTick - nStartTick; if (hWndDC && nDelta >= EXECUTE_CMD_WARN_TIMEOUT) { if (!IsDebuggerPresent()) { //_ASSERTE(nDelta <= EXECUTE_CMD_WARN_TIMEOUT || (pIn->hdr.nCmd == CECMD_CMDSTARTSTOP && nDelta <= EXECUTE_CMD_WARN_TIMEOUT2)); _ASSERTEX(nDelta <= EXECUTE_CMD_WARN_TIMEOUT); } } #endif //pIn->dwData[0] = (DWORD)ghWnd; //-V205 //pIn->dwData[1] = (DWORD)dwRc; //-V205 //pIn->dwData[0] = (l == 0) ? 0 : 1; ppReply->SrvStartStopRet.Info.hWnd = ghWnd; ppReply->SrvStartStopRet.Info.hWndDc = hWndDC; ppReply->SrvStartStopRet.Info.hWndBack = hWndBack; ppReply->SrvStartStopRet.Info.dwPID = GetCurrentProcessId(); // Limited logging of console contents (same output as processed by CECF_ProcessAnsi) gpConEmu->GetAnsiLogInfo(ppReply->SrvStartStopRet.AnsiLog); // Return GUI info, let it be in one place gpConEmu->GetGuiInfo(ppReply->SrvStartStopRet.GuiMapping); } else if (pIn->SrvStartStop.Started == srv_Stopped) { // Процесс сервера завершается CRealConsole* pRCon = NULL; CVConGuard VCon; for (size_t i = 0;; i++) { if (!CVConGroup::GetVCon(i, &VCon)) break; pRCon = VCon->RCon(); if (pRCon && (pRCon->GetServerPID(true) == pIn->hdr.nSrcPID || pRCon->GetServerPID(false) == pIn->hdr.nSrcPID)) { break; } pRCon = NULL; } if (pRCon) pRCon->OnServerClosing(pIn->hdr.nSrcPID); //pIn->dwData[0] = 1; } else { _ASSERTE((pIn->dwData[0] == 1) || (pIn->dwData[0] == 101)); } MCHKHEAP; lbRc = TRUE; //// Отправляем //fSuccess = WriteFile( // hPipe, // handle to pipe // pOut, // buffer to write from // pOut->hdr.cbSize, // number of bytes to write // &cbWritten, // number of bytes written // NULL); // not overlapped I/O //ExecuteFreeResult(pOut); break; } // CECMD_SRVSTARTSTOP case CECMD_ASSERT: { DWORD nBtn = MessageBox(NULL, pIn->AssertInfo.szDebugInfo, pIn->AssertInfo.szTitle, pIn->AssertInfo.nBtns); pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = nBtn; } //ExecutePrepareCmd(&pIn->hdr, CECMD_ASSERT, sizeof(CESERVER_REQ_HDR) + sizeof(DWORD)); //pIn->dwData[0] = nBtn; //// Отправляем //fSuccess = WriteFile( // hPipe, // handle to pipe // pIn, // buffer to write from // pIn->hdr.cbSize, // number of bytes to write // &cbWritten, // number of bytes written // NULL); // not overlapped I/O break; } // CECMD_ASSERT case CECMD_ATTACHGUIAPP: { pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_ATTACHGUIAPP); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; ppReply->AttachGuiApp = pIn->AttachGuiApp; //CESERVER_REQ Out; //ExecutePrepareCmd(&Out.hdr, CECMD_ATTACHGUIAPP, sizeof(CESERVER_REQ_HDR)+sizeof(Out.AttachGuiApp)); //Out.AttachGuiApp = pIn->AttachGuiApp; #ifdef SHOW_GUIATTACH_START if (pIn->AttachGuiApp.hWindow == NULL) { wchar_t szDbg[1024]; _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"AttachGuiApp requested from:\n%s\nPID=%u", pIn->AttachGuiApp.sAppFilePathName, pIn->AttachGuiApp.nPID); //MBoxA(szDbg); MessageBox(NULL, szDbg, L"ConEmu", MB_SYSTEMMODAL); } #endif // Уведомить ожидающую вкладку CRealConsole* pRCon = gpConEmu->AttachRequestedGui(pIn->AttachGuiApp.nServerPID, pIn->AttachGuiApp.sAppFilePathName, pIn->AttachGuiApp.nPID); if (pRCon) { CVConGuard VCon(pRCon->VCon()); RECT rcPrev = ppReply->AttachGuiApp.rcWindow; HWND hBack = pRCon->VCon()->GetBack(); //// Размер должен быть независим от возможности наличия прокрутки в VCon //GetWindowRect(hBack, &ppReply->AttachGuiApp.rcWindow); //ppReply->AttachGuiApp.rcWindow.right -= ppReply->AttachGuiApp.rcWindow.left; //ppReply->AttachGuiApp.rcWindow.bottom -= ppReply->AttachGuiApp.rcWindow.top; //ppReply->AttachGuiApp.rcWindow.left = ppReply->AttachGuiApp.rcWindow.top = 0; ////MapWindowPoints(NULL, hBack, (LPPOINT)&ppReply->AttachGuiApp.rcWindow, 2); //pRCon->CorrectGuiChildRect(ppReply->AttachGuiApp.nStyle, ppReply->AttachGuiApp.nStyleEx, ppReply->AttachGuiApp.rcWindow); // Уведомить RCon и ConEmuC, что гуй подцепился // Вызывается два раза. Первый (при запуске exe) ahGuiWnd==NULL, второй - после фактического создания окна pRCon->SetGuiMode(pIn->AttachGuiApp.nFlags, pIn->AttachGuiApp.hAppWindow, pIn->AttachGuiApp.Styles.nStyle, pIn->AttachGuiApp.Styles.nStyleEx, pIn->AttachGuiApp.sAppFilePathName, pIn->AttachGuiApp.nPID, pIn->hdr.nBits, rcPrev); ppReply->AttachGuiApp.nFlags = agaf_Success | (pRCon->isActive(false) ? 0 : agaf_Inactive); ppReply->AttachGuiApp.nServerPID = pRCon->GetServerPID(); ppReply->AttachGuiApp.nPID = ppReply->AttachGuiApp.nServerPID; ppReply->AttachGuiApp.hConEmuDc = pRCon->GetView(); ppReply->AttachGuiApp.hConEmuBack = hBack; ppReply->AttachGuiApp.hConEmuWnd = ghWnd; ppReply->AttachGuiApp.hAppWindow = pIn->AttachGuiApp.hAppWindow; ppReply->AttachGuiApp.hSrvConWnd = pRCon->ConWnd(); ppReply->AttachGuiApp.hkl = (DWORD)(LONG)(LONG_PTR)GetKeyboardLayout(gpConEmu->mn_MainThreadId); ZeroStruct(ppReply->AttachGuiApp.Styles.Shifts); CRealConsole::CorrectGuiChildRect(pIn->AttachGuiApp.Styles.nStyle, pIn->AttachGuiApp.Styles.nStyleEx, ppReply->AttachGuiApp.Styles.Shifts, pIn->AttachGuiApp.sAppFilePathName); } else { ppReply->AttachGuiApp.nFlags = agaf_Fail; _ASSERTE(FALSE && "No one tab is waiting for ChildGui process"); } lbRc = TRUE; //// Отправляем //fSuccess = WriteFile( // hPipe, // handle to pipe // &Out, // buffer to write from // Out.hdr.cbSize, // number of bytes to write // &cbWritten, // number of bytes written // NULL); // not overlapped I/O break; } // CECMD_ATTACHGUIAPP case CECMD_GUICLIENTSHIFT: { pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(GuiStylesAndShifts); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; ppReply->GuiAppShifts = pIn->GuiAppShifts; ZeroStruct(ppReply->GuiAppShifts.Shifts); CRealConsole::CorrectGuiChildRect(pIn->GuiAppShifts.nStyle, pIn->GuiAppShifts.nStyleEx, ppReply->GuiAppShifts.Shifts, pIn->GuiAppShifts.szExeName); lbRc = TRUE; break; } // CECMD_GUICLIENTSHIFT case CECMD_GUIMACRO: { // Допустимо, если GuiMacro пытаются выполнить извне CVConGuard VCon; CVConGroup::GetActiveVCon(&VCon); DWORD nFarPluginPID = VCon->RCon()->GetFarPID(true); LPWSTR pszResult = ConEmuMacro::ExecuteMacro(pIn->GuiMacro.sMacro, VCon->RCon(), (nFarPluginPID==pIn->hdr.nSrcPID)); int nLen = pszResult ? _tcslen(pszResult) : 0; pcbReplySize = sizeof(CESERVER_REQ_HDR)+sizeof(CESERVER_REQ_GUIMACRO)+nLen*sizeof(wchar_t); if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) goto wrap; if (pszResult) { lstrcpy(ppReply->GuiMacro.sMacro, pszResult); ppReply->GuiMacro.nSucceeded = 1; free(pszResult); } else { ppReply->GuiMacro.sMacro[0] = 0; ppReply->GuiMacro.nSucceeded = 0; } lbRc = TRUE; break; } // CECMD_GUIMACRO case CECMD_CMDSTARTSTOP: { CRealServer* pRSrv = NULL; CVConGuard VCon; if (CVConGroup::GetVConBySrvPID(pIn->hdr.nSrcPID, &VCon)) pRSrv = &VCon->RCon()->m_RConServer; if (pRSrv) { CESERVER_REQ* pOut = pRSrv->cmdStartStop(pInst, pIn, pIn->DataSize()); if (pOut) { DWORD nDataSize = pOut->DataSize(); pcbReplySize = pOut->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pOut->hdr.nCmd, pcbReplySize)) { if (nDataSize > 0) { memmove(ppReply->Data, pOut->Data, nDataSize); } lbRc = TRUE; } ExecuteFreeResult(pOut); } } break; } // CECMD_CMDSTARTSTOP //case CECMD_DEFTERMSTARTED: //{ // if (gpConEmu->mp_DefTrm) // gpConEmu->mp_DefTrm->OnDefTermStarted(pIn); // pcbReplySize = sizeof(CESERVER_REQ_HDR); // if (!ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) // goto wrap; // lbRc = TRUE; // break; //} // CECMD_DEFTERMSTARTED default: _ASSERTE(FALSE && "Command was not handled in CGuiServer::GuiServerCommand"); } //// Освободить память //if (pIn && (LPVOID)pIn != (LPVOID)&in) //{ // free(pIn); pIn = NULL; //} wrap: return lbRc; }