bool CConEmuInside::TurnExplorerTipPane(wchar_t (&szAddMsg)[128]) { bool bRepeat = false; int nBtn = IDCANCEL; DWORD_PTR nRc; LRESULT lSendRc; if (gnOsVer < 0x600) { // WinXP, Win2k3 nBtn = IDYES; // MessageBox(L"Tip pane is not found in Explorer window!\nThis pane is required for 'ConEmu Inside' mode.\nDo you want to show this pane?", MB_ICONQUESTION|MB_YESNO); if (nBtn == IDYES) { #if 0 HWND hWorker = GetDlgItem(mh_InsideParentRoot, 0xA005); #ifdef _DEBUG if (hWorker) { HWND hReBar = FindWindowEx(hWorker, NULL, L"ReBarWindow32", NULL); if (hReBar) { POINT pt = {4,4}; HWND hTool = ChildWindowFromPoint(hReBar, pt); if (hTool) { //TBBUTTON tb = {}; //lSendRc = SendMessageTimeout(mh_InsideParentRoot, TB_GETBUTTON, 2, (LPARAM)&tb, SMTO_NOTIMEOUTIFNOTHUNG, 500, &nRc); //if (tb.idCommand) //{ // NMTOOLBAR nm = {{hTool, 0, TBN_DROPDOWN}, 32896/*tb.idCommand*/}; // lSendRc = SendMessageTimeout(mh_InsideParentRoot, WM_NOTIFY, 0, (LPARAM)&nm, SMTO_NOTIMEOUTIFNOTHUNG, 500, &nRc); //} lSendRc = SendMessageTimeout(mh_InsideParentRoot, WM_COMMAND, 32896, 0, SMTO_NOTIMEOUTIFNOTHUNG, 500, &nRc); } } } // There is no way to force "Tip pane" in WinXP // if popup menu "View -> Explorer bar" was not _shown_ at least once // In that case, Explorer ignores WM_COMMAND(41536) and does not reveal tip pane. HMENU hMenu1 = GetMenu(mh_InsideParentRoot), hMenu2 = NULL, hMenu3 = NULL; if (hMenu1) { hMenu2 = GetSubMenu(hMenu1, 2); //if (!hMenu2) //{ // lSendRc = SendMessageTimeout(mh_InsideParentRoot, WM_MENUSELECT, MAKELONG(2,MF_POPUP), (LPARAM)hMenu1, SMTO_NOTIMEOUTIFNOTHUNG, 1500, &nRc); // hMenu2 = GetSubMenu(hMenu1, 2); //} if (hMenu2) { hMenu3 = GetSubMenu(hMenu2, 2); } } #endif #endif //INPUT keys[4] = {INPUT_KEYBOARD,INPUT_KEYBOARD,INPUT_KEYBOARD,INPUT_KEYBOARD}; //keys[0].ki.wVk = VK_F10; keys[0].ki.dwFlags = 0; //keys[0].ki.wScan = MapVirtualKey(VK_F10,MAPVK_VK_TO_VSC); //keys[1].ki.wVk = VK_F10; keys[1].ki.dwFlags = KEYEVENTF_KEYUP; //keys[0].ki.wScan = MapVirtualKey(VK_F10,MAPVK_VK_TO_VSC); //keys[1].ki.wVk = 'V'; //keys[2].ki.wVk = 'E'; //keys[3].ki.wVk = 'T'; //LRESULT lSentRc = 0; //SetForegroundWindow(mh_InsideParentRoot); //LRESULT lSentRc = SendInput(2/*countof(keys)*/, keys, sizeof(keys[0])); //lSentRc = SendMessageTimeout(mh_InsideParentRoot, WM_SYSKEYUP, 'V', 0, SMTO_NOTIMEOUTIFNOTHUNG, 5000, &nRc); lSendRc = SendMessageTimeout(mh_InsideParentRoot, WM_COMMAND, EMID_TIPOFDAY/*41536*/, 0, SMTO_NOTIMEOUTIFNOTHUNG, 5000, &nRc); UNREFERENCED_PARAMETER(lSendRc); mb_InsidePaneWasForced = true; // Подготовим сообщение если не удастся wcscpy_c(szAddMsg, L"Forcing Explorer to show Tip pane failed.\nShow pane yourself and recall ConEmu.\n\n"); } } if (nBtn == IDYES) { // Первая проверка mh_InsideParentWND = mh_InsideParentRel = NULL; m_InsideIntegration = ii_Auto; InsideFindShellView(mh_InsideParentRoot); if (mh_InsideParentWND && mh_InsideParentRel) { bRepeat = true; goto wrap; } // Если не нашли - задержка и повторная проверка Sleep(500); mh_InsideParentWND = mh_InsideParentRel = NULL; m_InsideIntegration = ii_Auto; InsideFindShellView(mh_InsideParentRoot); if (mh_InsideParentWND && mh_InsideParentRel) { bRepeat = true; goto wrap; } // Last chance - try to post key sequence "F10 Left Left Down Down Down Left" // This will opens popup menu containing "Tip of the day" menuitem // "Esc Esc Esc" it and post {WM_COMMAND,EMID_TIPOFDAY} again WORD vkPostKeys[] = {VK_ESCAPE, VK_ESCAPE, VK_ESCAPE, VK_RIGHT, VK_RIGHT, VK_RIGHT, VK_DOWN, VK_DOWN, VK_DOWN, VK_RIGHT, VK_ESCAPE, VK_ESCAPE, VK_ESCAPE, 0}; // Go if (SendVkKeySequence(mh_InsideParentRoot, vkPostKeys)) { // Try again (Tip of the day) lSendRc = SendMessageTimeout(mh_InsideParentRoot, WM_COMMAND, EMID_TIPOFDAY/*41536*/, 0, SMTO_NOTIMEOUTIFNOTHUNG, 5000, &nRc); // Wait and check again Sleep(500); mh_InsideParentWND = mh_InsideParentRel = NULL; m_InsideIntegration = ii_Auto; InsideFindShellView(mh_InsideParentRoot); if (mh_InsideParentWND && mh_InsideParentRel) { bRepeat = true; goto wrap; } } } wrap: if (bRepeat) { mb_TipPaneWasShown = true; } return bRepeat; }
bool CConEmuInside::InsideFindShellView(HWND hFrom) { wchar_t szClass[128]; wchar_t szParent[128]; wchar_t szRoot[128]; HWND hChild = NULL; // Для WinXP HWND hXpView = NULL, hXpPlace = NULL; while ((hChild = FindWindowEx(hFrom, hChild, NULL, NULL)) != NULL) { // Нас интересуют только видимые окна! if (!IsWindowVisible(hChild)) continue; // Windows 7, Windows 8. GetClassName(hChild, szClass, countof(szClass)); if (lstrcmp(szClass, L"SHELLDLL_DefView") == 0) { GetClassName(hFrom, szParent, countof(szParent)); if (lstrcmp(szParent, L"CtrlNotifySink") == 0) { HWND hParent = GetParent(hFrom); if (hParent) { GetClassName(hParent, szRoot, countof(szRoot)); _ASSERTE(lstrcmp(szRoot, L"DirectUIHWND") == 0); mh_InsideParentWND = hParent; mh_InsideParentRel = hFrom; m_InsideIntegration = ii_Explorer; return true; } } else if ((gnOsVer < 0x600) && (lstrcmp(szParent, L"ExploreWClass") == 0)) { _ASSERTE(mh_InsideParentRoot == hFrom); hXpView = hChild; } } else if ((gnOsVer < 0x600) && (lstrcmp(szClass, L"BaseBar") == 0)) { RECT rcBar = {}; GetWindowRect(hChild, &rcBar); MapWindowPoints(NULL, hFrom, (LPPOINT)&rcBar, 2); RECT rcParent = {}; GetClientRect(hFrom, &rcParent); if ((-10 <= (rcBar.right - rcParent.right)) && ((rcBar.right - rcParent.right) <= 10)) { // Нас интересует область, прилепленная к правому-нижнему углу hXpPlace = hChild; } } // Путь в этом (hChild) хранится в формате "Address: D:\users\max" else if ((gnOsVer >= 0x600) && lstrcmp(szClass, L"ToolbarWindow32") == 0) { GetClassName(hFrom, szParent, countof(szParent)); if (lstrcmp(szParent, L"Breadcrumb Parent") == 0) { HWND hParent = GetParent(hFrom); if (hParent) { GetClassName(hParent, szRoot, countof(szRoot)); _ASSERTE(lstrcmp(szRoot, L"msctls_progress32") == 0); mh_InsideParentPath = hChild; // Остается ComboBox/Edit, в который можно запихнуть путь, чтобы заставить эксплорер по нему перейти // Но есть проблема. Этот контрол не создается при открытии окна! return true; } } } if ((hChild != hXpView) && (hChild != hXpPlace)) { if (InsideFindShellView(hChild)) { if (mh_InsideParentRel && mh_InsideParentPath) return true; else break; } } if (hXpView && hXpPlace) { mh_InsideParentRel = FindWindowEx(hXpPlace, NULL, L"ReBarWindow32", NULL); if (!mh_InsideParentRel) { _ASSERTE(mh_InsideParentRel && L"ReBar must be found on XP & 2k3"); return true; // закончить поиск } mh_InsideParentWND = hXpPlace; mh_InsideParentPath = mh_InsideParentRoot; m_InsideIntegration = ii_Explorer; return true; } } return false; }
// Вызывается для инициализации из Settings::LoadSettings() HWND CConEmuInside::InsideFindParent() { bool bFirstStep = true; DWORD nParentPID = 0; if (!m_InsideIntegration) { return NULL; } if (mh_InsideParentWND) { if (IsWindow(mh_InsideParentWND)) { if (m_InsideIntegration == ii_Simple) { if (mh_InsideParentRoot == NULL) { // Если еще не искали "корневое" окно HWND hParent = mh_InsideParentWND; while (hParent) { mh_InsideParentRoot = hParent; hParent = GetParent(hParent); } } // В этом режиме занимаем всю клиентскую область _ASSERTE(mh_InsideParentRel==NULL); mh_InsideParentRel = NULL; } _ASSERTE(mh_InsideParentWND!=NULL); goto wrap; } else { if (m_InsideIntegration == ii_Simple) { DisplayLastError(L"Specified window not found"); mh_InsideParentWND = NULL; goto wrap; } _ASSERTE(IsWindow(mh_InsideParentWND)); mh_InsideParentRoot = mh_InsideParentWND = mh_InsideParentRel = NULL; } } _ASSERTE(m_InsideIntegration!=ii_Simple); if (mn_InsideParentPID) { PROCESSENTRY32 pi = {sizeof(pi)}; if ((mn_InsideParentPID == GetCurrentProcessId()) || !GetProcessInfo(mn_InsideParentPID, &pi)) { DisplayLastError(L"Invalid parent process specified"); m_InsideIntegration = ii_None; mh_InsideParentWND = NULL; goto wrap; } nParentPID = mn_InsideParentPID; } else { PROCESSENTRY32 pi = {sizeof(pi)}; if (!GetProcessInfo(GetCurrentProcessId(), &pi) || !pi.th32ParentProcessID) { DisplayLastError(L"GetProcessInfo(GetCurrentProcessId()) failed"); m_InsideIntegration = ii_None; mh_InsideParentWND = NULL; goto wrap; } nParentPID = pi.th32ParentProcessID; } EnumWindows(EnumInsideFindParent, nParentPID); if (!mh_InsideParentRoot) { int nBtn = MsgBox(L"Can't find appropriate parent window!\n\nContinue in normal mode?", MB_ICONSTOP|MB_YESNO|MB_DEFBUTTON2); if (nBtn != IDYES) { mh_InsideParentWND = INSIDE_PARENT_NOT_FOUND; return mh_InsideParentWND; // Закрыться! } // Продолжить в обычном режиме m_InsideIntegration = ii_None; mh_InsideParentWND = NULL; goto wrap; } HWND hExistConEmu; if ((hExistConEmu = InsideFindConEmu(mh_InsideParentRoot)) != NULL) { _ASSERTE(FALSE && "Continue to create tab in existing instance"); // Если в проводнике уже есть ConEmu - открыть в нем новую вкладку gpSetCls->SingleInstanceShowHide = sih_None; LPCWSTR pszCmdLine = GetCommandLine(); LPCWSTR pszCmd = StrStrI(pszCmdLine, L" /cmd "); gpConEmu->RunSingleInstance(hExistConEmu, pszCmd ? (pszCmd + 6) : NULL); mh_InsideParentWND = INSIDE_PARENT_NOT_FOUND; return mh_InsideParentWND; // Закрыться! } // Теперь нужно найти дочерние окна // 1. в которое будем внедряться // 2. по которому будем позиционироваться // 3. для синхронизации текущего пути InsideFindShellView(mh_InsideParentRoot); RepeatCheck: if (!mh_InsideParentWND || (!mh_InsideParentRel && (m_InsideIntegration == ii_Explorer))) { wchar_t szAddMsg[128] = L"", szMsg[1024]; if (bFirstStep) { bFirstStep = false; if (TurnExplorerTipPane(szAddMsg)) { goto RepeatCheck; } } //MessageBox(L"Can't find appropriate shell window!", MB_ICONSTOP); _wsprintf(szMsg, SKIPLEN(countof(szMsg)) L"%sCan't find appropriate shell window!\nUnrecognized layout of the Explorer.\n\nContinue in normal mode?", szAddMsg); int nBtn = MsgBox(szMsg, MB_ICONSTOP|MB_YESNO|MB_DEFBUTTON2); if (nBtn != IDYES) { mh_InsideParentWND = INSIDE_PARENT_NOT_FOUND; return mh_InsideParentWND; // Закрыться! } m_InsideIntegration = ii_None; mh_InsideParentRoot = NULL; mh_InsideParentWND = NULL; goto wrap; } wrap: if (!mh_InsideParentWND) { m_InsideIntegration = ii_None; mh_InsideParentRoot = NULL; } else { GetWindowThreadProcessId(mh_InsideParentWND, &mn_InsideParentPID); // Для мониторинга папки GetCurrentDirectory(countof(ms_InsideParentPath), ms_InsideParentPath); int nLen = lstrlen(ms_InsideParentPath); if ((nLen > 3) && (ms_InsideParentPath[nLen-1] == L'\\')) { ms_InsideParentPath[nLen-1] = 0; } } return mh_InsideParentWND; }
// Вызывается для инициализации из Settings::LoadSettings() HWND CConEmuInside::InsideFindParent() { bool bFirstStep = true; DWORD nParentPID = 0; PROCESSENTRY32 pi = {sizeof(pi)}; EnumFindParentArg find = {}; if (!m_InsideIntegration) { return NULL; } if (mh_InsideParentWND) { if (IsWindow(mh_InsideParentWND)) { if (m_InsideIntegration == ii_Simple) { // We cover all client area of mh_InsideParentWND in this mode _ASSERTE(mh_InsideParentRel==NULL); mh_InsideParentRel = NULL; } _ASSERTE(mh_InsideParentWND!=NULL); goto wrap; } else { if (m_InsideIntegration == ii_Simple) { DisplayLastError(L"Specified window not found"); SetInsideParentWND(NULL); goto wrap; } _ASSERTE(IsWindow(mh_InsideParentWND)); SetInsideParentWND(mh_InsideParentRel = NULL); } } _ASSERTE(m_InsideIntegration!=ii_Simple); if (mn_InsideParentPID) { if ((mn_InsideParentPID == GetCurrentProcessId()) || !GetProcessInfo(mn_InsideParentPID, &pi)) { DisplayLastError(L"Invalid parent process specified"); m_InsideIntegration = ii_None; SetInsideParentWND(NULL); goto wrap; } nParentPID = mn_InsideParentPID; } else { PROCESSENTRY32 pi = {sizeof(pi)}; if (!GetProcessInfo(GetCurrentProcessId(), &pi) || !pi.th32ParentProcessID) { DisplayLastError(L"GetProcessInfo(GetCurrentProcessId()) failed"); m_InsideIntegration = ii_None; SetInsideParentWND(NULL); goto wrap; } nParentPID = pi.th32ParentProcessID; } // Do window enumeration find.nPID = nParentPID; ::EnumWindows(EnumInsideFindParent, (LPARAM)&find); if (!find.hParentRoot) { int nBtn = MsgBox(L"Can't find appropriate parent window!\n\nContinue in normal mode?", MB_ICONSTOP|MB_YESNO|MB_DEFBUTTON2); if (nBtn != IDYES) { SetInsideParentWND(INSIDE_PARENT_NOT_FOUND); return mh_InsideParentWND; // Закрыться! } // Продолжить в обычном режиме m_InsideIntegration = ii_None; SetInsideParentWND(NULL); goto wrap; } mh_InitialRoot = find.hParentRoot; mn_InsideParentPID = nParentPID; HWND hExistConEmu; if ((hExistConEmu = InsideFindConEmu(find.hParentRoot)) != NULL) { _ASSERTE(FALSE && "Continue to create tab in existing instance"); // Если в проводнике уже есть ConEmu - открыть в нем новую вкладку gpSetCls->SingleInstanceShowHide = sih_None; LPCWSTR pszCmdLine = GetCommandLine(); CEStr lsArg; LPCWSTR pszCmd = pszCmdLine; while (0 == NextArg(&pszCmd, lsArg)) { if (lsArg.OneOfSwitches(L"-runlist",L"-cmdlist")) { pszCmd = NULL; break; } else if (lsArg.OneOfSwitches(L"-run",L"-cmd")) { break; } } gpConEmu->RunSingleInstance(hExistConEmu, (pszCmd && *pszCmd) ? (pszCmd) : NULL); SetInsideParentWND(INSIDE_PARENT_NOT_FOUND); return mh_InsideParentWND; // Закрыться! } // Теперь нужно найти дочерние окна // 1. в которое будем внедряться // 2. по которому будем позиционироваться // 3. для синхронизации текущего пути InsideFindShellView(find.hParentRoot); RepeatCheck: if (!isInsideWndSet() || (!mh_InsideParentRel && (m_InsideIntegration == ii_Explorer))) { wchar_t szAddMsg[128] = L"", szMsg[1024]; if (bFirstStep) { bFirstStep = false; if (TurnExplorerTipPane(szAddMsg)) { goto RepeatCheck; } } _wsprintf(szMsg, SKIPLEN(countof(szMsg)) L"%sCan't find appropriate shell window!\nUnrecognized layout of the Explorer.\n\nContinue in normal mode?", szAddMsg); int nBtn = MsgBox(szMsg, MB_ICONSTOP|MB_YESNO|MB_DEFBUTTON2); if (nBtn != IDYES) { SetInsideParentWND(INSIDE_PARENT_NOT_FOUND); return mh_InsideParentWND; // Закрыться! } m_InsideIntegration = ii_None; SetInsideParentWND(NULL); goto wrap; } wrap: if (!isInsideWndSet()) { m_InsideIntegration = ii_None; } else { GetWindowThreadProcessId(mh_InsideParentWND, &mn_InsideParentPID); // Для мониторинга папки GetCurrentDirectory(countof(ms_InsideParentPath), ms_InsideParentPath); int nLen = lstrlen(ms_InsideParentPath); if ((nLen > 3) && (ms_InsideParentPath[nLen-1] == L'\\')) { ms_InsideParentPath[nLen-1] = 0; } } return mh_InsideParentWND; }