// Issue 1191: ConEmu was launched instead of explorer from taskbar pinned library icon void CSetPgIntegr::UnregisterShellInvalids() { HKEY hkDir; if (0 == RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Classes\\LibraryFolder\\shell", 0, KEY_READ, &hkDir)) { int iOthers = 0; MArray<wchar_t*> lsNames; for (DWORD i = 0; i < 512; i++) { wchar_t szName[MAX_PATH+32] = {}; wchar_t szCmd[MAX_PATH*4]; DWORD cchMax = countof(szName) - 32; if (0 != RegEnumKeyEx(hkDir, i, szName, &cchMax, NULL, NULL, NULL, NULL)) break; wchar_t* pszSlash = szName + _tcslen(szName); wcscat_c(szName, L"\\command"); HKEY hkCmd = NULL; if (0 == RegOpenKeyEx(hkDir, szName, 0, KEY_READ, &hkCmd)) { DWORD cbMax = sizeof(szCmd)-2; if (0 == RegQueryValueEx(hkCmd, NULL, NULL, NULL, (LPBYTE)szCmd, &cbMax)) { szCmd[cbMax>>1] = 0; *pszSlash = 0; //LPCWSTR pszInside = StrStrI(szCmd, L"-inside"); LPCWSTR pszConEmu = StrStrI(szCmd, L"conemu"); if (pszConEmu) lsNames.push_back(lstrdup(szName)); else iOthers++; } RegCloseKey(hkCmd); }
static INT_PTR WLoadWindows(MArray<WindowInfo>& wCurrent, int windowCount) { WindowInfo WInfo; wCurrent.clear(); // Load window list for (int i = 0; i < windowCount; i++) { ZeroStruct(WInfo); WInfo.StructSize = sizeof(WInfo); WInfo.Pos = i; if (!InfoW2800->AdvControl(&guid_ConEmu, ACTL_GETWINDOWINFO, 0, &WInfo)) continue; if (WInfo.Type != WTYPE_EDITOR && WInfo.Type != WTYPE_VIEWER && WInfo.Type != WTYPE_PANELS) continue; if (WInfo.Type == WTYPE_PANELS) { if ((wCurrent.size() > 0) && (wCurrent[0].Type == WTYPE_PANELS)) wCurrent[0] = WInfo; else wCurrent.insert(0, WInfo); } else { wCurrent.push_back(WInfo); } } return wCurrent.size(); }
void ReleaseVectors() { Switch* p; while (stdSwitches.pop_back(p)) SafeDelete(p); while (ourSwitches.pop_back(p)) SafeDelete(p); };
VALUE OR_Matrix::to_ruby() { Matrix matrix; MArray<double> values; double cell; int i, number_of_values; VALUE argv[2]; matrix = octave_val.matrix_value(); int number_of_rows = matrix.rows(); int number_of_columns = matrix.columns(); if ((number_of_rows == 0) && (number_of_columns == 0)) { return rb_ary_new2(0); } else if (number_of_columns == 1) { values = matrix.column(0); } else { argv[0] = INT2FIX(number_of_rows); argv[1] = INT2FIX(number_of_columns); ruby_val = rb_class_new_instance(2, argv, rb_path2class("Octave::Matrix")); int row_index, column_index = 0; VALUE cells, row; cells = rb_ary_new2(number_of_rows); for (row_index = 0; row_index < number_of_rows; row_index++) { row = rb_ary_new2(number_of_columns); values = matrix.row(row_index); for (column_index = 0; column_index < number_of_columns; column_index++) { cell = values(column_index); if (xisnan(cell) || octave_is_NA(cell)) { rb_ary_push(row, Qnil); } else { rb_ary_push(row, rb_float_new(cell)); } } rb_ary_push(cells, row); } rb_iv_set(ruby_val, "@cells", cells); return ruby_val; } number_of_values = values.length(); ruby_val = rb_ary_new2(number_of_values); for (i = 0; i < number_of_values; i++) { cell = values(i); if (xisnan(cell) || octave_is_NA(cell)) { rb_ary_push(ruby_val, Qnil); } else { rb_ary_push(ruby_val, rb_float_new(cell)); } } return ruby_val; }
// Set resource item bool CLngRc::SetResource(MArray<LngRcItem>& arr, int idx, LPCWSTR asValue, bool bLocalized) { if (idx < 0) { _ASSERTE(idx >= 0); return false; } _ASSERTE(!bLocalized || (asValue && *asValue)); if (idx >= arr.size()) { LngRcItem dummy = {}; arr.set_at(idx, dummy); } bool bOk = false; LngRcItem& item = arr[idx]; // Caching: no resource was found for that id if (!asValue || !*asValue) { if (item.Str) item.Str[0] = 0; item.Processed = true; item.Localized = false; return true; } size_t iLen = wcslen(asValue); if (iLen >= (u16)-1) { // Too long string? _ASSERTE(iLen < (u16)-1); } else { if (item.Str && (item.MaxLen >= iLen)) { _wcscpy_c(item.Str, item.MaxLen, asValue); } else { //TODO: thread-safe SafeFree(item.Str); item.MaxLen = iLen; item.Str = lstrdup(asValue); } bOk = (item.Str != NULL); } item.Processed = bOk; item.Localized = (bOk && bLocalized); return bOk; }
// Create the command to show on the Integration settings page LPCWSTR CreateCommand(CEStr& rsReady) { rsReady = L""; for (INT_PTR i = 0; i < ourSwitches.size(); i++) { Switch* ps = ourSwitches[i]; _ASSERTE(ps && !ps->szSwitch.IsEmpty()); bool bOpt = !ps->szOpt.IsEmpty(); bool bQuot = (bOpt && IsQuotationNeeded(ps->szOpt)); lstrmerge(&rsReady.ms_Val, ps->szSwitch, bOpt ? L" " : NULL, bQuot ? L"\"" : NULL, bOpt ? ps->szOpt.c_str() : NULL, bQuot ? L"\" " : L" "); } if (!rsReady.IsEmpty() || bCmdList) { lstrmerge(&rsReady.ms_Val, bCmdList ? L"-runlist " : L"-run ", szCmd); } else { rsReady.Set(szCmd); } return rsReady.c_str(L""); };
size_t CConEmuCtrl::GetOpenedPanels(wchar_t*& pszDirs, int& iCount, int& iCurrent) { CmdArg szActiveDir, szPassive; CVConGuard VCon; MArray<wchar_t*> Dirs; size_t cchAllLen = 1; iCount = iCurrent = 0; for (int V = 0; CVConGroup::GetVCon(V, &VCon, true); V++) { VCon->RCon()->GetPanelDirs(szActiveDir, szPassive); if (VCon->isActive(false)) iCurrent = iCount; LPCWSTR psz[] = {szActiveDir.ms_Arg, szPassive.ms_Arg}; for (int i = 0; i <= 1; i++) { if (psz[i] && psz[i][0]) { int iLen = lstrlen(psz[i]); cchAllLen += (iLen+1); Dirs.push_back(lstrdup(psz[i])); iCount++; } } } _ASSERTE(pszDirs == NULL); pszDirs = (wchar_t*)malloc(cchAllLen*sizeof(*pszDirs)); if (!pszDirs) return 0; wchar_t* psz = pszDirs; for (int i = 0; i < Dirs.size(); i++) { wchar_t* p = Dirs[i]; _wcscpy_c(psz, cchAllLen, p); psz += lstrlen(psz)+1; free(p); } return cchAllLen; }
void CLngRc::Clean(MArray<CLngRc::LngRcItem>& arr) { for (INT_PTR i = arr.size()-1; i >= 0; --i) { LngRcItem& l = arr[i]; l.Processed = false; l.Localized = false; l.MaxLen = 0; SafeFree(l.Str); } }
MArray<CDpiForDialog::DlgItem>* CDpiForDialog::LoadDialogItems(HWND hDlg) { MArray<DlgItem>* p = new MArray<DlgItem>(); DlgItem i = {hDlg}; if (!GetWindowRect(hDlg, &i.r)) { delete p; return NULL; } OffsetRect(&i.r, -i.r.left, -i.r.top); p->push_back(i); i.h = NULL; while ((i.h = FindWindowEx(hDlg, i.h, NULL, NULL)) != NULL) { if (GetWindowRect(i.h, &i.r) && MapWindowPoints(NULL, hDlg, (LPPOINT)&i.r, 2)) { #ifdef _DEBUG DWORD_PTR ID = GetWindowLong(i.h, GWL_ID); if (ID == cbExtendFonts) { RECT rcMargin = {}; if (Button_GetTextMargin(i.h, &rcMargin)) { wchar_t szLog[100]; _wsprintf(szLog, SKIPCOUNT(szLog) L"CheckBox Rect={%i,%i}-{%i,%i} Margin={%i,%i}-{%i,%i}", LOGRECTCOORDS(i.r), LOGRECTCOORDS(rcMargin)); LogString(szLog); } } #endif p->push_back(i); } } return p; }
MArray<CDpiForDialog::DlgItem>* CDpiForDialog::LoadDialogItems(HWND hDlg) { MArray<DlgItem>* p = new MArray<DlgItem>(); DlgItem i = {hDlg}; if (!GetWindowRect(hDlg, &i.r)) { delete p; return NULL; } OffsetRect(&i.r, -i.r.left, -i.r.top); p->push_back(i); i.h = NULL; while ((i.h = FindWindowEx(hDlg, i.h, NULL, NULL)) != NULL) { if (GetWindowRect(i.h, &i.r) && MapWindowPoints(NULL, hDlg, (LPPOINT)&i.r, 2)) { p->push_back(i); } } return p; }
static INT_PTR WExists(const WindowInfo& C, const MArray<WindowInfo>& wList) { for (INT_PTR j = 0; j < wList.size(); j++) { const WindowInfo& L = wList[j]; if (L.Type != C.Type) continue; if ((L.Type != WTYPE_PANELS) && (L.Id != C.Id)) continue; return j; } return -1; }
// Parse switches stored in gpConEmu during initialization (AppendExtraArgs) // These are, for example, `-lngfile`, `-fontdir`, and so on. void ParseStdSwitches() { _ASSERTE(stdSwitches.empty()); CEStr szArg, szNext, lsExta; LPCWSTR psz, pszExtraArgs; pszExtraArgs = gpConEmu->MakeConEmuStartArgs(lsExta); psz = pszExtraArgs; while (psz && *psz) { Switch* ps = GetNextPair(psz); if (!ps) { continue; } if (IsIgnored(ps, GetSkipSwitches())) { SafeDelete(ps); continue; } stdSwitches.push_back(ps); } };
bool CLngRc::GetResource(MArray<LngRcItem>& arr, int idx, CEStr& lsText) { bool bFound = false; if ((idx >= 0) && (idx < arr.size())) { const LngRcItem& item = arr[idx]; if (item.Processed && (item.Str && *item.Str)) { lsText.Set(item.Str); bFound = true; } } return bFound; }
bool IsIgnored(Switch* ps, MArray<Switch*>& Skip) { if (ps) { return true; } for (INT_PTR i = Skip.size()-1; i >= 0; i--) { if (!ps->szSwitch.IsSwitch(Skip[i]->szSwitch)) continue; if (0 != ps->szOpt.Compare(Skip[i]->szOpt, true)) { // Allow to add switch? return false; } return true; } return false; };
bool CAttachDlg::OnStartAttach() { bool lbRc = false; // Тут нужно получить инфу из списка и дернуть собственно аттач wchar_t szItem[128] = {}; //DWORD nPID = 0, nBits = WIN3264TEST(32,64); //AttachProcessType nType = apt_Unknown; wchar_t *psz; int iSel, iCur; DWORD nTID; HANDLE hThread = NULL; AttachParm *pParm = NULL; MArray<AttachParm> Parms; //HWND hAttachWnd = NULL; ShowWindow(mh_Dlg, SW_HIDE); BOOL bAlternativeMode = (IsDlgButtonChecked(mh_Dlg, IDC_ATTACH_ALT) != 0); iSel = ListView_GetNextItem(mh_List, -1, LVNI_SELECTED); while (iSel >= 0) { iCur = iSel; iSel = ListView_GetNextItem(mh_List, iCur, LVNI_SELECTED); AttachParm L = {NULL, 0, WIN3264TEST(32,64), apt_Unknown, bAlternativeMode}; ListView_GetItemText(mh_List, iCur, alc_PID, szItem, countof(szItem)-1); L.nPID = wcstoul(szItem, &psz, 10); if (L.nPID) { psz = wcschr(szItem, L'['); if (!psz) { _ASSERTE(FALSE && "Process bitness was not detected?"); } else { L.nBits = wcstoul(psz+1, &psz, 10); } } ListView_GetItemText(mh_List, iCur, alc_Type, szItem, countof(szItem)); if (lstrcmp(szItem, szTypeCon) == 0) L.nType = apt_Console; else if (lstrcmp(szItem, szTypeGui) == 0) L.nType = apt_Gui; ListView_GetItemText(mh_List, iCur, alc_HWND, szItem, countof(szItem)); L.hAttachWnd = (szItem[0]==L'0' && szItem[1]==L'x') ? (HWND)(DWORD_PTR)wcstoul(szItem+2, &psz, 16) : NULL; if (!L.nPID || !L.nBits || !L.nType || !L.hAttachWnd) { MBoxAssert(L.nPID && L.nBits && L.nType && L.hAttachWnd); goto wrap; } Parms.push_back(L); } if (Parms.empty()) { goto wrap; } else { AttachParm N = {NULL}; Parms.push_back(N); } //// Чтобы клик от мышки в консоль не провалился //WARNING("Клик от мышки в консоль проваливается"); //gpConEmu->mouse.nSkipEvents[0] = WM_LBUTTONUP; //gpConEmu->mouse.nSkipEvents[1] = 0; //gpConEmu->mouse.nReplaceDblClk = 0; // Все, диалог закрываем, чтобы не мешался Close(); // Работу делаем в фоновом потоке, чтобы не блокировать главный // (к окну ConEmu должна подцепиться новая вкладка) pParm = Parms.detach(); if (!pParm) { _wsprintf(szItem, SKIPLEN(countof(szItem)) L"ConEmu Attach, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); DisplayLastError(L"Parms.detach() failed", -1, 0, szItem); goto wrap; } else { hThread = apiCreateThread((LPTHREAD_START_ROUTINE)StartAttachThread, pParm, &nTID, "CAttachDlg::StartAttachThread#1"); if (!hThread) { DWORD dwErr = GetLastError(); _wsprintf(szItem, SKIPLEN(countof(szItem)) L"ConEmu Attach, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); DisplayLastError(L"Can't start attach thread", dwErr, 0, szItem); } else lbRc = true; } wrap: // We don't need this handle if (hThread) CloseHandle(hThread); return lbRc; }
CAttachDlg::AttachMacroRet CAttachDlg::AttachFromMacro(DWORD anPID, bool abAlternative) { MArray<AttachParm> Parms; HWND hFind = NULL; CProcessData ProcessData; while ((hFind = FindWindowEx(NULL, hFind, NULL, NULL)) != NULL) { if (!IsWindowVisible(hFind)) continue; AttachWndInfo Info = {}; if (!GetWindowThreadProcessId(hFind, &Info.nPID) || (Info.nPID != anPID)) continue; if (!CanAttachWindow(hFind, 0, &ProcessData, Info)) continue; AttachParm p = {}; p.hAttachWnd = hFind; p.nPID = Info.nPID; p.nBits = Info.nImageBits; if (lstrcmp(Info.szType, szTypeCon) == 0) p.nType = apt_Console; else if (lstrcmp(Info.szType, szTypeGui) == 0) p.nType = apt_Gui; else continue; p.bAlternativeMode = abAlternative; Parms.push_back(p); } if (Parms.empty()) return amr_WindowNotFound; if (Parms.size() > 1) return amr_Ambiguous; AttachParm Null = {}; Parms.push_back(Null); // Работу делаем в фоновом потоке, чтобы не блокировать главный // (к окну ConEmu должна подцепиться новая вкладка) AttachParm* pParm = Parms.detach(); if (!pParm) return amr_Unexpected; DWORD nTID = 0; HANDLE hThread = apiCreateThread((LPTHREAD_START_ROUTINE)StartAttachThread, pParm, &nTID, "CAttachDlg::StartAttachThread#2"); if (!hThread) { //DWORD dwErr = GetLastError(); //_wsprintf(szItem, SKIPLEN(countof(szItem)) L"ConEmu Attach, PID=%u, TID=%u", GetCurrentProcessId(), GetCurrentThreadId()); //DisplayLastError(L"Can't start attach thread", dwErr, 0, szItem); return amr_Unexpected; } // We don't need this handle CloseHandle(hThread); return amr_Success; }
void CRunQueue::ProcessRunQueue() { #ifdef _DEBUG // We run in self thread if (mb_InExecution) { _ASSERTE(!mb_InExecution); } #endif // Block adding new requests from other threads MArray<RunQueueItem> Stack; MSectionLockSimple cs; cs.Lock(mpcs_QueueLock); RunQueueItem item = {}; while (m_RunQueue.pop_back(item)) { //item = m_RunQueue[0]; //m_RunQueue.erase(0); Stack.push_back(item); } cs.Unlock(); DWORD nCurDelay, nWaitExtra; bool bOpt; // And process stack while (!mb_Terminate && Stack.pop_back(item)) { if (!gpConEmu->isValid(item.pVCon)) continue; CVConGuard VCon(item.pVCon); if (!VCon.VCon()) continue; // Avoid too fast process creation? if (mn_LastExecutionTick) { nCurDelay = (GetTickCount() - mn_LastExecutionTick); if (nCurDelay < RUNQUEUE_CREATE_LAG) { nWaitExtra = (RUNQUEUE_CREATE_LAG - nCurDelay); Sleep(nWaitExtra); } } mb_InExecution = true; bOpt = gpConEmu->ExecuteProcessPrepare(); VCon->RCon()->OnStartProcessAllowed(); gpConEmu->ExecuteProcessFinished(bOpt); mb_InExecution = false; // Remember last execution moment mn_LastExecutionTick = GetTickCount(); } }
// pszFull comes from registry's [HKCR\Directory\shell\...\command] // Example: // "C:\Tools\ConEmu.exe" -inside -LoadCfgFile "C:\Tools\ConEmu.xml" -FontDir C:\Tools\ConEmu // -lngfile C:\Tools\ConEmu\ConEmu.l10n -lng ru -dir "%1" -run {cmd} -cur_console:n // Strip switches which match current instance startup arguments // No sense to show them (e.g. "-lng ru") in the Integration dialog page void StripDupSwitches(LPCWSTR pszFull) { bCmdList = false; szCmd = L""; szDirSync = L""; szConfig = L""; ReleaseVectors(); CEStr szArg, szNext; LPCWSTR psz; Switch* ps = NULL; // First, parse our extra args (passed to current ConEmu.exe) ParseStdSwitches(); // Now parse new switches (command from registry or from field on Integration page) // Drop `-dir "..."` (especially from registry) always! psz = pszFull; while (0 == NextArg(&psz, szArg)) { if (!szArg.IsPossibleSwitch()) continue; if (szArg.OneOfSwitches(L"-inside", L"-here")) { // Nop } else if (szArg.IsSwitch(L"-inside:")) // Both "-inside:" and "-inside=" notations are supported { szDirSync.Set(szArg.Mid(8)); // may be empty! } else if (szArg.IsSwitch(L"-config")) { if (0 != NextArg(&psz, szArg)) break; szConfig.Set(szArg); } else if (szArg.IsSwitch(L"-dir")) { if (0 != NextArg(&psz, szArg)) break; _ASSERTE(lstrcmpi(szArg, L"%1")==0); } else if (szArg.OneOfSwitches(L"-Single", L"-NoSingle", L"-ReUse")) { ps = new Switch(szArg.Detach(), NULL); ourSwitches.push_back(ps); } else if (szArg.OneOfSwitches(L"-run", L"-cmd", L"-runlist", L"-cmdlist")) { // FIN! LAST SWITCH! szCmd.Set(psz); bCmdList = szArg.OneOfSwitches(L"-runlist",L"-cmdlist"); break; } else if (NULL != (ps = GetNextSwitch(psz, szArg))) { if (IsIgnored(ps, GetSkipSwitches()) || IsIgnored(ps, stdSwitches)) { SafeDelete(ps); } else { ourSwitches.push_back(ps); } } } };
bool CLngRc::LoadSection(MJsonValue* pJson, MArray<LngRcItem>& arr, int idDiff) { bool bRc = false; MJsonValue jRes, jItem; _ASSERTE(!ms_Lng.IsEmpty()); for (INT_PTR i = arr.size()-1; i >= 0; --i) { LngRcItem& l = arr[i]; l.Processed = false; l.Localized = false; } size_t iCount = pJson->getLength(); for (size_t i = 0; i < iCount; i++) { if (!pJson->getItem(i, jRes) || (jRes.getType() != MJsonValue::json_Object)) continue; // Now, jRes contains something like this: // { // "en": "Decrease window height (check ‘Resize with arrows’)", // "ru": [ "Decrease window height ", "(check ‘Resize with arrows’)" ], // "id": 2046 // } LPCWSTR lsLoc = NULL; i64 id = -1; size_t childCount = jRes.getLength(); for (INT_PTR c = (childCount - 1); c >= 0; --c) { LPCWSTR pszName = jRes.getObjectName(c); if (!pszName || !*pszName) { _ASSERTE(FALSE && "Invalid object name!"); return false; } // "id" field must be LAST! if (wcscmp(pszName, L"id") == 0) { if (!jRes.getItem(c, jItem) || (jItem.getType() != MJsonValue::json_Integer)) { _ASSERTE(FALSE && "Invalid 'id' field"); return false; } id = jItem.getInt(); if ((id <= idDiff) || ((id - idDiff) > 0xFFFF)) { _ASSERTE(FALSE && "Invalid 'id' value"); return false; } } // "id" // "en" field must be FIRST! else if ((wcscmp(pszName, ms_Lng) == 0) || (wcscmp(pszName, L"en") == 0) ) { if (id == -1) { _ASSERTE(FALSE && "Wrong format, 'id' not found!"); return false; } if (!jRes.getItem(c, jItem) || ((jItem.getType() != MJsonValue::json_String) && (jItem.getType() != MJsonValue::json_Array)) ) { _ASSERTE(FALSE && "Invalid 'lng' field"); return false; } switch (jItem.getType()) { case MJsonValue::json_String: if (!SetResource(arr, (id - idDiff), jItem.getString(), true)) { // Already asserted return false; } bRc = true; break; case MJsonValue::json_Array: if (!SetResource(arr, (id - idDiff), &jItem)) { // Already asserted return false; } bRc = true; break; default: _ASSERTE(FALSE && "Unsupported object type!") return false; } // switch (jItem.getType()) // proper lng string found and processed, go to next resource break; // for (size_t c = 0; c < childCount; c++) } // ms_Lng || "en" } // for (size_t c = 0; c < childCount; c++) } // for (size_t i = 0; i < iCount; i++) return bRc; }
bool CDpiForDialog::SetDialogDPI(const DpiValue& newDpi, LPRECT lprcSuggested /*= NULL*/) { wchar_t szLog[160]; RECT rcClient = {}, rcCurWnd = {}; #ifdef _DEBUG if (gbSkipSetDialogDPI) { GetClientRect(mh_Dlg, &rcClient); GetWindowRect(mh_Dlg, &rcCurWnd); _wsprintf(szLog, SKIPCOUNT(szLog) L"SKIPPED CDpiForDialog::SetDialogDPI x%08X, OldDpi={%i,%i}, NewDpi={%i,%i}, CurSize={%i,%i}, CurClient={%i,%i}", (DWORD)(DWORD_PTR)mh_Dlg, m_CurDpi.Xdpi, m_CurDpi.Ydpi, newDpi.Xdpi, newDpi.Ydpi, (rcCurWnd.right - rcCurWnd.left), (rcCurWnd.bottom - rcCurWnd.top), (rcClient.right - rcClient.left), (rcClient.bottom - rcClient.top)); LogString(szLog); return false; } #endif if (mn_InSet > 0) return false; if (newDpi.Ydpi <= 0 || newDpi.Xdpi <= 0) return false; if (m_CurDpi.Ydpi <= 0 || m_CurDpi.Xdpi <= 0) return false; // When overall DPI is very large but new dpi is small // (example: primary mon is 192 high-dpi, new mon is 96 dpi) // Windows goes crazy... HUGE caption, scrollbars, checkbox marks and so on... // So huge difference makes dialog unattractive, let's try to smooth that DpiValue setDpi(newDpi); if (m_InitDpi.Ydpi > MulDiv(setDpi.Ydpi, 144, 96)) { // Increase DPI one step up setDpi.Ydpi = MulDiv(setDpi.Ydpi, 120, 96); setDpi.Xdpi = MulDiv(setDpi.Xdpi, 120, 96); // Log it _wsprintf(szLog, SKIPCOUNT(szLog) L"CDpiForDialog::SetDialogDPI x%08X forces larger dpi value from {%i,%i} to {%i,%i}", (DWORD)(DWORD_PTR)mh_Dlg, newDpi.Xdpi, newDpi.Ydpi, setDpi.Xdpi, setDpi.Ydpi); LogString(szLog); } if (m_CurDpi.Equals(setDpi)) return false; bool bRc = false; MArray<DlgItem>* p = NULL; DpiValue curDpi(m_CurDpi); HFONT hf = NULL; wchar_t szClass[100]; #ifdef _DEBUG LOGFONT lftest1 = {}, lftest2 = {}; HFONT hftest; int itest1, itest2; #endif // To avoid several nested passes InterlockedIncrement(&mn_InSet); m_CurDpi.SetDpi(setDpi); // Eval mn_CurFontHeight = GetFontSizeForDpi(NULL, m_CurDpi.Ydpi); //(m_CurDpi.Ydpi && m_InitDpi.Ydpi) ? (mn_InitFontHeight * m_CurDpi.Ydpi / m_InitDpi.Ydpi) : -11; mlf_CurFont = mlf_InitFont; mlf_CurFont.lfHeight = mn_CurFontHeight; mlf_CurFont.lfWidth = 0; // Font mapper fault if (mn_CurFontHeight == 0) goto wrap; if (!m_Items.Get(m_CurDpi.Ydpi, &p)) { MArray<DlgItem>* pOrig = NULL; int iOrigDpi = 0; if (!m_Items.GetNext(NULL, &iOrigDpi, &pOrig) || !pOrig || (iOrigDpi <= 0)) goto wrap; int iNewDpi = m_CurDpi.Ydpi; p = new MArray<DlgItem>(); DWORD dwStyle = GetWindowLong(mh_Dlg, GWL_STYLE); DWORD dwStyleEx = GetWindowLong(mh_Dlg, GWL_EXSTYLE); if (!GetClientRect(mh_Dlg, &rcClient) || !GetWindowRect(mh_Dlg, &rcCurWnd)) { delete p; goto wrap; } _ASSERTE(rcClient.left==0 && rcClient.top==0); int calcDlgWidth = rcClient.right * m_CurDpi.Xdpi / curDpi.Xdpi; int calcDlgHeight = rcClient.bottom * m_CurDpi.Ydpi / curDpi.Ydpi; DlgItem i = {mh_Dlg}; // Windows DWM manager do not resize NonClient areas of per-monitor dpi aware applications // So, we can not use AdjustWindowRectEx to determine full window rectangle // Just use current NonClient dimensions i.r.right = calcDlgWidth + ((rcCurWnd.right - rcCurWnd.left) - rcClient.right); i.r.bottom = calcDlgHeight + ((rcCurWnd.bottom - rcCurWnd.top) - rcClient.bottom); // .right and .bottom are width and height of the dialog _ASSERTE(i.r.left==0 && i.r.top==0); p->push_back(i); for (INT_PTR k = 1; k < pOrig->size(); k++) { const DlgItem& iOrig = (*pOrig)[k]; i.h = iOrig.h; i.r.left = iOrig.r.left * iNewDpi / iOrigDpi; i.r.top = iOrig.r.top * iNewDpi / iOrigDpi; i.r.right = iOrig.r.right * iNewDpi / iOrigDpi; i.r.bottom = iOrig.r.bottom * iNewDpi / iOrigDpi; p->push_back(i); } m_Items.Set(iNewDpi, p); } if (p->size() <= 0) { _ASSERTE(FALSE && "No elements"); goto wrap; } else { const DlgItem& di = (*p)[0]; _wsprintf(szLog, SKIPCOUNT(szLog) L"CDpiForDialog::SetDialogDPI x%08X, OldDpi={%i,%i}, NewDpi={%i,%i}, OldSize={%i,%i}, NewSize={%i,%i}, NewFont=%i", (DWORD)(DWORD_PTR)mh_Dlg, curDpi.Xdpi, curDpi.Ydpi, newDpi.Xdpi, newDpi.Ydpi, (rcCurWnd.right - rcCurWnd.left), (rcCurWnd.bottom - rcCurWnd.top), di.r.right, di.r.bottom, mlf_CurFont.lfHeight); LogString(szLog); } hf = CreateFontIndirect(&mlf_CurFont); if (hf == NULL) { goto wrap; } for (INT_PTR k = p->size() - 1; k >= 1; k--) { const DlgItem& di = (*p)[k]; GetClassName(di.h, szClass, countof(szClass)); DWORD nCtrlID = GetWindowLong(di.h, GWL_ID); DWORD nStyles = GetWindowLong(di.h, GWL_STYLE); bool bResizeCombo = (lstrcmpi(szClass, L"ComboBox") == 0); int iComboFieldHeight = 0, iComboWasHeight = 0; LONG_PTR lFieldHeight = 0, lNewHeight = 0; RECT rcCur = {}; HWND hComboEdit = NULL; RECT rcEdit = {}, rcClient = {}; if (bResizeCombo && (nStyles & CBS_OWNERDRAWFIXED)) { GetWindowRect(di.h, &rcCur); hComboEdit = FindWindowEx(di.h, NULL, L"Edit", NULL); GetClientRect(di.h, &rcClient); GetClientRect(hComboEdit, &rcEdit); iComboWasHeight = (rcCur.bottom - rcCur.top); lFieldHeight = SendMessage(di.h, CB_GETITEMHEIGHT, -1, 0); if (lFieldHeight < iComboWasHeight) { iComboFieldHeight = lFieldHeight; } } int newW = di.r.right - di.r.left; int newH = di.r.bottom - di.r.top; MoveWindow(di.h, di.r.left, di.r.top, newW, newH, FALSE); SendMessage(di.h, WM_SETFONT, (WPARAM)hf, FALSE/*immediately*/); if (bResizeCombo) { if ((nStyles & CBS_OWNERDRAWFIXED) && (iComboWasHeight > 0) && (iComboFieldHeight > 0)) { RECT rcEdit2 = {}, rcClient2 = {}; GetClientRect(di.h, &rcClient2); GetClientRect(hComboEdit, &rcEdit2); lNewHeight = newH*iComboFieldHeight/iComboWasHeight; _wsprintf(szLog, SKIPCOUNT(szLog) L"CDpiForDialog::Combo height changed - OldHeight=%i, ItemHeight=%i, NewHeight=%i, NewItemHeight=%i", (rcCur.bottom - rcCur.top), lFieldHeight, newH, lNewHeight); LogString(szLog); SendMessage(di.h, CB_SETITEMHEIGHT, -1, lNewHeight); } SendMessage(di.h, CB_SETEDITSEL, 0, MAKELPARAM(-1,0)); } EditIconHint_ResChanged(di.h); InvalidateRect(di.h, NULL, TRUE); #ifdef _DEBUG itest1 = GetObject(hf, sizeof(lftest1), &lftest1); hftest = (HFONT)SendMessage(di.h, WM_GETFONT, 0, 0); itest2 = GetObject(hftest, sizeof(lftest2), &lftest2); #endif } if (p->size() > 0) { const DlgItem& di = (*p)[0]; SendMessage(mh_Dlg, WM_SETFONT, (WPARAM)hf, FALSE); DWORD nWndFlags = SWP_NOZORDER | (lprcSuggested ? 0 : SWP_NOMOVE); SetWindowPos(mh_Dlg, NULL, lprcSuggested ? lprcSuggested->left : 0, lprcSuggested ? lprcSuggested->top : 0, di.r.right, di.r.bottom, nWndFlags); RECT rc = {}; GetClientRect(mh_Dlg, &rc); InvalidateRect(mh_Dlg, NULL, TRUE); RedrawWindow(mh_Dlg, &rc, NULL, /*RDW_ERASE|*/RDW_ALLCHILDREN/*|RDW_INVALIDATE|RDW_UPDATENOW|RDW_INTERNALPAINT*/); } if (mh_CurFont != hf) DeleteObject(mh_CurFont); mh_CurFont = hf; bRc = true; wrap: InterlockedDecrement(&mn_InSet); return bRc; }
// Supports MultiLine and SingleLine strings // If there were no key_value or key_value_type is unexpected, DOESN'T touch *value bool SettingsXML::Load(const wchar_t *regName, wchar_t **value) noexcept { bool lbRc = false; SettingsXML::node *pChild = NULL; SettingsXML::node *pNode = NULL; const char *sType; size_t cchMax = 0; CEStrA data; LPCSTR pszData = nullptr; try { if (mp_Key) pChild = FindItem(mp_Key, L"value", regName, false); if (!pChild) return false; sType = GetAttr(pChild, "type"); if (0 == _strcmpi(sType, "multi")) { //<value name="CmdLineHistory" type="multi"> // <line data="C:\Far\Far.exe"/> // <line data="cmd"/> //</value> struct line_info { const char* str; size_t cchSize; }; MArray<line_info> lines; for (pNode = pChild->first_node("line"); pNode; pNode = pNode->next_sibling("line")) { const char* lstr = GetAttr(pNode, "data"); if (!lstr || !*lstr) lstr = " "; // Because of ASCIIZZ we must be sure there were no zero-length string size_t cchSize = strlen(lstr) + 1; cchMax += cchSize; lines.push_back({lstr, cchSize}); } if (!lines.empty()) { // ASCIIZ,ASCIIZ,...,ASCIIZ buffer if (char* buffer = data.getbuffer(cchMax)) { for (INT_PTR i = 0; i < lines.size(); ++i) { const auto& line = lines[i]; strcpy_s(buffer, line.cchSize, line.str); buffer += line.cchSize; } _ASSERTE(cchMax>=1 && data.ms_Val[cchMax-1]==0); pszData = data.c_str(); } } } else if (0 == _strcmpi(sType, "string")) { pszData = GetAttr(pChild, "data"); cchMax = pszData ? (strlen(pszData) + 1) : 0; // ASCIIZ } else { // We don't care about other data types, only strings here } // Data exist? if (pszData) { int cvt_size = MultiByteToWideChar(CP_UTF8, 0, pszData, cchMax, nullptr, 0); if (cvt_size > 0) { // Allocate data for ASCIIZZ (additional zero at the end) if ((*value = (wchar_t*)realloc(*value, (cvt_size + 1) * sizeof(**value)))) { int cvt = MultiByteToWideChar(CP_UTF8, 0, pszData, cchMax, *value, cvt_size+1); _ASSERTE(cvt == cvt_size); if (cvt > 0) { _ASSERTE((*value)[cvt-1] == 0); (*value)[cvt] = 0; // ASCIIZZ lbRc = true; } } } } } catch (rapidxml::parse_error&) { // #XML Log error lbRc = false; } return lbRc; }
bool CPluginW2800::UpdateConEmuTabsApi(int windowCount) { if (!InfoW2800 || !InfoW2800->AdvControl || gbIgnoreUpdateTabs) return false; bool lbCh = false, lbDummy = false; WindowInfo WInfo = {sizeof(WindowInfo)}; wchar_t szWNameBuffer[CONEMUTABMAX]; int tabCount = 0; bool lbActiveFound = false; _ASSERTE(GetCurrentThreadId() == gnMainThreadId); WindowInfo WActive = {sizeof(WActive)}; WActive.Pos = -1; bool bActiveInfo = InfoW2800->AdvControl(&guid_ConEmu, ACTL_GETWINDOWINFO, 0, &WActive)!=0; // Если фар запущен с ключом "/e" (как standalone редактор) - будет ассерт при первой попытке // считать информацию об окне (редактор еще не создан?, а панелей вообще нет) _ASSERTE(bActiveInfo && (WActive.Flags & WIF_CURRENT)); static WindowInfo WLastActive; if (!pwList) pwList = new MArray<WindowInfo>(); // Another weird Far API breaking change. How more?.. MArray<WindowInfo> wCurrent; // Load window list for (int i = 0; i < windowCount; i++) { ZeroStruct(WInfo); WInfo.StructSize = sizeof(WInfo); WInfo.Pos = i; if (!InfoW2800->AdvControl(&guid_ConEmu, ACTL_GETWINDOWINFO, 0, &WInfo)) continue; if (WInfo.Type != WTYPE_EDITOR && WInfo.Type != WTYPE_VIEWER && WInfo.Type != WTYPE_PANELS) continue; if (WInfo.Type == WTYPE_PANELS) { if ((wCurrent.size() > 0) && (wCurrent[0].Type == WTYPE_PANELS)) wCurrent[0] = WInfo; else wCurrent.insert(0, WInfo); } else { wCurrent.push_back(WInfo); } } // Clear closed windows for (INT_PTR i = 0; i < pwList->size();) { const WindowInfo& L = (*pwList)[i]; INT_PTR iFound = WExists(L, wCurrent); if (iFound < 0) pwList->erase(i); else i++; } // Add new windows for (INT_PTR i = 0; i < wCurrent.size(); i++) { const WindowInfo& C = wCurrent[i]; INT_PTR iFound = WExists(C, *pwList); if (iFound >= 0) { (*pwList)[iFound] = C; } else { if (C.Type == WTYPE_PANELS) { if ((pwList->size() > 0) && ((*pwList)[0].Type == WTYPE_PANELS)) (*pwList)[0] = C; else pwList->insert(0, C); } else { pwList->push_back(C); } } } // And check the count windowCount = pwList->size(); // Проверить, есть ли активный редактор/вьювер/панель if (bActiveInfo && (WActive.Type == WTYPE_EDITOR || WActive.Type == WTYPE_VIEWER || WActive.Type == WTYPE_PANELS)) { if (!(WActive.Flags & WIF_MODAL)) WLastActive = WActive; } else { int nTabs = 0, nModalTabs = 0; bool bFound = false; WindowInfo WModal, WFirst; // Поскольку в табах диалоги не отображаются - надо подменить "активное" окно // т.е. предпочитаем тот таб, который был активен ранее for (int i = 0; i < windowCount; i++) { WInfo = (*pwList)[i]; _ASSERTE(WInfo.Type == WTYPE_EDITOR || WInfo.Type == WTYPE_VIEWER || WInfo.Type == WTYPE_PANELS); if (!nTabs) WFirst = WInfo; nTabs++; if (WInfo.Flags & WIF_MODAL) { nModalTabs++; WModal = WInfo; } if (WLastActive.StructSize && (WInfo.Type == WLastActive.Type) && (WInfo.Id == WLastActive.Id)) { bActiveInfo = bFound = true; WActive = WInfo; } } if (!bFound) { if (nModalTabs) { bActiveInfo = true; WActive = WModal; } else if (nTabs) { bActiveInfo = true; WActive = WFirst; } } } for (int i = 0; i < windowCount; i++) { WInfo = (*pwList)[i]; if (WInfo.Type == WTYPE_EDITOR || WInfo.Type == WTYPE_VIEWER || WInfo.Type == WTYPE_PANELS) { WInfo.Name = szWNameBuffer; WInfo.NameSize = CONEMUTABMAX; InfoW2800->AdvControl(&guid_ConEmu, ACTL_GETWINDOWINFO, 0, &WInfo); WARNING("Для получения имени нужно пользовать ECTL_GETFILENAME"); //// Проверить, чего там... //_ASSERTE((WInfo.Flags & WIF_MODAL) == 0); if (WInfo.Type == WTYPE_EDITOR || WInfo.Type == WTYPE_VIEWER || WInfo.Type == WTYPE_PANELS) { if ((WInfo.Flags & WIF_CURRENT)) { lbActiveFound = true; } else if (bActiveInfo && (WInfo.Type == WActive.Type) && (WInfo.Id == WActive.Id)) { WInfo.Flags |= WIF_CURRENT; lbActiveFound = true; } TODO("Определение ИД редактора/вьювера"); lbCh |= AddTab(tabCount, WInfo.Pos, false/*losingFocus*/, false/*editorSave*/, WInfo.Type, WInfo.Name, /*editorSave ? ei.FileName :*/ NULL, (WInfo.Flags & WIF_CURRENT), (WInfo.Flags & WIF_MODIFIED), (WInfo.Flags & WIF_MODAL), WInfo.Id); } } } bool bHasPanels = this->CheckPanelExist(); if (!lbActiveFound) { // Порядок инициализации поменялся, при запуске "far /e ..." редактора сначала вообще "нет". _ASSERTE((!bHasPanels && windowCount==0 && bActiveInfo && WActive.Type == WTYPE_DESKTOP) && "Active window must be detected already!"); if (tabCount == 0) { // Добавить в табы хоть что-то lbCh |= AddTab(tabCount, 0, false/*losingFocus*/, false/*editorSave*/, WTYPE_PANELS, L"far", /*editorSave ? ei.FileName :*/ NULL, 1/*Current*/, 0/*Modified*/, 1/*Modal*/, 0); } if (tabCount > 0) { gpTabs->Tabs.CurrentType = gnCurrentWindowType = gpTabs->Tabs.tabs[tabCount-1].Type; } else { _ASSERTE(tabCount>0); } } // 101224 - сразу запомнить количество! gpTabs->Tabs.nTabCount = tabCount; return lbCh; }
bool CDpiForDialog::SetDialogDPI(const DpiValue& newDpi, LPRECT lprcSuggested /*= NULL*/) { if (mn_InSet > 0) return false; if (newDpi.Ydpi <= 0 || newDpi.Xdpi <= 0) return false; if (m_CurDpi.Ydpi <= 0 || m_CurDpi.Xdpi <= 0) return false; if (m_CurDpi.Equals(newDpi)) return false; bool bRc = false; MArray<DlgItem>* p = NULL; DpiValue curDpi(m_CurDpi); HFONT hf = NULL; wchar_t szClass[100]; #ifdef _DEBUG LOGFONT lftest1 = {}, lftest2 = {}; HFONT hftest; int itest1, itest2; #endif // To avoid several nested passes InterlockedIncrement(&mn_InSet); m_CurDpi.SetDpi(newDpi); _wsprintf(szClass, SKIPLEN(countof(szClass)) L"CDpiForDialog::SetDialogDPI(x%08X, {%i,%i})", (DWORD)(DWORD_PTR)mh_Dlg, newDpi.Xdpi, newDpi.Ydpi); LogString(szClass); // Eval mn_CurFontHeight = (mn_InitFontHeight * newDpi.Ydpi / 96); mlf_CurFont = mlf_InitFont; mlf_CurFont.lfHeight = mn_CurFontHeight; mlf_CurFont.lfWidth = 0; // Font mapper fault if (mn_CurFontHeight == 0 || mn_InitFontHeight == 0) goto wrap; if (!m_Items.Get(newDpi.Ydpi, &p)) { MArray<DlgItem>* pOrig = NULL; int iOrigDpi = 0; if (!m_Items.GetNext(NULL, &iOrigDpi, &pOrig) || !pOrig || (iOrigDpi <= 0)) goto wrap; int iNewDpi = newDpi.Ydpi; p = new MArray<DlgItem>(); DWORD dwStyle = GetWindowLong(mh_Dlg, GWL_STYLE); DWORD dwStyleEx = GetWindowLong(mh_Dlg, GWL_EXSTYLE); RECT rcClient = {}, rcCurWnd = {}; if (!GetClientRect(mh_Dlg, &rcClient) || !GetWindowRect(mh_Dlg, &rcCurWnd)) { delete p; goto wrap; } _ASSERTE(rcClient.left==0 && rcClient.top==0); int calcDlgWidth = rcClient.right * newDpi.Xdpi / curDpi.Xdpi; int calcDlgHeight = rcClient.bottom * newDpi.Ydpi / curDpi.Ydpi; DlgItem i = {mh_Dlg}; // Windows DWM manager do not resize NonClient areas of per-monitor dpi aware applications // So, we can not use AdjustWindowRectEx to determine full window rectangle // Just use current NonClient dimensions i.r.right = calcDlgWidth + ((rcCurWnd.right - rcCurWnd.left) - rcClient.right); i.r.bottom = calcDlgHeight + ((rcCurWnd.bottom - rcCurWnd.top) - rcClient.bottom); // .right and .bottom are width and height of the dialog _ASSERTE(i.r.left==0 && i.r.top==0); p->push_back(i); for (INT_PTR k = 1; k < pOrig->size(); k++) { const DlgItem& iOrig = (*pOrig)[k]; i.h = iOrig.h; i.r.left = iOrig.r.left * iNewDpi / iOrigDpi; i.r.top = iOrig.r.top * iNewDpi / iOrigDpi; i.r.right = iOrig.r.right * iNewDpi / iOrigDpi; i.r.bottom = iOrig.r.bottom * iNewDpi / iOrigDpi; p->push_back(i); } m_Items.Set(iNewDpi, p); } hf = CreateFontIndirect(&mlf_CurFont); if (hf == NULL) { goto wrap; } for (INT_PTR k = p->size() - 1; k >= 0; k--) { const DlgItem& di = (*p)[k]; GetClassName(di.h, szClass, countof(szClass)); DWORD nCtrlID = GetWindowLong(di.h, GWL_ID); DWORD nStyles = GetWindowLong(di.h, GWL_STYLE); bool bResizeCombo = (lstrcmpi(szClass, L"ComboBox") == 0); int iComboFieldHeight = 0, iComboWasHeight = 0; if (bResizeCombo && (nStyles & CBS_OWNERDRAWFIXED)) { RECT rcCur = {}; GetWindowRect(di.h, &rcCur); iComboWasHeight = (rcCur.bottom - rcCur.top); LONG_PTR lFieldHeight = SendMessage(di.h, CB_GETITEMHEIGHT, -1, 0); if (lFieldHeight < iComboWasHeight) { iComboFieldHeight = lFieldHeight; } } int newW = di.r.right - di.r.left; int newH = di.r.bottom - di.r.top; MoveWindow(di.h, di.r.left, di.r.top, newW, newH, FALSE); SendMessage(di.h, WM_SETFONT, (WPARAM)hf, FALSE/*immediately*/); if (bResizeCombo) { if ((nStyles & CBS_OWNERDRAWFIXED) && (iComboWasHeight > 0) && (iComboFieldHeight > 0)) SendMessage(di.h, CB_SETITEMHEIGHT, -1, newH*iComboFieldHeight/iComboWasHeight); SendMessage(di.h, CB_SETEDITSEL, 0, MAKELPARAM(-1,0)); } EditIconHint_ResChanged(di.h); InvalidateRect(di.h, NULL, TRUE); #ifdef _DEBUG itest1 = GetObject(hf, sizeof(lftest1), &lftest1); hftest = (HFONT)SendMessage(di.h, WM_GETFONT, 0, 0); itest2 = GetObject(hftest, sizeof(lftest2), &lftest2); #endif } if (p->size() > 0) { const DlgItem& di = (*p)[0]; SendMessage(mh_Dlg, WM_SETFONT, (WPARAM)hf, FALSE); DWORD nWndFlags = SWP_NOZORDER | (lprcSuggested ? 0 : SWP_NOMOVE); SetWindowPos(mh_Dlg, NULL, lprcSuggested ? lprcSuggested->left : 0, lprcSuggested ? lprcSuggested->top : 0, di.r.right, di.r.bottom, nWndFlags); RECT rc = {}; GetClientRect(mh_Dlg, &rc); InvalidateRect(mh_Dlg, NULL, TRUE); RedrawWindow(mh_Dlg, &rc, NULL, /*RDW_ERASE|*/RDW_ALLCHILDREN/*|RDW_INVALIDATE|RDW_UPDATENOW|RDW_INTERNALPAINT*/); } if (mh_CurFont != hf) DeleteObject(mh_CurFont); mh_CurFont = hf; bRc = true; wrap: InterlockedDecrement(&mn_InSet); return bRc; }