diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5e1002b..78464db 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -78,6 +78,13 @@ jobs: C:\msys64\usr\bin\patch.exe -N SimpleWindowSwitcher/sws_def.h 972acb76d1e6429133c92ed7cdefd29b9a2c6179.patch C:\msys64\usr\bin\unix2dos.exe SimpleWindowSwitcher/sws_def.h exit /b 0 + + - name: Setup NuGet + uses: nuget/setup-nuget@v1 + + - name: Restore NuGet packages + run: | + nuget restore ExplorerPatcher.sln - name: Build funchook shell: powershell diff --git a/CHANGELOG.md b/CHANGELOG.md index 54e1299..3a98e94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ This document includes the same release notes as in the [Releases](https://github.com/valinet/ExplorerPatcher/releases) section on GitHub. +## 22000.469.42 + +Tested on OS build 22000.434. + +#### New features + +* Implemented Weather widget for the classic taskbar, similar to what is available in the more recent updates to Windows 10. Read more about it [here](https://github.com/valinet/ExplorerPatcher/wiki/Weather). + ## 22000.469.41 Tested on OS build 22000.434. diff --git a/ExplorerPatcher.sln b/ExplorerPatcher.sln index ea96bec..dc50207 100644 --- a/ExplorerPatcher.sln +++ b/ExplorerPatcher.sln @@ -4,6 +4,10 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerPatcher", "ExplorerPatcher\ExplorerPatcher.vcxproj", "{DB3E4319-2969-42B6-B7E8-BB57AA8C9FA9}" + ProjectSection(ProjectDependencies) = postProject + {AF02ABAC-EAEB-471C-9957-73D430B8B4DE} = {AF02ABAC-EAEB-471C-9957-73D430B8B4DE} + {314A50C1-F0A0-4D0C-89E1-AD8F3951043E} = {314A50C1-F0A0-4D0C-89E1-AD8F3951043E} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ep_generate_release_description", "ep_generate_release_description\ep_generate_release_description.vcxproj", "{C362CFBE-7C6B-4457-8D01-839818D42ECB}" EndProject @@ -13,6 +17,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ep_setup", "ep_setup\ep_set ProjectSection(ProjectDependencies) = postProject {DB3E4319-2969-42B6-B7E8-BB57AA8C9FA9} = {DB3E4319-2969-42B6-B7E8-BB57AA8C9FA9} {1ECCAB38-61B6-4C85-BBB5-2E2232DA3A87} = {1ECCAB38-61B6-4C85-BBB5-2E2232DA3A87} + {314A50C1-F0A0-4D0C-89E1-AD8F3951043E} = {314A50C1-F0A0-4D0C-89E1-AD8F3951043E} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ep_setup_patch", "ep_setup_patch\ep_setup_patch.vcxproj", "{0C13E5F3-106B-4836-A7C2-8E5808A6ED78}" @@ -22,6 +27,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ep_setup_patch", "ep_setup_ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ep_dwm", "ep_dwm\ep_dwm\ep_dwm.vcxproj", "{1ECCAB38-61B6-4C85-BBB5-2E2232DA3A87}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ep_weather_host", "ep_weather_host\ep_weather_host.vcxproj", "{314A50C1-F0A0-4D0C-89E1-AD8F3951043E}" + ProjectSection(ProjectDependencies) = postProject + {AF02ABAC-EAEB-471C-9957-73D430B8B4DE} = {AF02ABAC-EAEB-471C-9957-73D430B8B4DE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ep_weather_host_stub", "ep_weather_host_stub\ep_weather_host_stub.vcxproj", "{AF02ABAC-EAEB-471C-9957-73D430B8B4DE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|amd64 = Debug|amd64 @@ -64,10 +76,22 @@ Global {0C13E5F3-106B-4836-A7C2-8E5808A6ED78}.Release|IA-32.ActiveCfg = Release|Win32 {1ECCAB38-61B6-4C85-BBB5-2E2232DA3A87}.Debug|amd64.ActiveCfg = Debug|x64 {1ECCAB38-61B6-4C85-BBB5-2E2232DA3A87}.Debug|amd64.Build.0 = Debug|x64 - {1ECCAB38-61B6-4C85-BBB5-2E2232DA3A87}.Debug|IA-32.ActiveCfg = Debug|x64 + {1ECCAB38-61B6-4C85-BBB5-2E2232DA3A87}.Debug|IA-32.ActiveCfg = Debug|Win32 {1ECCAB38-61B6-4C85-BBB5-2E2232DA3A87}.Release|amd64.ActiveCfg = Release|x64 {1ECCAB38-61B6-4C85-BBB5-2E2232DA3A87}.Release|amd64.Build.0 = Release|x64 {1ECCAB38-61B6-4C85-BBB5-2E2232DA3A87}.Release|IA-32.ActiveCfg = Release|Win32 + {314A50C1-F0A0-4D0C-89E1-AD8F3951043E}.Debug|amd64.ActiveCfg = Debug|x64 + {314A50C1-F0A0-4D0C-89E1-AD8F3951043E}.Debug|amd64.Build.0 = Debug|x64 + {314A50C1-F0A0-4D0C-89E1-AD8F3951043E}.Debug|IA-32.ActiveCfg = Debug|Win32 + {314A50C1-F0A0-4D0C-89E1-AD8F3951043E}.Release|amd64.ActiveCfg = Release|x64 + {314A50C1-F0A0-4D0C-89E1-AD8F3951043E}.Release|amd64.Build.0 = Release|x64 + {314A50C1-F0A0-4D0C-89E1-AD8F3951043E}.Release|IA-32.ActiveCfg = Release|Win32 + {AF02ABAC-EAEB-471C-9957-73D430B8B4DE}.Debug|amd64.ActiveCfg = Debug|x64 + {AF02ABAC-EAEB-471C-9957-73D430B8B4DE}.Debug|amd64.Build.0 = Debug|x64 + {AF02ABAC-EAEB-471C-9957-73D430B8B4DE}.Debug|IA-32.ActiveCfg = Debug|Win32 + {AF02ABAC-EAEB-471C-9957-73D430B8B4DE}.Release|amd64.ActiveCfg = Release|x64 + {AF02ABAC-EAEB-471C-9957-73D430B8B4DE}.Release|amd64.Build.0 = Release|x64 + {AF02ABAC-EAEB-471C-9957-73D430B8B4DE}.Release|IA-32.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ExplorerPatcher/GUI.c b/ExplorerPatcher/GUI.c index f645ded..653ef79 100644 --- a/ExplorerPatcher/GUI.c +++ b/ExplorerPatcher/GUI.c @@ -623,10 +623,18 @@ LSTATUS GUI_RegQueryValueExW( LPDWORD lpcbData ) { + DWORD dwSize = lpcbData ? *(DWORD*)lpcbData : sizeof(DWORD); LSTATUS lRes = GUI_Internal_RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); if (AuditFile) { - fwprintf(AuditFile, L"%s\"%s\"=dword:%08x\n", (lpValueName && wcsncmp(lpValueName, L"Virtualized_" _T(EP_CLSID), 50)) ? L"" : L";", lpValueName, *(DWORD*)lpData); + if (dwSize != sizeof(DWORD)) + { + fwprintf(AuditFile, L"%s\"%s\"=\"%s\"\n", (lpValueName && wcsncmp(lpValueName, L"Virtualized_" _T(EP_CLSID), 50)) ? L"" : L";", lpValueName, lpData); + } + else + { + fwprintf(AuditFile, L"%s\"%s\"=dword:%08x\n", (lpValueName && wcsncmp(lpValueName, L"Virtualized_" _T(EP_CLSID), 50)) ? L"" : L";", lpValueName, *(DWORD*)lpData); + } } return lRes; } @@ -1831,6 +1839,13 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) wprintf(L"%s %d\n", wszName, dwVal); GUI_RegSetValueExW(NULL, wszName, 0, RRF_RT_DWORD, &dwVal, sizeof(DWORD)); } + else + { + WCHAR* wszTitle = malloc(MAX_LINE_LENGTH * sizeof(WCHAR)); + wchar_t* x = wcschr(ddd + 2, L'"'); + x[0] = 0; + //wprintf(L">>> %s\n", ddd + 2); + } } } free(line2); @@ -1840,6 +1855,10 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) } } } + else if (!strncmp(line + 1, "update_weather", 14)) + { + PostMessageW(FindWindowW(_T(EPW_WEATHER_CLASSNAME), NULL), EP_WEATHER_WM_FETCH_DATA, 0, 0); + } } } dwMaxHeight += dwLineHeight * dy; @@ -1848,7 +1867,7 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) tabOrder++; } } - else if (!strncmp(line, ";l ", 3) || !strncmp(line, ";y ", 3) || !strncmp(line, ";c ", 3) || !strncmp(line, ";z ", 3) || !strncmp(line, ";b ", 3) || !strncmp(line, ";i ", 3) || !strncmp(line, ";d ", 3) || !strncmp(line, ";v ", 3)) + else if (!strncmp(line, ";l ", 3) || !strncmp(line, ";y ", 3) || !strncmp(line, ";c ", 3) || !strncmp(line, ";w ", 3) || !strncmp(line, ";z ", 3) || !strncmp(line, ";b ", 3) || !strncmp(line, ";i ", 3) || !strncmp(line, ";d ", 3) || !strncmp(line, ";v ", 3)) { ZeroMemory(text, (MAX_LINE_LENGTH + 3) * sizeof(wchar_t)); text[0] = L'\u2795'; @@ -1867,9 +1886,14 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) if (x) *x = 0; x = wcschr(text, L'\r'); if (x) *x = 0; - if (!strncmp(line, ";c ", 3) || !strncmp(line, ";z ", 3) || !strncmp(line, ";b ", 3) || !strncmp(line, ";i ", 3) || !strncmp(line, ";d ", 3) || !strncmp(line, ";v ", 3)) + if (!strncmp(line, ";w ", 3) || !strncmp(line, ";c ", 3) || !strncmp(line, ";z ", 3) || !strncmp(line, ";b ", 3) || !strncmp(line, ";i ", 3) || !strncmp(line, ";d ", 3) || !strncmp(line, ";v ", 3)) { + WCHAR* wszTitle = NULL; + WCHAR* wszPrompt = NULL; + WCHAR* wszDefault = NULL; + WCHAR* wszFallbackDefault = NULL; HMENU hMenu = NULL; + BOOL bInput = !strncmp(line, ";w ", 3); BOOL bChoice = !strncmp(line, ";c ", 3); BOOL bChoiceLefted = !strncmp(line, ";z ", 3); BOOL bInvert = !strncmp(line, ";i ", 3); @@ -1930,6 +1954,43 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) free(miText); } } + else if (bInput) + { + wszTitle = malloc(MAX_LINE_LENGTH * sizeof(WCHAR)); + wszPrompt = malloc(MAX_LINE_LENGTH * sizeof(WCHAR)); + wszDefault = malloc(MAX_LINE_LENGTH * sizeof(WCHAR)); + wszFallbackDefault = malloc(MAX_LINE_LENGTH * sizeof(WCHAR)); + char* l = malloc(MAX_LINE_LENGTH * sizeof(char)); + numChRd = getline(&l, &bufsiz, f); + char* p = l; + p = strchr(p + 1, '\r'); + if (p) *p = 0; + p = strchr(p + 1, '\n'); + if (p) *p = 0; + MultiByteToWideChar( + CP_UTF8, + MB_PRECOMPOSED, + l + 1, + numChRd - 1, + wszPrompt, + MAX_LINE_LENGTH + ); + numChRd = getline(&l, &bufsiz, f); + p = l; + p = strchr(p + 1, '\r'); + if (p) *p = 0; + p = strchr(p + 1, '\n'); + if (p) *p = 0; + MultiByteToWideChar( + CP_UTF8, + MB_PRECOMPOSED, + l + 1, + numChRd - 1, + wszFallbackDefault, + MAX_LINE_LENGTH + ); + free(l); + } numChRd = getline(&line, &bufsiz, f); if (!strncmp(line, ";\"Virtualized_" EP_CLSID, 52)) { @@ -2011,14 +2072,47 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) DWORD value = FALSE; //wprintf(L"%s %s %s\n", section, name, d + 1); - if (!wcsncmp(d + 1, L"dword:", 6)) + if (!bInput && !wcsncmp(d + 1, L"dword:", 6)) { wchar_t* x = wcschr(d + 1, L':'); x++; value = wcstol(x, NULL, 16); } + if (bInput) + { + wchar_t* x = wcschr(d + 2, L'"'); + x[0] = 0; + wcscpy_s(wszDefault, MAX_LINE_LENGTH, d + 2); + } - if (!bJustCheck) + if (bInput) + { + dwSize = MAX_LINE_LENGTH; + GUI_RegCreateKeyExW( + bIsHKLM ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + wcschr(section, L'\\') + 1, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | (hDC ? 0 : (!bIsHKLM ? KEY_WRITE : 0)), + NULL, + & hKey, + & dwDisposition + ); + if (hKey == NULL || hKey == INVALID_HANDLE_VALUE) + { + hKey = NULL; + } + GUI_RegQueryValueExW( + hKey, + name, + 0, + NULL, + wszDefault, + &dwSize + ); + } + else if (!bJustCheck) { GUI_RegCreateKeyExW( bIsHKLM ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, @@ -2067,7 +2161,28 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) } value = hKey; } - if (bInvert || bBool || bJustCheck) + if (bInput) + { + wcscpy_s(wszTitle, MAX_LINE_LENGTH, text + 3); + wcscat_s( + text, + MAX_LINE_LENGTH, + L" : " + ); + if (wszDefault[0] == 0) + { + wcscat_s(text, MAX_LINE_LENGTH, wszFallbackDefault); + } + else + { + wcscat_s( + text, + MAX_LINE_LENGTH, + wszDefault + ); + } + } + else if (bInvert || bBool || bJustCheck) { if (value) { @@ -2254,7 +2369,23 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) else { DWORD val = 0; - if (bChoice || bChoiceLefted) + if (bInput) + { + WCHAR* wszAnswer = malloc(MAX_LINE_LENGTH * sizeof(WCHAR)); + InputBox(FALSE, hwnd, wszPrompt, wszTitle, wszDefault, wszAnswer, MAX_LINE_LENGTH); + GUI_RegSetValueExW( + hKey, + name, + 0, + REG_SZ, + wszAnswer, + (wcslen(wszAnswer) + 1) * sizeof(WCHAR) + ); + Sleep(100); + PostMessageW(FindWindowW(_T(EPW_WEATHER_CLASSNAME), NULL), EP_WEATHER_WM_FETCH_DATA, 0, 0); + free(wszAnswer); + } + else if (bChoice || bChoiceLefted) { RECT rcTemp; rcTemp = rcText; @@ -2298,7 +2429,7 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) { value = _this->section + 1; } - if (!(bChoice || bChoiceLefted) || ((bChoice || bChoiceLefted) && val)) + if (!bInput && (!(bChoice || bChoiceLefted) || ((bChoice || bChoiceLefted) && val))) { GUI_RegSetValueExW( hKey, @@ -2332,6 +2463,22 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) } DestroyMenu(hMenu); } + if (wszTitle) + { + free(wszTitle); + } + if (wszPrompt) + { + free(wszPrompt); + } + if (wszDefault) + { + free(wszDefault); + } + if (wszFallbackDefault) + { + free(wszFallbackDefault); + } } if (hDC && (!strncmp(line, ";l ", 3) || !strncmp(line, ";y ", 3))) { @@ -2477,6 +2624,7 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) if (text[0] == L'\u2714') dwType = 1; else if (text[0] == L'\u274C') dwType = 2; else if (text[accLen - 1] == 56405) dwType = 3; + else if (!strstr(line, "dword")) dwType = 5; WCHAR accText[1000], accText2[1000]; ZeroMemory(accText, 1000 * sizeof(wchar_t)); ZeroMemory(accText2, 1000 * sizeof(wchar_t)); @@ -2494,7 +2642,8 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) (dwType == 2 ? L"Disabled" : (dwType == 3 ? L"Link" : (dwType == 4 ? L"Button" : - L"List"))) + (dwType == 5 ? L"Input" : + L"List")))) ); accLen = wcslen(accText); unsigned int j = 0; @@ -2935,10 +3084,10 @@ static LRESULT CALLBACK GUI_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR return 0; } // this should be determined from the file, but for now it works - else if (wParam >= '1' && wParam <= '9') + else if (wParam >= '1' && wParam <= '9' || wParam == '0') { _this->tabOrder = 0; - GUI_SetSection(_this, TRUE, wParam - '1'); + GUI_SetSection(_this, TRUE, wParam == '0' ? 9 : wParam - '1'); _this->bShouldAnnounceSelected = TRUE; InvalidateRect(hWnd, NULL, FALSE); return 0; @@ -2983,6 +3132,14 @@ static LRESULT CALLBACK GUI_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR SetTimer(hWnd, GUI_TIMER_READ_HELP, 200, NULL); return 0; } + else if (wParam == 'Z') + { + return 0; + } + else if (wParam == 'X') + { + return 0; + } } else if (uMsg == WM_NCMOUSELEAVE && IsThemeActive()) { @@ -3187,7 +3344,7 @@ __declspec(dllexport) int ZZGUI(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLin return 0; } - HRESULT hr = CoInitialize(0); + HRESULT hr = CoInitializeEx(0, COINIT_APARTMENTTHREADED); HKEY hKey = NULL; DWORD dwSize = sizeof(DWORD); diff --git a/ExplorerPatcher/GUI.h b/ExplorerPatcher/GUI.h index 4768fb0..c4e8ae1 100644 --- a/ExplorerPatcher/GUI.h +++ b/ExplorerPatcher/GUI.h @@ -24,6 +24,7 @@ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #include "getline.h" #include "fmemopen.h" #include "utility.h" +#include "../ep_weather_host/ep_weather.h" #define MAX_LINE_LENGTH 2000 extern HMODULE hModule; diff --git a/ExplorerPatcher/StartMenu.c b/ExplorerPatcher/StartMenu.c index c562fae..c4c153b 100644 --- a/ExplorerPatcher/StartMenu.c +++ b/ExplorerPatcher/StartMenu.c @@ -77,6 +77,7 @@ LRESULT CALLBACK OpenStartOnCurentMonitorThreadHook( MSG* msg = (MSG*)lParam; if (GetSystemMetrics(SM_CMONITORS) >= 2 && msg->message == WM_SYSCOMMAND && (msg->wParam & 0xFFF0) == SC_TASKLIST) { + printf("Position Start\n"); if (bMonitorOverride) { goto finish; @@ -102,6 +103,7 @@ LRESULT CALLBACK OpenStartOnCurentMonitorThreadHook( POINT pt; pt.x = GET_X_LPARAM(pts); pt.y = GET_Y_LPARAM(pts); + printf("!! %d %d\n", pt.x, pt.y); HMONITOR monitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONULL @@ -131,12 +133,7 @@ DWORD OpenStartOnCurentMonitorThread(OpenStartOnCurentMonitorThreadParams* unuse HWND g_ProgWin = NULL; while (!g_ProgWin) { - g_ProgWin = FindWindowEx( - NULL, - NULL, - L"Progman", - NULL - ); + g_ProgWin = GetShellWindow(); if (!g_ProgWin) { Sleep(100); diff --git a/ExplorerPatcher/dllmain.c b/ExplorerPatcher/dllmain.c index 1b341d6..7346e43 100644 --- a/ExplorerPatcher/dllmain.c +++ b/ExplorerPatcher/dllmain.c @@ -31,6 +31,11 @@ #endif #include #include +#include "../ep_weather_host/ep_weather.h" +#ifdef _WIN64 +#include "../ep_weather_host/ep_weather_host_h.h" +IEPWeather* epw = NULL; +#endif #define WINX_ADJUST_X 5 #define WINX_ADJUST_Y 5 @@ -99,6 +104,13 @@ BYTE* lpShouldDisplayCCButton = NULL; HMONITOR hMonitorList[MAX_NUM_MONITORS]; DWORD dwMonitorCount = 0; HANDLE hCanStartSws = NULL; +DWORD dwWeatherViewMode = EP_WEATHER_VIEW_ICONTEXT; +DWORD dwWeatherTemperatureUnit = EP_WEATHER_TUNIT_CELSIUS; +DWORD dwWeatherUpdateSchedule = EP_WEATHER_UPDATE_NORMAL; +WCHAR* wszWeatherTerm = NULL; +WCHAR* wszWeatherLanguage = NULL; +WCHAR* wszEPWeatherKillswitch = NULL; +HANDLE hEPWeatherKillswitch = NULL; int Code = 0; HRESULT InjectStartFromExplorer(); void InvokeClockFlyout(); @@ -3552,10 +3564,639 @@ HRESULT WINAPI Widgets_GetTooltipTextHook(__int64 a1, __int64 a2, __int64 a3, WC } } +/*int WINAPI explorer_LoadStringWHook(HINSTANCE hInstance, UINT uID, WCHAR* lpBuffer, UINT cchBufferMax) +{ + WCHAR wszBuffer[MAX_PATH]; + if (hInstance == GetModuleHandle(NULL) && uID == 912)// && SUCCEEDED(epw->lpVtbl->GetTitle(epw, MAX_PATH, wszBuffer))) + { + //sws_error_PrintStackTrace(); + int rez = LoadStringW(hInstance, uID, lpBuffer, cchBufferMax); + //wprintf(L"%s\n", lpBuffer); + return rez; + } + else + { + return LoadStringW(hInstance, uID, lpBuffer, cchBufferMax); + } +}*/ + void stub1(void* i) { } +HWND PeopleButton_LastHWND = NULL; + +BOOL explorer_DeleteMenu(HMENU hMenu, UINT uPosition, UINT uFlags) +{ + if (uPosition == 621 && uFlags == 0) // when removing News and interests + { + DeleteMenu(hMenu, 449, 0); // remove Cortana menu + DeleteMenu(hMenu, 435, 0); // remove People menu + } + return DeleteMenu(hMenu, uPosition, uFlags); +} + +SIZE (*PeopleButton_CalculateMinimumSizeFunc)(void*, SIZE*); +SIZE WINAPI PeopleButton_CalculateMinimumSizeHook(void* _this, SIZE* pSz) +{ + SIZE ret = PeopleButton_CalculateMinimumSizeFunc(_this, pSz); + int mul = 1; + if (epw) + { + switch (dwWeatherViewMode) + { + case EP_WEATHER_VIEW_ICONTEXT: + mul = 4; + break; + case EP_WEATHER_VIEW_ICONTEMP: + mul = 2; + break; + case EP_WEATHER_VIEW_ICONONLY: + mul = 1; + break; + } + } + //printf(">> %d %d\n", pSz->cx, pSz->cy); + pSz->cx = pSz->cx * mul; + if (pSz->cy && epw) + { + BOOL bIsInitialized = TRUE; + HRESULT hr = epw->lpVtbl->IsInitialized(epw, &bIsInitialized); + if (SUCCEEDED(hr)) + { + int rt = MulDiv(48, pSz->cy, 60); + if (!bIsInitialized) + { + epw->lpVtbl->SetTerm(epw, MAX_PATH * sizeof(WCHAR), wszWeatherTerm); + epw->lpVtbl->SetLanguage(epw, MAX_PATH * sizeof(WCHAR), wszWeatherLanguage); + if (FAILED(epw->lpVtbl->Initialize(epw, wszEPWeatherKillswitch, bAllocConsole, EP_WEATHER_PROVIDER_GOOGLE, rt, rt, dwWeatherTemperatureUnit, dwWeatherUpdateSchedule * 1000, pSz->cy / 48.0))) + { + epw->lpVtbl->Release(epw); + } + } + else + { + epw->lpVtbl->SetIconSize(epw, rt, rt); + } + } + else + { + if (hr == 0x800706ba) // RPC server is unavailable + { + epw = NULL; + InvalidateRect(PeopleButton_LastHWND, NULL, TRUE); + } + } + } + return ret; +} + +int PeopleBand_MulDivHook(int nNumber, int nNumerator, int nDenominator) +{ + //printf("<< %d %d %d\n", nNumber, nNumerator, nDenominator); + int mul = 1; + if (epw) + { + switch (dwWeatherViewMode) + { + case EP_WEATHER_VIEW_ICONTEXT: + mul = 4; + break; + case EP_WEATHER_VIEW_ICONTEMP: + mul = 2; + break; + case EP_WEATHER_VIEW_ICONONLY: + mul = 1; + break; + } + } + return MulDiv(nNumber * mul, nNumerator, nDenominator); +} + +DWORD epw_cbTemperature = 0; +DWORD epw_cbUnit = 0; +DWORD epw_cbCondition = 0; +DWORD epw_cbImage = 0; +WCHAR* epw_wszTemperature = NULL; +WCHAR* epw_wszUnit = NULL; +WCHAR* epw_wszCondition = NULL; +char* epw_pImage = NULL; +__int64 (*PeopleBand_DrawTextWithGlowFunc)( + HDC hdc, + const unsigned __int16* a2, + int a3, + struct tagRECT* a4, + unsigned int a5, + unsigned int a6, + unsigned int a7, + unsigned int dy, + unsigned int a9, + int a10, + int(__stdcall* a11)(HDC, unsigned __int16*, int, struct tagRECT*, unsigned int, __int64), + __int64 a12); +__int64 __fastcall PeopleBand_DrawTextWithGlowHook( + HDC hdc, + const unsigned __int16* a2, + int a3, + struct tagRECT* a4, + unsigned int a5, + unsigned int a6, + unsigned int a7, + unsigned int dy, + unsigned int a9, + int a10, + int(__stdcall* a11)(HDC, unsigned __int16*, int, struct tagRECT*, unsigned int, __int64), + __int64 a12) +{ + if (a5 == 0x21 && epw) + { + BOOL bUseCachedData = InSendMessage(); + HRESULT hr = S_OK; + if (bUseCachedData ? TRUE : SUCCEEDED(hr = epw->lpVtbl->LockData(epw))) + { + UINT dpiX = 0, dpiY = 0; + HRESULT hr = GetDpiForMonitor(MonitorFromWindow(PeopleButton_LastHWND, MONITOR_DEFAULTTOPRIMARY), MDT_DEFAULT, &dpiX, &dpiY); + BOOL bShouldUnlockData = TRUE; + DWORD cbTemperature = 0; + DWORD cbUnit = 0; + DWORD cbCondition = 0; + DWORD cbImage = 0; + BOOL bEmptyData = FALSE; + if (bUseCachedData ? TRUE : SUCCEEDED(hr = epw->lpVtbl->GetDataSizes(epw, &cbTemperature, &cbUnit, &cbCondition, &cbImage))) + { + if (cbTemperature && cbUnit && cbCondition && cbImage) + { + epw_cbTemperature = cbTemperature; + epw_cbUnit = cbUnit; + epw_cbCondition = cbCondition; + epw_cbImage = cbImage; + } + else + { + if (!bUseCachedData) + { + bEmptyData = TRUE; + if (bShouldUnlockData) + { + epw->lpVtbl->UnlockData(epw); + bShouldUnlockData = FALSE; + } + } + else + { + bEmptyData = !epw_wszTemperature || !epw_wszUnit || !epw_wszCondition; + } + bUseCachedData = TRUE; + } + if (!bUseCachedData) + { + if (epw_wszTemperature) + { + free(epw_wszTemperature); + } + epw_wszTemperature = calloc(1, epw_cbTemperature); + if (epw_wszUnit) + { + free(epw_wszUnit); + } + epw_wszUnit = calloc(1, epw_cbUnit); + if (epw_wszCondition) + { + free(epw_wszCondition); + } + epw_wszCondition = calloc(1, epw_cbCondition); + if (epw_pImage) + { + free(epw_pImage); + } + epw_pImage = calloc(1, epw_cbImage); + } + if (bUseCachedData ? TRUE : SUCCEEDED(hr = epw->lpVtbl->GetData(epw, epw_cbTemperature, epw_wszTemperature, epw_cbUnit, epw_wszUnit, epw_cbCondition, epw_wszCondition, epw_cbImage, epw_pImage))) + { + if (!bUseCachedData) + { + epw->lpVtbl->UnlockData(epw); + bShouldUnlockData = FALSE; + } + + LOGFONTW logFont; + ZeroMemory(&logFont, sizeof(logFont)); + NONCLIENTMETRICS ncm; + ZeroMemory(&ncm, sizeof(NONCLIENTMETRICS)); + ncm.cbSize = sizeof(NONCLIENTMETRICS); + SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0); + logFont = ncm.lfCaptionFont; + logFont.lfHeight = -14 * (dpiX / 96.0); + if (bEmptyData) + { + DWORD dwVal = 1, dwSize = sizeof(DWORD); + RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", L"TaskbarSmallIcons", RRF_RT_DWORD, NULL, &dwVal, &dwSize); + if (!dwVal) + { + logFont.lfHeight *= 1.6; + } + } + else + { + if (dwWeatherViewMode == EP_WEATHER_VIEW_ICONTEXT) + { + //logFont.lfHeight = -12 * (dpiX / 96.0); + } + } + HFONT hFont = CreateFontIndirectW(&logFont); + if (hFont) + { + HDC hDC = CreateCompatibleDC(0); + if (hDC) + { + COLORREF rgbColor = RGB(0, 0, 0); + if (ShouldSystemUseDarkMode && ShouldSystemUseDarkMode()) + { + rgbColor = RGB(255, 255, 255); + } + HFONT hOldFont = SelectFont(hDC, hFont); + if (bEmptyData) + { + RECT rcText; + SetRect(&rcText, 0, 0, a4->right, a4->bottom); + SIZE size; + size.cx = rcText.right - rcText.left; + size.cy = rcText.bottom - rcText.top; + DWORD dwTextFlags = DT_SINGLELINE | DT_VCENTER | DT_HIDEPREFIX | DT_CENTER; + HBITMAP hBitmap = sws_WindowHelpers_CreateAlphaTextBitmap(L"\U0001f4f0", hFont, dwTextFlags, size, rgbColor); + if (hBitmap) + { + HBITMAP hOldBMP = SelectBitmap(hDC, hBitmap); + BITMAP BMInf; + GetObjectW(hBitmap, sizeof(BITMAP), &BMInf); + + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 0xFF; + bf.AlphaFormat = AC_SRC_ALPHA; + GdiAlphaBlend(hdc, 0, 0, BMInf.bmWidth, BMInf.bmHeight, hDC, 0, 0, BMInf.bmWidth, BMInf.bmHeight, bf); + + SelectBitmap(hDC, hOldBMP); + DeleteBitmap(hBitmap); + } + } + else + { + DWORD dwTextFlags = DT_SINGLELINE | DT_VCENTER | DT_HIDEPREFIX; + + WCHAR wszText1[MAX_PATH]; + swprintf_s(wszText1, MAX_PATH, L"%s %s", epw_wszTemperature, dwWeatherTemperatureUnit == EP_WEATHER_TUNIT_FAHRENHEIT ? L"\u00B0F" : L"\u00B0C");// epw_wszUnit); + RECT rcText1; + SetRect(&rcText1, 0, 0, a4->right, a4->bottom); + DrawTextW(hDC, wszText1, -1, &rcText1, dwTextFlags | DT_CALCRECT); + rcText1.bottom = a4->bottom; + WCHAR wszText2[MAX_PATH]; + swprintf_s(wszText2, MAX_PATH, L"%s", epw_wszCondition); + RECT rcText2; + SetRect(&rcText2, 0, 0, a4->right, a4->bottom); + DrawTextW(hDC, wszText2, -1, &rcText2, dwTextFlags | DT_CALCRECT); + rcText2.bottom = a4->bottom; + + dwTextFlags |= DT_END_ELLIPSIS; + + int addend = 0; + //int rt = MulDiv(48, a4->bottom, 60); + int rt = sqrt(epw_cbImage / 4); + int p = 0;// MulDiv(rt, 4, 64); + int margin_h = MulDiv(12, dpiX, 144); + + switch (dwWeatherViewMode) + { + case EP_WEATHER_VIEW_ICONTEXT: + addend = (rcText1.right - rcText1.left) + margin_h + (rcText2.right - rcText2.left) + margin_h; + break; + case EP_WEATHER_VIEW_ICONTEMP: + addend = (rcText1.right - rcText1.left) + margin_h; + break; + case EP_WEATHER_VIEW_ICONONLY: + addend = 0; + break; + } + int margin_v = (a4->bottom - rt) / 2; + int total_h = (margin_h - p) + rt + (margin_h - p) + addend; + if (total_h > a4->right) + { + int diff = total_h - a4->right; + rcText2.right -= diff - 2; + switch (dwWeatherViewMode) + { + case EP_WEATHER_VIEW_ICONTEXT: + addend = (rcText1.right - rcText1.left) + margin_h + (rcText2.right - rcText2.left) + margin_h; + break; + case EP_WEATHER_VIEW_ICONTEMP: + addend = (rcText1.right - rcText1.left) + margin_h; + break; + case EP_WEATHER_VIEW_ICONONLY: + addend = 0; + break; + } + total_h = (margin_h - p) + rt + (margin_h - p) + addend; + } + + int start_x = (a4->right - total_h) / 2; + + HBITMAP hBitmap = NULL, hOldBitmap = NULL; + void* pvBits = NULL; + SIZE size; + + BITMAPINFOHEADER BMIH; + ZeroMemory(&BMIH, sizeof(BITMAPINFOHEADER)); + BMIH.biSize = sizeof(BITMAPINFOHEADER); + BMIH.biWidth = rt; + BMIH.biHeight = -rt; + BMIH.biPlanes = 1; + BMIH.biBitCount = 32; + BMIH.biCompression = BI_RGB; + hBitmap = CreateDIBSection(hDC, &BMIH, 0, &pvBits, NULL, 0); + if (hBitmap) + { + memcpy(pvBits, epw_pImage, epw_cbImage); + hOldBitmap = SelectBitmap(hDC, hBitmap); + + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 0xFF; + bf.AlphaFormat = AC_SRC_ALPHA; + GdiAlphaBlend(hdc, start_x + (margin_h - p), margin_v, rt, rt, hDC, 0, 0, rt, rt, bf); + + SelectBitmap(hDC, hOldBitmap); + DeleteBitmap(hBitmap); + } + + if (dwWeatherViewMode == EP_WEATHER_VIEW_ICONTEMP || dwWeatherViewMode == EP_WEATHER_VIEW_ICONTEXT) + { + size.cx = rcText1.right - rcText1.left; + size.cy = rcText1.bottom - rcText1.top; + hBitmap = sws_WindowHelpers_CreateAlphaTextBitmap(wszText1, hFont, dwTextFlags, size, rgbColor); + if (hBitmap) + { + HBITMAP hOldBMP = SelectBitmap(hDC, hBitmap); + BITMAP BMInf; + GetObjectW(hBitmap, sizeof(BITMAP), &BMInf); + + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 0xFF; + bf.AlphaFormat = AC_SRC_ALPHA; + GdiAlphaBlend(hdc, start_x + (margin_h - p) + rt + (margin_h - p), 0, BMInf.bmWidth, BMInf.bmHeight, hDC, 0, 0, BMInf.bmWidth, BMInf.bmHeight, bf); + + SelectBitmap(hDC, hOldBMP); + DeleteBitmap(hBitmap); + } + } + + if (dwWeatherViewMode == EP_WEATHER_VIEW_ICONTEXT) + { + size.cx = rcText2.right - rcText2.left; + size.cy = rcText2.bottom - rcText2.top; + hBitmap = sws_WindowHelpers_CreateAlphaTextBitmap(wszText2, hFont, dwTextFlags, size, rgbColor); + if (hBitmap) + { + HBITMAP hOldBMP = SelectBitmap(hDC, hBitmap); + BITMAP BMInf; + GetObjectW(hBitmap, sizeof(BITMAP), &BMInf); + + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 0xFF; + bf.AlphaFormat = AC_SRC_ALPHA; + GdiAlphaBlend(hdc, start_x + (margin_h - p) + rt + (margin_h - p) + (rcText1.right - rcText1.left) + margin_h, 0, BMInf.bmWidth, BMInf.bmHeight, hDC, 0, 0, BMInf.bmWidth, BMInf.bmHeight, bf); + + SelectBitmap(hDC, hOldBMP); + DeleteBitmap(hBitmap); + } + } + } + SelectFont(hDC, hOldFont); + DeleteDC(hDC); + } + } + } + /*free(epw_pImage); + free(epw_wszCondition); + free(epw_wszUnit); + free(epw_wszTemperature);*/ + } + if (!bUseCachedData && bShouldUnlockData) + { + epw->lpVtbl->UnlockData(epw); + } + } + else + { + //printf("444444444444 0x%x\n", hr); + if (hr == 0x800706ba) // RPC server is unavailable + { + epw = NULL; + InvalidateRect(PeopleButton_LastHWND, NULL, TRUE); + } + } + + //printf("hr %x\n", hr); + + return S_OK; + } + else + { + return PeopleBand_DrawTextWithGlowFunc(hdc, a2, a3, a4, a5, a6, a7, dy, a9, a10, a11, a12); + } +} + +void(*PeopleButton_ShowTooltipFunc)(__int64 a1, unsigned __int8 bShow) = 0; +void WINAPI PeopleButton_ShowTooltipHook(__int64 _this, unsigned __int8 bShow) +{ + if (epw) + { + if (bShow) + { + HRESULT hr = epw->lpVtbl->LockData(epw); + if (SUCCEEDED(hr)) + { + WCHAR wszBuffer[MAX_PATH]; + ZeroMemory(wszBuffer, sizeof(WCHAR) * MAX_PATH); + epw->lpVtbl->GetTitle(epw, sizeof(WCHAR) * MAX_PATH, wszBuffer, dwWeatherViewMode); + if (wcsstr(wszBuffer, L"(null)")) + { + HMODULE hModule = GetModuleHandleW(L"pnidui.dll"); + if (hModule) + { + LoadStringW(hModule, 35, wszBuffer, MAX_PATH); + } + } + TTTOOLINFOW ti; + ZeroMemory(&ti, sizeof(TTTOOLINFOW)); + ti.cbSize = sizeof(TTTOOLINFOW); + ti.hwnd = *((INT64*)_this + 1); + ti.uId = *((INT64*)_this + 1); + ti.lpszText = wszBuffer; + SendMessageW((HWND) * ((INT64*)_this + 10), TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti); + epw->lpVtbl->UnlockData(epw); + } + } + } + else + { + WCHAR wszBuffer[MAX_PATH]; + ZeroMemory(wszBuffer, sizeof(WCHAR) * MAX_PATH); + LoadStringW(GetModuleHandle(NULL), 912, wszBuffer, MAX_PATH); + if (wszBuffer[0]) + { + TTTOOLINFOW ti; + ZeroMemory(&ti, sizeof(TTTOOLINFOW)); + ti.cbSize = sizeof(TTTOOLINFOW); + ti.hwnd = *((INT64*)_this + 1); + ti.uId = *((INT64*)_this + 1); + ti.lpszText = wszBuffer; + SendMessageW((HWND) * ((INT64*)_this + 10), TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti); + } + } + if (PeopleButton_ShowTooltipFunc) + { + return PeopleButton_ShowTooltipFunc(_this, bShow); + } + return 0; +} + +__int64 (*PeopleButton_OnClickFunc)(__int64 a1, __int64 a2) = 0; +__int64 PeopleButton_OnClickHook(__int64 a1, __int64 a2) +{ + if (epw) + { + HWND hWnd = NULL; + if (SUCCEEDED(epw->lpVtbl->GetWindowHandle(epw, &hWnd)) && hWnd) + { + if (IsWindowVisible(hWnd)) + { + if (GetForegroundWindow() != hWnd) + { + SwitchToThisWindow(hWnd, TRUE); + } + else + { + epw->lpVtbl->Hide(epw); + //printf("HR %x\n", PostMessageW(hWnd, EP_WEATHER_WM_FETCH_DATA, 0, 0)); + } + } + else + { + RECT rcButton; + GetWindowRect(PeopleButton_LastHWND, &rcButton); + POINT pButton; + pButton.x = rcButton.left; + pButton.y = rcButton.top; + + RECT rcWindow; + GetWindowRect(hWnd, &rcWindow); + + POINT pNewWindow; + + RECT rc; + UINT tbPos = GetTaskbarLocationAndSize(pButton, &rc); + if (tbPos == TB_POS_BOTTOM) + { + pNewWindow.y = rcButton.top - (rcWindow.bottom - rcWindow.top); + } + else if (tbPos == TB_POS_TOP) + { + pNewWindow.y = rcButton.bottom; + } + else if (tbPos == TB_POS_LEFT) + { + pNewWindow.x = rcButton.right; + } + if (tbPos == TB_POS_RIGHT) + { + pNewWindow.x = rcButton.left - (rcWindow.right - rcWindow.left); + } + + if (tbPos == TB_POS_BOTTOM || tbPos == TB_POS_TOP) + { + pNewWindow.x = rcButton.left + ((rcButton.right - rcButton.left) / 2) - ((rcWindow.right - rcWindow.left) / 2); + + HMONITOR hMonitor = MonitorFromPoint(pButton, MONITOR_DEFAULTTOPRIMARY); + if (hMonitor) + { + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + if (GetMonitorInfoW(hMonitor, &mi)) + { + if (mi.rcWork.right < pNewWindow.x + (rcWindow.right - rcWindow.left)) + { + pNewWindow.x = mi.rcWork.right - (rcWindow.right - rcWindow.left); + } + } + } + } + else if (tbPos == TB_POS_LEFT || tbPos == TB_POS_RIGHT) + { + pNewWindow.y = rcButton.top + ((rcButton.bottom - rcButton.top) / 2) - ((rcWindow.bottom - rcWindow.top) / 2); + + HMONITOR hMonitor = MonitorFromPoint(pButton, MONITOR_DEFAULTTOPRIMARY); + if (hMonitor) + { + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + if (GetMonitorInfoW(hMonitor, &mi)) + { + if (mi.rcWork.bottom < pNewWindow.y + (rcWindow.bottom - rcWindow.top)) + { + pNewWindow.y = mi.rcWork.bottom - (rcWindow.bottom - rcWindow.top); + } + } + } + } + + SetWindowPos(hWnd, NULL, pNewWindow.x, pNewWindow.y, 0, 0, SWP_NOSIZE, SWP_SHOWWINDOW | SWP_FRAMECHANGED); + + epw->lpVtbl->Show(epw); + + SwitchToThisWindow(hWnd, TRUE); + } + } + return 0; + } + else + { + if (PeopleButton_OnClickFunc) + { + return PeopleButton_OnClickFunc(a1, a2); + } + return 0; + } +} + +INT64 PeopleButton_SubclassProc( + _In_ HWND hWnd, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam, + UINT_PTR uIdSubclass, + DWORD_PTR dwRefData +) +{ + if (uMsg == WM_NCDESTROY) + { + RemoveWindowSubclass(hWnd, PeopleButton_SubclassProc, PeopleButton_SubclassProc); + if (epw) + { + epw->lpVtbl->Release(epw); + epw = NULL; + PeopleButton_LastHWND = NULL; + } + } + return DefSubclassProc(hWnd, uMsg, wParam, lParam); +} + + static BOOL(*SetChildWindowNoActivateFunc)(HWND); BOOL explorer_SetChildWindowNoActivateHook(HWND hWnd) { @@ -3597,13 +4238,38 @@ BOOL explorer_SetChildWindowNoActivateHook(HWND hWnd) *(uintptr_t*)(Instance + 160) = ToggleTaskView; // OnClick VirtualProtect(Instance + 160, sizeof(uintptr_t), dwOldProtect, &dwOldProtect); } - /*else if (!wcscmp(wszComponentName, L"PeopleButton")) + else if (!wcscmp(wszComponentName, L"PeopleButton")) { DWORD dwOldProtect; + + uintptr_t PeopleButton_Instance = *((uintptr_t*)GetWindowLongPtrW(hWnd, 0) + 17); + + VirtualProtect(PeopleButton_Instance + 32, sizeof(uintptr_t), PAGE_READWRITE, &dwOldProtect); + if (!PeopleButton_CalculateMinimumSizeFunc) PeopleButton_CalculateMinimumSizeFunc = *(uintptr_t*)(PeopleButton_Instance + 32); + *(uintptr_t*)(PeopleButton_Instance + 32) = PeopleButton_CalculateMinimumSizeHook; // CalculateMinimumSize + VirtualProtect(PeopleButton_Instance + 32, sizeof(uintptr_t), dwOldProtect, &dwOldProtect); + + VirtualProtect(Instance + 224, sizeof(uintptr_t), PAGE_READWRITE, &dwOldProtect); + if (!PeopleButton_ShowTooltipFunc) PeopleButton_ShowTooltipFunc = *(uintptr_t*)(Instance + 224); + *(uintptr_t*)(Instance + 224) = PeopleButton_ShowTooltipHook; // OnTooltipShow + VirtualProtect(Instance + 224, sizeof(uintptr_t), dwOldProtect, &dwOldProtect); + VirtualProtect(Instance + 160, sizeof(uintptr_t), PAGE_READWRITE, &dwOldProtect); - *(uintptr_t*)(Instance + 160) = ToggleMainClockFlyout; // OnClick + if (!PeopleButton_OnClickFunc) PeopleButton_OnClickFunc = *(uintptr_t*)(Instance + 160); + *(uintptr_t*)(Instance + 160) = PeopleButton_OnClickHook; // OnClick VirtualProtect(Instance + 160, sizeof(uintptr_t), dwOldProtect, &dwOldProtect); - }*/ + + PeopleButton_LastHWND = hWnd; + SetWindowSubclass(hWnd, PeopleButton_SubclassProc, PeopleButton_SubclassProc, 0); + + if (!epw) + { + if (SUCCEEDED(CoCreateInstance(&CLSID_EPWeather, NULL, CLSCTX_LOCAL_SERVER, &IID_IEPWeather, &epw)) && epw) + { + epw->lpVtbl->SetNotifyWindow(epw, hWnd); + } + } + } } } return SetChildWindowNoActivateFunc(hWnd); @@ -4568,6 +5234,108 @@ void WINAPI LoadSettings(LPARAM lParam) &bDisableOfficeHotkeys, &dwSize ); + +#ifdef _WIN64 + DWORD dwOldWeatherTemperatureUnit = dwWeatherTemperatureUnit; + dwSize = sizeof(DWORD); + RegQueryValueExW( + hKey, + TEXT("WeatherTemperatureUnit"), + 0, + NULL, + &dwWeatherTemperatureUnit, + &dwSize + ); + if (dwWeatherTemperatureUnit != dwOldWeatherTemperatureUnit && epw) + { + epw->lpVtbl->SetTemperatureUnit(epw, dwWeatherTemperatureUnit); + HWND hWnd = NULL; + if (SUCCEEDED(epw->lpVtbl->GetWindowHandle(epw, &hWnd)) && hWnd) + { + SendMessageW(hWnd, EP_WEATHER_WM_FETCH_DATA, 0, 0); + } + } + + DWORD dwOldWeatherViewMode = dwWeatherViewMode; + dwSize = sizeof(DWORD); + RegQueryValueExW( + hKey, + TEXT("WeatherViewMode"), + 0, + NULL, + &dwWeatherViewMode, + &dwSize + ); + if (dwWeatherViewMode != dwOldWeatherViewMode && PeopleButton_LastHWND) + { + ToggleTaskbarAutohide(); + ToggleTaskbarAutohide(); + InvalidateRect(PeopleButton_LastHWND, NULL, TRUE); + } + + DWORD dwOldUpdateSchedule = dwWeatherUpdateSchedule; + dwSize = sizeof(DWORD); + RegQueryValueExW( + hKey, + TEXT("WeatherContentUpdateMode"), + 0, + NULL, + &dwWeatherUpdateSchedule, + &dwSize + ); + if (dwWeatherUpdateSchedule != dwOldUpdateSchedule && epw) + { + epw->lpVtbl->SetUpdateSchedule(epw, dwWeatherUpdateSchedule * 1000); + } + + dwSize = MAX_PATH * sizeof(WCHAR); + if (RegQueryValueExW( + hKey, + TEXT("WeatherLocation"), + 0, + NULL, + wszWeatherTerm, + &dwSize + )) + { + wcscpy_s(wszWeatherTerm, MAX_PATH, L""); + } + else + { + if (wszWeatherTerm[0] == 0) + { + wcscpy_s(wszWeatherTerm, MAX_PATH, L""); + } + } + if (epw) + { + epw->lpVtbl->SetTerm(epw, MAX_PATH * sizeof(WCHAR), wszWeatherTerm); + } + dwSize = MAX_PATH * sizeof(WCHAR); + if (RegQueryValueExW( + hKey, + TEXT("WeatherLanguage"), + 0, + NULL, + wszWeatherLanguage, + &dwSize + )) + { + wcscpy_s(wszWeatherLanguage, MAX_PATH, L"en"); + } + else + { + if (wszWeatherLanguage[0] == 0) + { + wcscpy_s(wszWeatherLanguage, MAX_PATH, L"en"); + } + } + if (epw) + { + epw->lpVtbl->SetLanguage(epw, MAX_PATH * sizeof(WCHAR), wszWeatherLanguage); + } +#endif + dwTemp = TASKBARGLOMLEVEL_DEFAULT; dwSize = sizeof(DWORD); RegQueryValueExW( @@ -6534,6 +7302,12 @@ DWORD Inject(BOOL bIsExplorer) int rv; + if (bIsExplorer) + { + wszWeatherLanguage = malloc(sizeof(WCHAR) * MAX_PATH); + wszWeatherTerm = malloc(sizeof(WCHAR) * MAX_PATH); + } + LoadSettings(MAKELPARAM(bIsExplorer, FALSE)); #ifdef _WIN64 @@ -6724,6 +7498,13 @@ DWORD Inject(BOOL bIsExplorer) return; } + + wszEPWeatherKillswitch = calloc(sizeof(WCHAR), MAX_PATH); + rand_string(wszEPWeatherKillswitch, MAX_PATH / 2); + wcscat_s(wszEPWeatherKillswitch, MAX_PATH, _T(EP_Weather_Killswitch)); + hEPWeatherKillswitch = CreateMutexW(NULL, TRUE, wszEPWeatherKillswitch); + + #ifdef _WIN64 hCanStartSws = CreateEventW(NULL, FALSE, FALSE, NULL); hWin11AltTabInitialized = CreateEventW(NULL, FALSE, FALSE, NULL); @@ -6798,6 +7579,7 @@ DWORD Inject(BOOL bIsExplorer) VnPatchIAT(hExplorer, "uxtheme.dll", "OpenThemeDataForDpi", explorer_OpenThemeDataForDpi); VnPatchIAT(hExplorer, "uxtheme.dll", "DrawThemeBackground", explorer_DrawThemeBackground); VnPatchIAT(hExplorer, "uxtheme.dll", "CloseThemeData", explorer_CloseThemeData); + //VnPatchIAT(hExplorer, "api-ms-win-core-libraryloader-l1-2-0.dll", "LoadStringW", explorer_LoadStringWHook); if (bClassicThemeMitigations) { /*explorer_SetWindowThemeFunc = SetWindowTheme; @@ -6827,6 +7609,10 @@ DWORD Inject(BOOL bIsExplorer) { VnPatchIAT(hExplorer, "API-MS-WIN-NTUSER-RECTANGLE-L1-1-0.DLL", "SetRect", explorer_SetRect); } + if (bOldTaskbar) + { + VnPatchIAT(hExplorer, "USER32.DLL", "DeleteMenu", explorer_DeleteMenu); + } #ifdef USE_PRIVATE_INTERFACES @@ -6870,7 +7656,13 @@ DWORD Inject(BOOL bIsExplorer) SetPreferredAppMode = GetProcAddress(hUxtheme, (LPCSTR)0x87); AllowDarkModeForWindow = GetProcAddress(hUxtheme, (LPCSTR)0x85); ShouldAppsUseDarkMode = GetProcAddress(hUxtheme, (LPCSTR)0x84); + ShouldSystemUseDarkMode = GetProcAddress(hUxtheme, (LPCSTR)0x8A); GetThemeName = GetProcAddress(hUxtheme, (LPCSTR)0x4A); + PeopleBand_DrawTextWithGlowFunc = GetProcAddress(hUxtheme, (LPCSTR)0x7E); + if (bOldTaskbar) + { + VnPatchIAT(hExplorer, "uxtheme.dll", (LPCSTR)0x7E, PeopleBand_DrawTextWithGlowHook); + } printf("Setup uxtheme functions done\n"); @@ -7067,6 +7859,16 @@ DWORD Inject(BOOL bIsExplorer) + HANDLE hPeopleBand = LoadLibraryW(L"PeopleBand.dll"); + if (hPeopleBand) + { + VnPatchIAT(hPeopleBand, "api-ms-win-core-largeinteger-l1-1-0.dll", "MulDiv", PeopleBand_MulDivHook); + printf("Setup peopleband functions done\n"); + } + + + + rv = funchook_install(funchook, 0); if (rv != 0) { diff --git a/ExplorerPatcher/fmemopen.c b/ExplorerPatcher/fmemopen.c index 6fbd02b..b3cb144 100644 --- a/ExplorerPatcher/fmemopen.c +++ b/ExplorerPatcher/fmemopen.c @@ -1,67 +1,49 @@ -/*- - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: +/* + * Copyright (c) 2017 Joachim Nilsson * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of Novell nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "fmemopen.h" -FILE* -fmemopen(void* buf, size_t size, const char* mode) +FILE* fmemopen(void* buf, size_t len, const char* type) { - char temppath[MAX_PATH + 1]; - char tempnam[MAX_PATH + 1]; - DWORD l; - HANDLE fh; - FILE* fp; + int fd; + FILE* fp; + char tp[MAX_PATH - 13]; + char fn[MAX_PATH + 1]; - if (strcmp(mode, "r") != 0 && strcmp(mode, "r+") != 0) - return 0; - l = GetTempPathA(MAX_PATH, temppath); - if (!l || l >= MAX_PATH) - return 0; - if (!GetTempFileNameA(temppath, "solvtmp", 0, tempnam)) - return 0; - fh = CreateFileA(tempnam, DELETE | GENERIC_READ | GENERIC_WRITE, 0, - NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, - NULL); - if (fh == INVALID_HANDLE_VALUE) - return 0; - fp = _fdopen(_open_osfhandle((intptr_t)fh, 0), "w+b"); - if (!fp) - { - CloseHandle(fh); - return 0; - } - if (buf && size && fwrite(buf, size, 1, fp) != 1) - { - fclose(fp); - return 0; - } - rewind(fp); - return fp; + if (!GetTempPathA(sizeof(tp), tp)) + return NULL; + + if (!GetTempFileNameA(tp, "eptmp", 0, fn)) + return NULL; + + _sopen_s(&fd, fn, + _O_CREAT | _O_RDWR | _O_SHORT_LIVED | _O_TEMPORARY | _O_BINARY, + _SH_DENYRW, + _S_IREAD | _S_IWRITE); + if (fd == -1) + return NULL; + + fp = _fdopen(fd, "w+"); + if (!fp) { + _close(fd); + return NULL; + } + + fwrite(buf, len, 1, fp); + rewind(fp); + + return fp; } \ No newline at end of file diff --git a/ExplorerPatcher/fmemopen.h b/ExplorerPatcher/fmemopen.h index 4b6060a..3c337ee 100644 --- a/ExplorerPatcher/fmemopen.h +++ b/ExplorerPatcher/fmemopen.h @@ -4,5 +4,6 @@ #include #include #include -FILE* fmemopen(void* buf, size_t size, const char* mode); +#include +FILE* fmemopen(void* buf, size_t len, const char* type); #endif \ No newline at end of file diff --git a/ExplorerPatcher/settings.reg b/ExplorerPatcher/settings.reg index 872ffb0..5dea111 100644 --- a/ExplorerPatcher/settings.reg +++ b/ExplorerPatcher/settings.reg @@ -68,9 +68,7 @@ ;x 1 Small ;x 0 Large (default) "TaskbarSmallIcons"=dword:00000000 -[HKEY_CURRENT_USER\Software\ExplorerPatcher] -;b Show People on the taskbar -;"Virtualized_{D17F1E1A-5919-4427-8F89-A1A8503CA3EB}_PeopleBand"=dword:00000000 +;e ;T System tray @@ -346,6 +344,48 @@ ;https://github.com/valinet/ExplorerPatcher/wiki/Simple-Window-Switcher + +;T Weather +;t The following settings only apply to the Windows 10 taskbar: +[HKEY_CURRENT_USER\Software\ExplorerPatcher] +;b Show Weather on the taskbar +;"Virtualized_{D17F1E1A-5919-4427-8F89-A1A8503CA3EB}_PeopleBand"=dword:00000000 +;c 3 Layout +;x 1 Icon only +;x 3 Icon and temperature +;x 0 Icon and text (default) +"WeatherViewMode"=dword:00000000 +;c 7 Update frequency +;x 60 Every minute +;x 300 Every 5 minutes +;x 900 Every 15 minutes +;x 1200 Every 20 minutes (default) +;x 1800 Every half an hour +;x 3600 Every hour +;x 7200 Every couple of hours +"WeatherContentUpdateMode"=dword:000004B0 +;c 2 Temperature unit +;x 0 Celsius (default) +;x 1 Fahrenheit +"WeatherTemperatureUnit"=dword:00000000 +;w Location +;Search City or Zip Code; the program looks up "weather in /* what you typed */" on Google. Leave blank for the default value (IP-based current location). +;Current location (default) +"WeatherLocation"="" +;w Language +;Type the short code for the language you'd like the weather data to be displayed in. For example, try "en", "ro", "de", "fr" etc. Leave blank for the default value (English). +;en (default) +"WeatherLanguage"="" +;q +;t Weather data courtesy of Google, and weather.com. +;y Learn more about the Weather taskbar widget 🡕 +;https://github.com/valinet/ExplorerPatcher/wiki/Weather +;u Refresh weather data +;update_weather + + + + ;T Other [HKEY_CURRENT_USER\Software\ExplorerPatcher] ;b Remember last used section in this window @@ -401,6 +441,15 @@ "UpdatePolicy"=dword:00000001 ;b Receive pre-release versions, if available (not recommended) "UpdatePreferStaging"=dword:00000000 +;t Update servers: +;w Releases +;Type a URL that serves resources adhering to GitHub's releases API. To learn how to configure your own update server, please consult the wiki. +;github.com/valinet/ExplorerPatcher/releases/latest +"UpdateURL"="" +;w Pre-releases +;Type a URL that serves resources adhering to GitHub's pre-releases API. To learn how to configure your own update server, please consult the wiki. +;api.github.com/repos/valinet/ExplorerPatcher/releases?per_page=1 +"UpdateURLStaging"="" ;y Check for updates ;;;EP_CHECK_FOR_UPDATES ;y Update program and restart File Explorer @@ -483,6 +532,7 @@ ;reset + ;f ;u Restart File Explorer (*) ;restart diff --git a/ExplorerPatcher/updates.c b/ExplorerPatcher/updates.c index 60331a9..22cac2c 100644 --- a/ExplorerPatcher/updates.c +++ b/ExplorerPatcher/updates.c @@ -596,6 +596,10 @@ BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail, szUpdateURL, &dwSize ); + if (dwSize == 1 && szUpdateURL[0] == 0) + { + strcat_s(szUpdateURL, MAX_PATH, UPDATES_RELEASE_INFO_URL_STABLE); + } strcat_s(szUpdateURL, MAX_PATH, "/download/"); strcat_s(szUpdateURL, MAX_PATH, SETUP_UTILITY_NAME); if (wszInfoURL) @@ -609,6 +613,10 @@ BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail, wszInfoURL, &dwSize ); + if (dwSize == 1 && wszInfoURL[0] == 0) + { + wcscat_s(wszInfoURL, dwInfoURLLen, _T(UPDATES_RELEASE_INFO_URL_STABLE)); + } } dwSize = sizeof(DWORD); RegQueryValueExA( @@ -641,6 +649,10 @@ BOOL IsUpdateAvailable(LPCWSTR wszDataStore, char* szCheckAgainst, BOOL* lpFail, szUpdateURL, &dwSize ); + if (dwSize == 1 && szUpdateURL[0] == 0) + { + strcat_s(szUpdateURL, MAX_PATH, UPDATES_RELEASE_INFO_URL_STAGING); + } } RegCloseKey(hKey); } @@ -706,6 +718,10 @@ BOOL UpdateProduct( szUpdateURL, &dwSize ); + if (dwSize == 1 && szUpdateURL[0] == 0) + { + strcat_s(szUpdateURL, MAX_PATH, UPDATES_RELEASE_INFO_URL_STABLE); + } strcat_s(szUpdateURL, MAX_PATH, "/download/"); strcat_s(szUpdateURL, MAX_PATH, SETUP_UTILITY_NAME); dwSize = sizeof(DWORD); @@ -739,6 +755,10 @@ BOOL UpdateProduct( szUpdateURL, &dwSize ); + if (dwSize == 1 && szUpdateURL[0] == 0) + { + strcat_s(szUpdateURL, MAX_PATH, UPDATES_RELEASE_INFO_URL_STAGING); + } } RegCloseKey(hKey); } diff --git a/ExplorerPatcher/utility.c b/ExplorerPatcher/utility.c index 43994f5..f252c99 100644 --- a/ExplorerPatcher/utility.c +++ b/ExplorerPatcher/utility.c @@ -788,4 +788,409 @@ LSTATUS RegisterDWMService(DWORD dwDesiredState, DWORD dwOverride) CloseHandle(ShExecInfo.hProcess); } return TRUE; +} + +char* StrReplaceAllA(const char* s, const char* oldW, const char* newW, int* dwNewSize) +{ + char* result; + int i, cnt = 0; + int newWlen = strlen(newW); + int oldWlen = strlen(oldW); + + for (i = 0; s[i] != '\0'; i++) { + if (strstr(&s[i], oldW) == &s[i]) { + cnt++; + i += oldWlen - 1; + } + } + result = (char*)malloc(i + cnt * (newWlen - oldWlen) + 1); + i = 0; + while (*s) { + if (strstr(s, oldW) == s) { + strcpy_s(&result[i], strlen(newW) + 1, newW); + i += newWlen; + s += oldWlen; + } + else + result[i++] = *s++; + } + + result[i] = '\0'; + if (dwNewSize) *dwNewSize = i; + return result; +} + +WCHAR* StrReplaceAllW(const WCHAR* s, const WCHAR* oldW, const WCHAR* newW, int* dwNewSize) +{ + WCHAR* result; + int i, cnt = 0; + int newWlen = wcslen(newW); + int oldWlen = wcslen(oldW); + + for (i = 0; s[i] != L'\0'; i++) { + if (wcsstr(&s[i], oldW) == &s[i]) { + cnt++; + i += oldWlen - 1; + } + } + result = (WCHAR*)malloc((i + cnt * (newWlen - oldWlen) + 1) * sizeof(WCHAR)); + i = 0; + while (*s) { + if (wcsstr(s, oldW) == s) { + wcscpy_s(&result[i], newWlen + 1, newW); + i += newWlen; + s += oldWlen; + } + else + result[i++] = *s++; + } + result[i] = L'\0'; + if (dwNewSize) *dwNewSize = i; + return result; +} + +HWND InputBox_HWND; + +HRESULT getEngineGuid(LPCTSTR extension, GUID* guidBuffer) +{ + wchar_t buffer[100]; + HKEY hk; + DWORD size; + HKEY subKey; + DWORD type; + + // See if this file extension is associated + // with an ActiveX script engine + if (!RegOpenKeyEx(HKEY_CLASSES_ROOT, extension, 0, + KEY_QUERY_VALUE | KEY_READ, &hk)) + { + type = REG_SZ; + size = sizeof(buffer); + size = RegQueryValueEx(hk, 0, 0, &type, + (LPBYTE)&buffer[0], &size); + RegCloseKey(hk); + if (!size) + { + // The engine set an association. + // We got the Language string in buffer[]. Now + // we can use it to look up the engine's GUID + + // Open HKEY_CLASSES_ROOT\{LanguageName} + again: size = sizeof(buffer); + if (!RegOpenKeyEx(HKEY_CLASSES_ROOT, (LPCTSTR)&buffer[0], 0, + KEY_QUERY_VALUE | KEY_READ, &hk)) + { + // Read the GUID (in string format) + // into buffer[] by querying the value of CLSID + if (!RegOpenKeyEx(hk, L"CLSID", 0, + KEY_QUERY_VALUE | KEY_READ, &subKey)) + { + size = RegQueryValueExW(subKey, 0, 0, &type, + (LPBYTE)&buffer[0], &size); + RegCloseKey(subKey); + } + else if (extension) + { + // If an error, see if we have a "ScriptEngine" + // key under here that contains + // the real language name + if (!RegOpenKeyEx(hk, L"ScriptEngine", 0, + KEY_QUERY_VALUE | KEY_READ, &subKey)) + { + size = RegQueryValueEx(subKey, 0, 0, &type, + (LPBYTE)&buffer[0], &size); + RegCloseKey(subKey); + if (!size) + { + RegCloseKey(hk); + extension = 0; + goto again; + } + } + } + } + + RegCloseKey(hk); + + if (!size) + { + // Convert the GUID string to a GUID + // and put it in caller's guidBuffer + if ((size = CLSIDFromString(&buffer[0], guidBuffer))) + { + return(E_FAIL); + } + return(size); + } + } + } + + return(E_FAIL); +} + +ULONG STDMETHODCALLTYPE ep_static_AddRefRelease(void* _this) +{ + return 1; +} + +HRESULT STDMETHODCALLTYPE IActiveScriptSite_QueryInterface(void* _this, REFIID riid, void** ppv) +{ + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IActiveScriptSite)) + *ppv = _this; + else if (IsEqualIID(riid, &IID_IActiveScriptSiteWindow)) + *ppv = ((unsigned char*)_this + 8); + else + { + *ppv = 0; + return(E_NOINTERFACE); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IActiveScriptSiteWindow_QueryInterface(void* _this, REFIID riid, void** ppv) +{ + return IActiveScriptSite_QueryInterface((char*)_this - 8, riid, ppv); +} + +HRESULT STDMETHODCALLTYPE IActiveScriptSite_GetLCID(void* _this, LCID* plcid) +{ + *plcid = LOCALE_USER_DEFAULT; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IActiveScriptSite_GetItemInfo(void* _this, LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown** ppiunkItem, ITypeInfo** ppti) +{ + return TYPE_E_ELEMENTNOTFOUND; +} + +HRESULT STDMETHODCALLTYPE IActiveScriptSite_GetDocVersionString(void* _this, BSTR* pbstrVersion) +{ + *pbstrVersion = 0; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IActiveScriptSite_OnScriptTerminate(void* _this, const void* pvarResult, const EXCEPINFO* pexcepinfo) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IActiveScriptSite_OnStateChange(void* _this, SCRIPTSTATE ssScriptState) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IActiveScriptSite_OnScriptError(void* _this, IActiveScriptError* scriptError) +{ + ULONG lineNumber; + BSTR desc; + EXCEPINFO ei; + OLECHAR wszOutput[1024]; + + // Call GetSourcePosition() to retrieve the line # where + // the error occurred in the script + scriptError->lpVtbl->GetSourcePosition(scriptError, 0, &lineNumber, 0); + + // Call GetSourceLineText() to retrieve the line in the script that + // has an error. + desc = 0; + scriptError->lpVtbl->GetSourceLineText(scriptError, &desc); + + // Call GetExceptionInfo() to fill in our EXCEPINFO struct with more + // information. + ZeroMemory(&ei, sizeof(EXCEPINFO)); + scriptError->lpVtbl->GetExceptionInfo(scriptError, &ei); + + // Format the message we'll display to the user + wsprintfW(&wszOutput[0], L"%s\nLine %u: %s\n%s", ei.bstrSource, + lineNumber + 1, ei.bstrDescription, desc ? desc : ""); + + // Free what we got from the IActiveScriptError functions + SysFreeString(desc); + SysFreeString(ei.bstrSource); + SysFreeString(ei.bstrDescription); + SysFreeString(ei.bstrHelpFile); + + // Display the message + MessageBoxW(0, &wszOutput[0], L"Error", + MB_SETFOREGROUND | MB_OK | MB_ICONEXCLAMATION); + + return(S_OK); +} + +HRESULT STDMETHODCALLTYPE IActiveScriptSite_OnEnterScript(void* _this) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IActiveScriptSite_OnLeaveScript(void* _this) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IActiveScriptSiteWindow_GetWindow(void* _this, HWND* phWnd) +{ + *phWnd = InputBox_HWND; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IActiveScriptSiteWindow_EnableModeless(void* _this, BOOL fEnable) +{ + return S_OK; +} + +static const IActiveScriptSiteVtbl IActiveScriptSite_Vtbl = { + .QueryInterface = IActiveScriptSite_QueryInterface, + .AddRef = ep_static_AddRefRelease, + .Release = ep_static_AddRefRelease, + .GetLCID = IActiveScriptSite_GetLCID, + .GetItemInfo = IActiveScriptSite_GetItemInfo, + .GetDocVersionString = IActiveScriptSite_GetDocVersionString, + .OnScriptTerminate = IActiveScriptSite_OnScriptTerminate, + .OnStateChange = IActiveScriptSite_OnStateChange, + .OnScriptError = IActiveScriptSite_OnScriptError, + .OnEnterScript = IActiveScriptSite_OnEnterScript, + .OnLeaveScript = IActiveScriptSite_OnLeaveScript, +}; + +static const IActiveScriptSiteWindowVtbl IActiveScriptSiteWindow_Vtbl = { + .QueryInterface = IActiveScriptSiteWindow_QueryInterface, + .AddRef = ep_static_AddRefRelease, + .Release = ep_static_AddRefRelease, + .GetWindow = IActiveScriptSiteWindow_GetWindow, + .EnableModeless = IActiveScriptSiteWindow_EnableModeless, +}; + +typedef struct _CSimpleScriptSite +{ + IActiveScriptSiteVtbl* lpVtbl; + IActiveScriptSiteWindowVtbl* lpVtbl1; +} CSimpleScriptSite; + +static const CSimpleScriptSite CSimpleScriptSite_Instance = { + .lpVtbl = &IActiveScriptSite_Vtbl, + .lpVtbl1 = &IActiveScriptSiteWindow_Vtbl +}; + +static BOOL HideInput = FALSE; +static LRESULT CALLBACK InputBoxProc(int nCode, WPARAM wParam, LPARAM lParam) { + if (nCode < HC_ACTION) + return CallNextHookEx(0, nCode, wParam, lParam); + if (nCode = HCBT_ACTIVATE) { + if (HideInput == TRUE) { + HWND TextBox = FindWindowExA((HWND)wParam, NULL, "Edit", NULL); + SendDlgItemMessageW((HWND)wParam, GetDlgCtrlID(TextBox), EM_SETPASSWORDCHAR, L'\x25cf', 0); + } + } + if (nCode = HCBT_CREATEWND) { + if (!(GetWindowLongPtr((HWND)wParam, GWL_STYLE) & WS_CHILD)) + SetWindowLongPtr((HWND)wParam, GWL_EXSTYLE, GetWindowLongPtr((HWND)wParam, GWL_EXSTYLE) | WS_EX_DLGMODALFRAME); + } + return CallNextHookEx(0, nCode, wParam, lParam); +} + +HRESULT InputBox(BOOL bPassword, HWND hWnd, LPCWSTR wszPrompt, LPCWSTR wszTitle, LPCWSTR wszDefault, LPCWSTR wszAnswer, DWORD cbAnswer) +{ + HRESULT hr = S_OK; + + GUID guidBuffer; + getEngineGuid(L".vbs", &guidBuffer); + + DWORD cchPromptSafe = 0, cchTitleSafe = 0, cchDefaultSafe = 0; + LPWSTR wszPromptSafe = StrReplaceAllW(wszPrompt, L"\"", L"\"\"", &cchPromptSafe); + LPWSTR wszTitleSafe = StrReplaceAllW(wszTitle, L"\"", L"\"\"", &cchTitleSafe); + LPWSTR wszDefaultSafe = StrReplaceAllW(wszDefault, L"\"", L"\"\"", &cchDefaultSafe); + if (!wszPromptSafe || !wszTitleSafe || !wszDefaultSafe) + { + if (wszPromptSafe) + { + free(wszPromptSafe); + } + if (wszTitleSafe) + { + free(wszTitleSafe); + } + if (wszDefaultSafe) + { + free(wszDefaultSafe); + } + return E_OUTOFMEMORY; + } + + IActiveScript* pActiveScript = NULL; + hr = CoCreateInstance(&guidBuffer, 0, CLSCTX_ALL, + &IID_IActiveScript, + (void**)&pActiveScript); + if (SUCCEEDED(hr) && pActiveScript) + { + hr = pActiveScript->lpVtbl->SetScriptSite(pActiveScript, &CSimpleScriptSite_Instance); + if (SUCCEEDED(hr)) + { + IActiveScriptParse* pActiveScriptParse = NULL; + hr = pActiveScript->lpVtbl->QueryInterface(pActiveScript, &IID_IActiveScriptParse, &pActiveScriptParse); + if (SUCCEEDED(hr) && pActiveScriptParse) + { + hr = pActiveScriptParse->lpVtbl->InitNew(pActiveScriptParse); + if (SUCCEEDED(hr)) + { + LPWSTR wszEvaluation = malloc(sizeof(WCHAR) * (cchPromptSafe + cchTitleSafe + cchDefaultSafe + 100)); + if (wszEvaluation) + { + swprintf_s(wszEvaluation, cchPromptSafe + cchTitleSafe + cchDefaultSafe + 100, L"InputBox(\"%s\", \"%s\", \"%s\")", wszPromptSafe, wszTitleSafe, wszDefaultSafe); + DWORD cchEvaluation2 = 0; + LPWSTR wszEvaluation2 = StrReplaceAllW(wszEvaluation, L"\n", L"\" + vbNewLine + \"", &cchEvaluation2); + if (wszEvaluation2) + { + EXCEPINFO ei; + ZeroMemory(&ei, sizeof(EXCEPINFO)); + DWORD dwThreadId = GetCurrentThreadId(); + HINSTANCE hInstance = GetModuleHandle(NULL); + + if (!hWnd) + { + InputBox_HWND = GetAncestor(GetActiveWindow(), GA_ROOTOWNER); + } + else + { + InputBox_HWND = hWnd; + } + + HHOOK hHook = SetWindowsHookExW(WH_CBT, &InputBoxProc, hInstance, dwThreadId); + + VARIANT result; + VariantInit(&result); + + HideInput = bPassword; + hr = pActiveScriptParse->lpVtbl->ParseScriptText(pActiveScriptParse, wszEvaluation2, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &result, &ei); + + UnhookWindowsHookEx(hHook); + + free(wszEvaluation2); + + memcpy(wszAnswer, result.bstrVal, cbAnswer * sizeof(WCHAR)); + + VariantClear(&result); + } + free(wszEvaluation); + } + } + pActiveScriptParse->lpVtbl->Release(pActiveScriptParse); + } + pActiveScript->lpVtbl->Release(pActiveScript); + } + } + + if (wszPromptSafe) + { + free(wszPromptSafe); + } + if (wszTitleSafe) + { + free(wszTitleSafe); + } + if (wszDefaultSafe) + { + free(wszDefaultSafe); + } + + return hr; } \ No newline at end of file diff --git a/ExplorerPatcher/utility.h b/ExplorerPatcher/utility.h index 3903a79..5986d75 100644 --- a/ExplorerPatcher/utility.h +++ b/ExplorerPatcher/utility.h @@ -18,6 +18,7 @@ #include #include "queryversion.h" #pragma comment(lib, "Psapi.lib") +#include #include "def.h" @@ -220,6 +221,8 @@ static void(*AllowDarkModeForWindow)(HWND hWnd, INT64 bAllowDark); static BOOL(*ShouldAppsUseDarkMode)(); +static BOOL(*ShouldSystemUseDarkMode)(); + static void(*GetThemeName)(void*, void*, void*); static BOOL AppsShouldUseDarkMode() { return TRUE; } @@ -236,6 +239,27 @@ BOOL SystemShutdown(BOOL reboot); LSTATUS RegisterDWMService(DWORD dwDesiredState, DWORD dwOverride); +char* StrReplaceAllA(const char* s, const char* oldW, const char* newW, int* dwNewSize); + +WCHAR* StrReplaceAllW(const WCHAR* s, const WCHAR* oldW, const WCHAR* newW, int* dwNewSize); + +HRESULT InputBox(BOOL bPassword, HWND hWnd, LPCWSTR wszPrompt, LPCWSTR wszTitle, LPCWSTR wszDefault, LPCWSTR wszAnswer, DWORD cbAnswer); + +// https://codereview.stackexchange.com/questions/29198/random-string-generator-in-c +static inline WCHAR* rand_string(WCHAR* str, size_t size) +{ + const WCHAR charset[] = L"abcdefghijklmnopqrstuvwxyz"; + if (size) { + --size; + for (size_t n = 0; n < size; n++) { + int key = rand() % (int)(sizeof charset - 1); + str[n] = charset[key]; + } + str[size] = L'\0'; + } + return str; +} + inline long long milliseconds_now() { LARGE_INTEGER s_frequency; BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency); diff --git a/ep_setup/ep_setup.c b/ep_setup/ep_setup.c index 0db9ad4..055ff2a 100644 --- a/ep_setup/ep_setup.c +++ b/ep_setup/ep_setup.c @@ -346,6 +346,32 @@ int WINAPI wWinMain( wcscat_s(wszPath, MAX_PATH, L"\\ep_dwm.exe"); bOk = InstallResource(TRUE, hInstance, IDR_EP_DWM, wszPath); } + if (argc >= 2) + { + wcsncpy_s(wszPath, MAX_PATH, wargv[1], MAX_PATH); + } + else + { + GetCurrentDirectoryW(MAX_PATH, wszPath); + } + if (bOk) + { + wcscat_s(wszPath, MAX_PATH, L"\\ep_weather_host.dll"); + bOk = InstallResource(TRUE, hInstance, IDR_EP_WEATHER, wszPath); + } + if (argc >= 2) + { + wcsncpy_s(wszPath, MAX_PATH, wargv[1], MAX_PATH); + } + else + { + GetCurrentDirectoryW(MAX_PATH, wszPath); + } + if (bOk) + { + wcscat_s(wszPath, MAX_PATH, L"\\ep_weather_host_stub.dll"); + bOk = InstallResource(TRUE, hInstance, IDR_EP_WEATHER_STUB, wszPath); + } return 0; } @@ -447,6 +473,8 @@ int WINAPI wWinMain( CloseHandle(sei.hProcess); } + Sleep(500); + BOOL bAreRoundedCornersDisabled = FALSE; HANDLE h_exists = CreateEventW(NULL, FALSE, FALSE, L"Global\\ep_dwm_" _T(EP_CLSID)); if (h_exists) @@ -628,6 +656,27 @@ int WINAPI wWinMain( wcscat_s(wszPath, MAX_PATH, L"\\ep_dwm.exe"); bOk = InstallResource(bInstall, hInstance, IDR_EP_DWM, wszPath); } + if (bInstall) + { + if (bOk) + { + PathRemoveFileSpecW(wszPath); + wcscat_s(wszPath, MAX_PATH, L"\\ep_weather_host.dll"); + bOk = InstallResource(bInstall, hInstance, IDR_EP_WEATHER, wszPath); + } + if (bOk) + { + PathRemoveFileSpecW(wszPath); + wcscat_s(wszPath, MAX_PATH, L"\\ep_weather_host_stub.dll"); + bOk = InstallResource(bInstall, hInstance, IDR_EP_WEATHER_STUB, wszPath); + } + if (bOk) + { + PathRemoveFileSpecW(wszPath); + wcscat_s(wszPath, MAX_PATH, L"\\WebView2Loader.dll"); + bOk = InstallResource(bInstall, hInstance, IDR_MS_WEBVIEW2_LOADER, wszPath); + } + } if (bOk) { bOk = GetWindowsDirectoryW(wszPath, MAX_PATH); @@ -670,6 +719,109 @@ int WINAPI wWinMain( GetExitCodeProcess(ShExecInfo.hProcess, &dwExitCode); CloseHandle(ShExecInfo.hProcess); } + if (bOk) + { + WCHAR wszArgs[MAX_PATH]; + wszArgs[0] = L'/'; + wszArgs[1] = L's'; + wszArgs[2] = L' '; + wszArgs[3] = L'"'; + if (!bInstall) + { + wszArgs[3] = L'/'; + wszArgs[4] = L'u'; + wszArgs[5] = L' '; + wszArgs[6] = L'"'; + } + SHGetFolderPathW(NULL, SPECIAL_FOLDER, NULL, SHGFP_TYPE_CURRENT, wszArgs + 4 + (bInstall ? 0 : 3)); + wcscat_s(wszArgs, MAX_PATH, _T(APP_RELATIVE_PATH) L"\\ep_weather_host.dll\""); + wprintf(L"%s\n", wszArgs); + WCHAR wszApp[MAX_PATH * 2]; + GetSystemDirectoryW(wszApp, MAX_PATH * 2); + wcscat_s(wszApp, MAX_PATH * 2, L"\\regsvr32.exe"); + wprintf(L"%s\n", wszApp); + SHELLEXECUTEINFOW sei; + ZeroMemory(&sei, sizeof(SHELLEXECUTEINFOW)); + sei.cbSize = sizeof(sei); + sei.fMask = SEE_MASK_NOCLOSEPROCESS; + sei.hwnd = NULL; + sei.hInstApp = NULL; + sei.lpVerb = NULL; + sei.lpFile = wszApp; + sei.lpParameters = wszArgs; + sei.hwnd = NULL; + sei.nShow = SW_NORMAL; + if (ShellExecuteExW(&sei) && sei.hProcess) + { + WaitForSingleObject(sei.hProcess, INFINITE); + DWORD dwExitCode = 0; + GetExitCodeProcess(sei.hProcess, &dwExitCode); + SetLastError(dwExitCode); + CloseHandle(sei.hProcess); + } + } + if (bOk) + { + WCHAR wszArgs[MAX_PATH]; + wszArgs[0] = L'/'; + wszArgs[1] = L's'; + wszArgs[2] = L' '; + wszArgs[3] = L'"'; + if (!bInstall) + { + wszArgs[3] = L'/'; + wszArgs[4] = L'u'; + wszArgs[5] = L' '; + wszArgs[6] = L'"'; + } + SHGetFolderPathW(NULL, SPECIAL_FOLDER, NULL, SHGFP_TYPE_CURRENT, wszArgs + 4 + (bInstall ? 0 : 3)); + wcscat_s(wszArgs, MAX_PATH, _T(APP_RELATIVE_PATH) L"\\ep_weather_host_stub.dll\""); + wprintf(L"%s\n", wszArgs); + WCHAR wszApp[MAX_PATH * 2]; + GetSystemDirectoryW(wszApp, MAX_PATH * 2); + wcscat_s(wszApp, MAX_PATH * 2, L"\\regsvr32.exe"); + wprintf(L"%s\n", wszApp); + SHELLEXECUTEINFOW sei; + ZeroMemory(&sei, sizeof(SHELLEXECUTEINFOW)); + sei.cbSize = sizeof(sei); + sei.fMask = SEE_MASK_NOCLOSEPROCESS; + sei.hwnd = NULL; + sei.hInstApp = NULL; + sei.lpVerb = NULL; + sei.lpFile = wszApp; + sei.lpParameters = wszArgs; + sei.hwnd = NULL; + sei.nShow = SW_NORMAL; + if (ShellExecuteExW(&sei) && sei.hProcess) + { + WaitForSingleObject(sei.hProcess, INFINITE); + DWORD dwExitCode = 0; + GetExitCodeProcess(sei.hProcess, &dwExitCode); + SetLastError(dwExitCode); + CloseHandle(sei.hProcess); + } + } + if (!bInstall) + { + if (bOk) + { + SHGetFolderPathW(NULL, SPECIAL_FOLDER, NULL, SHGFP_TYPE_CURRENT, wszPath); + wcscat_s(wszPath, MAX_PATH, _T(APP_RELATIVE_PATH) L"\\ep_weather_host.dll"); + bOk = InstallResource(bInstall, hInstance, IDR_EP_WEATHER, wszPath); + } + if (bOk) + { + PathRemoveFileSpecW(wszPath); + wcscat_s(wszPath, MAX_PATH, L"\\ep_weather_host_stub.dll"); + bOk = InstallResource(bInstall, hInstance, IDR_EP_WEATHER_STUB, wszPath); + } + if (bOk) + { + PathRemoveFileSpecW(wszPath); + wcscat_s(wszPath, MAX_PATH, L"\\WebView2Loader.dll"); + bOk = InstallResource(bInstall, hInstance, IDR_MS_WEBVIEW2_LOADER, wszPath); + } + } if (bOk) { diff --git a/ep_setup/ep_setup.rc b/ep_setup/ep_setup.rc index 2a9389a..832cf18 100644 --- a/ep_setup/ep_setup.rc +++ b/ep_setup/ep_setup.rc @@ -96,6 +96,12 @@ IDR_EP_IA32 RCDATA "..\\build\\Release\\ExplorerPatcher. IDR_EP_DWM RCDATA "..\\build\\Release\\ep_dwm.exe" +IDR_EP_WEATHER RCDATA "..\\build\\Release\\ep_weather_host.dll" + +IDR_EP_WEATHER_STUB RCDATA "..\\build\\Release\\ep_weather_host_stub.dll" + +IDR_MS_WEBVIEW2_LOADER RCDATA "..\\build\\Release\\WebView2Loader.dll" + #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/ep_setup/ep_setup.vcxproj b/ep_setup/ep_setup.vcxproj index 4942bc2..24fcaac 100644 --- a/ep_setup/ep_setup.vcxproj +++ b/ep_setup/ep_setup.vcxproj @@ -173,6 +173,14 @@ true true + + true + true + + + true + true + true true @@ -189,6 +197,14 @@ + + true + true + + + true + true + true true diff --git a/ep_setup/ep_setup.vcxproj.filters b/ep_setup/ep_setup.vcxproj.filters index 1e63132..24b3cb7 100644 --- a/ep_setup/ep_setup.vcxproj.filters +++ b/ep_setup/ep_setup.vcxproj.filters @@ -48,5 +48,9 @@ + + + + \ No newline at end of file diff --git a/ep_setup/ep_setup_debug.rc b/ep_setup/ep_setup_debug.rc index 597f277..3bf9708 100644 --- a/ep_setup/ep_setup_debug.rc +++ b/ep_setup/ep_setup_debug.rc @@ -96,6 +96,12 @@ IDR_EP_IA32 RCDATA "..\\build\\Debug\\ExplorerPatcher.IA IDR_EP_DWM RCDATA "..\\build\\Debug\\ep_dwm.exe" +IDR_EP_WEATHER RCDATA "..\\build\\Debug\\ep_weather_host.dll" + +IDR_EP_WEATHER_STUB RCDATA "..\\build\\Debug\\ep_weather_host_stub.dll" + +IDR_MS_WEBVIEW2_LOADER RCDATA "..\\build\\Release\\WebView2Loader.dll" + #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/ep_setup/resource.h b/ep_setup/resource.h index a26c845..7c8e3b7 100644 --- a/ep_setup/resource.h +++ b/ep_setup/resource.h @@ -5,6 +5,9 @@ #define IDR_EP_AMD64 103 #define IDR_EP_IA32 104 #define IDR_EP_DWM 105 +#define IDR_EP_WEATHER 106 +#define IDR_EP_WEATHER_STUB 107 +#define IDR_MS_WEBVIEW2_LOADER 201 // Next default values for new objects // diff --git a/ep_weather_host/ep_weather.c b/ep_weather_host/ep_weather.c new file mode 100644 index 0000000..b5d2097 --- /dev/null +++ b/ep_weather_host/ep_weather.c @@ -0,0 +1,309 @@ +#include "ep_weather.h" +#include "ep_weather_factory.h" +#include "ep_weather_host.h" + +HMODULE epw_hModule; +DWORD epw_OutstandingObjects = 0; +DWORD epw_LockCount = 0; + +#ifdef _WIN64 +#pragma comment(linker, "/export:DllRegisterServer=_DllRegisterServer") +#else +#pragma comment(linker, "/export:DllRegisterServer=__DllRegisterServer@0") +#endif +HRESULT WINAPI _DllRegisterServer() +{ + DWORD dwLastError = ERROR_SUCCESS; + HKEY hKey = NULL; + DWORD dwSize = 0; + wchar_t wszFilename[MAX_PATH]; + wchar_t wszInstallPath[MAX_PATH]; + + if (!dwLastError) + { + if (!GetModuleFileNameW(epw_hModule, wszFilename, MAX_PATH)) + { + dwLastError = GetLastError(); + } + } + if (!dwLastError) + { + dwLastError = RegCreateKeyExW( + HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Classes\\CLSID\\") _T(CLSID_EPWeather_TEXT), + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | KEY_WOW64_64KEY, + NULL, + &hKey, + NULL + ); + if (hKey == NULL || hKey == INVALID_HANDLE_VALUE) + { + hKey = NULL; + } + if (hKey) + { + dwLastError = RegSetValueExW( + hKey, + NULL, + 0, + REG_SZ, + _T(CLSID_EPWeather_Name), + 29 * sizeof(wchar_t) + ); + dwLastError = RegSetValueExW( + hKey, + L"AppID", + 0, + REG_SZ, + _T(CLSID_EPWeather_TEXT), + 39 * sizeof(wchar_t) + ); + RegCloseKey(hKey); + } + dwLastError = RegCreateKeyExW( + HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Classes\\CLSID\\") _T(CLSID_EPWeather_TEXT) _T("\\InProcServer32"), + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | KEY_WOW64_64KEY, + NULL, + &hKey, + NULL + ); + if (hKey == NULL || hKey == INVALID_HANDLE_VALUE) + { + hKey = NULL; + } + if (hKey) + { + dwLastError = RegSetValueExW( + hKey, + NULL, + 0, + REG_SZ, + wszFilename, + (wcslen(wszFilename) + 1) * sizeof(wchar_t) + ); + dwLastError = RegSetValueExW( + hKey, + L"ThreadingModel", + 0, + REG_SZ, + L"Apartment", + 10 * sizeof(wchar_t) + ); + RegCloseKey(hKey); + } + dwLastError = RegCreateKeyExW( + HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Classes\\AppID\\") _T(CLSID_EPWeather_TEXT), + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | KEY_WOW64_64KEY, + NULL, + &hKey, + NULL + ); + if (hKey == NULL || hKey == INVALID_HANDLE_VALUE) + { + hKey = NULL; + } + if (hKey) + { + dwLastError = RegSetValueExW( + hKey, + NULL, + 0, + REG_SZ, + _T(CLSID_EPWeather_Name), + 29 * sizeof(wchar_t) + ); + dwLastError = RegSetValueExW( + hKey, + L"DllSurrogate", + 0, + REG_SZ, + L"", + 1 * sizeof(wchar_t) + ); + RegCloseKey(hKey); + } + dwLastError = RegCreateKeyExW( + HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Classes\\AppID\\") _T(CLSID_EPWeather_TEXT), + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | KEY_WOW64_64KEY, + NULL, + &hKey, + NULL + ); + if (hKey == NULL || hKey == INVALID_HANDLE_VALUE) + { + hKey = NULL; + } + if (hKey) + { + dwLastError = RegSetValueExW( + hKey, + NULL, + 0, + REG_SZ, + _T(CLSID_EPWeather_Name), + 29 * sizeof(wchar_t) + ); + dwLastError = RegSetValueExW( + hKey, + L"DllSurrogate", + 0, + REG_SZ, + L"", + 1 * sizeof(wchar_t) + ); + RegCloseKey(hKey); + } + } + + return dwLastError == 0 ? (NOERROR) : (HRESULT_FROM_WIN32(dwLastError)); +} + +#ifdef _WIN64 +#pragma comment(linker, "/export:DllUnregisterServer=_DllUnregisterServer") +#else +#pragma comment(linker, "/export:DllUnregisterServer=__DllUnregisterServer@0") +#endif +HRESULT WINAPI _DllUnregisterServer() +{ + DWORD dwLastError = ERROR_SUCCESS; + HKEY hKey = NULL; + DWORD dwSize = 0; + wchar_t wszFilename[MAX_PATH]; + + if (!dwLastError) + { + if (!GetModuleFileNameW(epw_hModule, wszFilename, MAX_PATH)) + { + dwLastError = GetLastError(); + } + } + if (!dwLastError) + { + dwLastError = RegOpenKeyW( + HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Classes\\CLSID\\") _T(CLSID_EPWeather_TEXT), + &hKey + ); + if (hKey == NULL || hKey == INVALID_HANDLE_VALUE) + { + hKey = NULL; + } + if (hKey) + { + dwLastError = RegDeleteTreeW( + hKey, + 0 + ); + RegCloseKey(hKey); + if (!dwLastError) + { + RegDeleteKeyW( + HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Classes\\CLSID\\") _T(CLSID_EPWeather_TEXT) + ); + } + } + dwLastError = RegOpenKeyW( + HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Classes\\AppID\\") _T(CLSID_EPWeather_TEXT), + &hKey + ); + if (hKey == NULL || hKey == INVALID_HANDLE_VALUE) + { + hKey = NULL; + } + if (hKey) + { + dwLastError = RegDeleteTreeW( + hKey, + 0 + ); + RegCloseKey(hKey); + if (!dwLastError) + { + RegDeleteKeyW( + HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Classes\\AppID\\") _T(CLSID_EPWeather_TEXT) + ); + } + } + } + + return dwLastError == 0 ? (NOERROR) : (HRESULT_FROM_WIN32(dwLastError)); +} + +#ifdef _WIN64 +#pragma comment(linker, "/export:DllCanUnloadNow=_DllCanUnloadNow") +#else +#pragma comment(linker, "/export:DllCanUnloadNow=__DllCanUnloadNow@0") +#endif +HRESULT WINAPI _DllCanUnloadNow() +{ + return((epw_OutstandingObjects | epw_LockCount) ? S_FALSE : S_OK); +} + +#ifdef _WIN64 +#pragma comment(linker, "/export:DllGetClassObject=_DllGetClassObject") +#else +#pragma comment(linker, "/export:DllGetClassObject=__DllGetClassObject@12") +#endif +HRESULT WINAPI _DllGetClassObject( + REFCLSID objGuid, + REFIID factoryGuid, + LPVOID* factoryHandle +) +{ + HRESULT hr; + if (IsEqualCLSID(objGuid, &CLSID_EPWeather)) + { + hr = ClassFactory->lpVtbl->QueryInterface( + ClassFactory, + factoryGuid, + factoryHandle + ); + } + else + { + *factoryHandle = 0; + hr = CLASS_E_CLASSNOTAVAILABLE; + } + + return(hr); +} + +BOOL WINAPI DllMain( + _In_ HINSTANCE hinstDLL, + _In_ DWORD fdwReason, + _In_ LPVOID lpvReserved +) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + epw_hModule = hinstDLL; + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} diff --git a/ep_weather_host/ep_weather.h b/ep_weather_host/ep_weather.h new file mode 100644 index 0000000..674ea32 --- /dev/null +++ b/ep_weather_host/ep_weather.h @@ -0,0 +1,51 @@ +#ifndef _H_AS_H_ +#define _H_AS_H_ +#include +#include +#include +#include + +#pragma comment(lib, "Version.lib") +#pragma comment(lib, "Shlwapi.lib") + +#define ALLOC(x) calloc(1, x) +#define FREE(x) free(x) + +extern HMODULE epw_hModule; +extern DWORD epw_OutstandingObjects; +extern DWORD epw_LockCount; + +// {A6EA9C2D-4982-4827-9204-0AC532959F6D} +#define CLSID_EPWeather_Name "ExplorerPatcher Weather Host" +#define CLSID_EPWeather_TEXT "{A6EA9C2D-4982-4827-9204-0AC532959F6D}" +#define EP_Weather_Killswitch "Global\\EP_Weather_Killswitch_" CLSID_EPWeather_TEXT +DEFINE_GUID(CLSID_EPWeather, + 0xa6ea9c2d, 0x4982, 0x4827, 0x92, 0x4, 0xa, 0xc5, 0x32, 0x95, 0x9f, 0x6d); + +#if defined(__cplusplus) && !defined(CINTERFACE) +#else +DEFINE_GUID(IID_IEPWeather, + 0xcdbf3734, 0xf847, 0x4f1b, 0xb9, 0x53, 0xa6, 0x5, 0x43, 0x4d, 0xc1, 0xe7); +#endif + +#define EPW_WEATHER_CLASSNAME "ExplorerPatcher_Weather_" CLSID_EPWeather_TEXT + +#define EP_WEATHER_KEEP_VALUE -1 + +#define EP_WEATHER_NUM_PROVIDERS 2 +#define EP_WEATHER_PROVIDER_TEST 0 +#define EP_WEATHER_PROVIDER_GOOGLE 1 + +#define EP_WEATHER_NUM_TUNITS 2 +#define EP_WEATHER_TUNIT_CELSIUS 0 +#define EP_WEATHER_TUNIT_FAHRENHEIT 1 + +#define EP_WEATHER_VIEW_ICONONLY 1 +#define EP_WEATHER_VIEW_ICONTEMP 3 +#define EP_WEATHER_VIEW_ICONTEXT 0 + +#define EP_WEATHER_UPDATE_NORMAL 1200 +#define EP_WEATHER_UPDATE_REDUCED 3600 + +#define EP_WEATHER_WM_FETCH_DATA (WM_USER + 10) +#endif diff --git a/ep_weather_host/ep_weather_factory.c b/ep_weather_host/ep_weather_factory.c new file mode 100644 index 0000000..d2a0b3f --- /dev/null +++ b/ep_weather_host/ep_weather_factory.c @@ -0,0 +1,93 @@ +#include "ep_weather_factory.h" +#include "ep_weather_host.h" + +ULONG STDMETHODCALLTYPE epw_factory_AddRef(IClassFactory* _this) +{ + return(1); +} + +ULONG STDMETHODCALLTYPE epw_factory_Release(IClassFactory* _this) +{ + return(1); +} + +HRESULT STDMETHODCALLTYPE epw_factory_QueryInterface( + IClassFactory* _this, + REFIID riid, + void** ppv +) +{ + if (!IsEqualIID(riid, &IID_IUnknown) && + !IsEqualIID(riid, &IID_IClassFactory)) + { + *ppv = 0; + return(E_NOINTERFACE); + } + *ppv = _this; + _this->lpVtbl->AddRef(_this); + return(NOERROR); +} + +HRESULT STDMETHODCALLTYPE epw_factory_LockServer( + IClassFactory* this, + BOOL flock +) +{ + if (flock) InterlockedIncrement(&epw_LockCount); + else + { + LONG dwOutstandingLocks = InterlockedDecrement(&epw_LockCount); + LONG dwOutstandingObjects = InterlockedAdd(&epw_OutstandingObjects, 0); + if (!dwOutstandingObjects && !dwOutstandingLocks) + { + } + } + return(NOERROR); +} + +HRESULT STDMETHODCALLTYPE epw_factory_CreateInstance( + IClassFactory* _this, + IUnknown* punkOuter, + REFIID vTableGuid, + void** ppv +) +{ + HRESULT hr = E_NOINTERFACE; + EPWeather* thisobj = NULL; + + *ppv = 0; + + if (punkOuter) + { + hr = CLASS_E_NOAGGREGATION; + } + else + { + BOOL bOk = FALSE; + if (IsEqualIID(vTableGuid, &IID_IEPWeather)) + { + if (!(thisobj = ALLOC(sizeof(EPWeather)))) + { + hr = E_OUTOFMEMORY; + } + else + { + thisobj->lpVtbl = &IEPWeather_Vtbl; + bOk = TRUE; + } + } + if (bOk) + { + thisobj->cbCount = 1; + hr = thisobj->lpVtbl->QueryInterface(thisobj, vTableGuid, ppv); + thisobj->lpVtbl->Release(thisobj); + if (SUCCEEDED(hr)) InterlockedIncrement(&epw_OutstandingObjects); + } + else + { + return hr; + } + } + + return(hr); +} \ No newline at end of file diff --git a/ep_weather_host/ep_weather_factory.h b/ep_weather_host/ep_weather_factory.h new file mode 100644 index 0000000..f988443 --- /dev/null +++ b/ep_weather_host/ep_weather_factory.h @@ -0,0 +1,34 @@ +#ifndef _H_AS_FACTORY_H_ +#define _H_AS_FACTORY_H_ +#include "ep_weather.h" +ULONG STDMETHODCALLTYPE epw_factory_AddRef(IClassFactory* _this); +ULONG STDMETHODCALLTYPE epw_factory_Release(IClassFactory* _this); +HRESULT STDMETHODCALLTYPE epw_factory_QueryInterface( + IClassFactory* _this, + REFIID riid, + void** ppv +); +HRESULT STDMETHODCALLTYPE epw_factory_LockServer( + IClassFactory* _this, + BOOL flock +); +HRESULT STDMETHODCALLTYPE epw_factory_CreateInstance( + IClassFactory* _this, + IUnknown* punkOuter, + REFIID vTableGuid, + void** ppv +); +typedef interface IEPWeatherFactory IEPWeatherFactory; +// {A25216A3-4223-4CB3-A572-11A7CC1AEE4E} +DEFINE_GUID(IID_IEPWeatherFactory, + 0xa25216a3, 0x4223, 0x4cb3, 0xa5, 0x72, 0x11, 0xa7, 0xcc, 0x1a, 0xee, 0x4e); +static const IClassFactoryVtbl IEPWeatherFactoryVtbl = { + epw_factory_QueryInterface, + epw_factory_AddRef, + epw_factory_Release, + epw_factory_CreateInstance, + epw_factory_LockServer +}; +static IClassFactory IClassFactoryInstance = { &IEPWeatherFactoryVtbl }; +static IClassFactory* ClassFactory = &IClassFactoryInstance; +#endif diff --git a/ep_weather_host/ep_weather_host.c b/ep_weather_host/ep_weather_host.c new file mode 100644 index 0000000..e344355 --- /dev/null +++ b/ep_weather_host/ep_weather_host.c @@ -0,0 +1,1048 @@ +#include "ep_weather_host.h" +#include "ep_weather_provider_google_html.h" +#include "ep_weather_provider_google_script.h" + +LPCWSTR EP_Weather_Script_Provider_Google = L"\n"; + +HRESULT STDMETHODCALLTYPE INetworkListManagerEvents_QueryInterface(void* _this, REFIID riid, void** ppv) +{ + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_INetworkListManagerEvents)) + *ppv = _this; + else + { + *ppv = 0; + return(E_NOINTERFACE); + } + return S_OK; +} + +ULONG STDMETHODCALLTYPE INetworkListManagerEvents_AddRefRelease(void* _this) +{ + return 1; +} + +HRESULT STDMETHODCALLTYPE INetworkListManagerEvents_ConnectivityChanged(void* _this2, NLM_CONNECTIVITY newConnectivity) +{ + EPWeather* _this = GetWindowLongPtrW(FindWindowW(_T(EPW_WEATHER_CLASSNAME), NULL), GWLP_USERDATA); + if (_this) + { + if ((newConnectivity & (NLM_CONNECTIVITY_IPV4_INTERNET | NLM_CONNECTIVITY_IPV6_INTERNET)) != 0) + { + printf("[Network Events] Internet connection status is: Available.\n"); + LONG64 dwUpdateSchedule = InterlockedAdd64(&_this->dwUpdateSchedule, 0); + PostMessageW(_this->hWnd, EP_WEATHER_WM_FETCH_DATA, 0, 0); + SetTimer(_this->hWnd, EP_WEATHER_TIMER_SCHEDULE_REFRESH, dwUpdateSchedule, NULL); + printf("[Network Events] Reinstalled refresh timer.\n"); + } + else + { + printf("[Network Events] Internet connection status is: Offline.\n"); + KillTimer(_this->hWnd, EP_WEATHER_TIMER_SCHEDULE_REFRESH); + printf("[Network Events] Killed refresh timer.\n"); + } + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_static_Stub(void* _this) +{ + return S_OK; +} + +ULONG STDMETHODCALLTYPE epw_Weather_static_AddRefRelease(void* _this) +{ + return 1; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_static_QueryInterface(void* _this, REFIID riid, void** ppv) +{ + *ppv = _this; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ICoreWebView2_get_AdditionalBrowserArguments(ICoreWebView2EnvironmentOptions* _this, LPWSTR* value) +{ + *value = CoTaskMemAlloc(82 * sizeof(WCHAR)); + if (*value) + { + wcscpy_s(*value, 82, L"--disable-site-isolation-trials --disable-web-security --allow-insecure-localhost"); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ICoreWebView2_get_Language(ICoreWebView2EnvironmentOptions* _this, LPWSTR* value) +{ + *value = CoTaskMemAlloc(6 * sizeof(WCHAR)); + if (*value) + { + wcscpy_s(*value, 6, L"en-US"); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ICoreWebView2_get_TargetCompatibleBrowserVersion(ICoreWebView2EnvironmentOptions* _this, LPWSTR* value) +{ + *value = CoTaskMemAlloc(13 * sizeof(WCHAR)); + if (*value) + { + wcscpy_s(*value, 13, L"97.0.1072.69"); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ICoreWebView2_get_AllowSingleSignOnUsingOSPrimaryAccount(ICoreWebView2EnvironmentOptions* _this, BOOL* allow) +{ + *allow = TRUE; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ICoreWebView2_CreateCoreWebView2EnvironmentCompleted(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* _this, HRESULT hr, ICoreWebView2Environment* pCoreWebView2Environemnt) +{ + pCoreWebView2Environemnt->lpVtbl->CreateCoreWebView2Controller(pCoreWebView2Environemnt, FindWindowW(_T(EPW_WEATHER_CLASSNAME), NULL), &EPWeather_ICoreWebView2CreateCoreWebView2ControllerCompletedHandler); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE _epw_Weather_NavigateToProvider(EPWeather* _this) +{ + HRESULT hr = S_OK; + LONG64 dwProvider = InterlockedAdd64(&_this->dwProvider, 0); + if (dwProvider == EP_WEATHER_PROVIDER_TEST) + { + } + else if (dwProvider == EP_WEATHER_PROVIDER_GOOGLE) + { + //hr = _this->pCoreWebView2->lpVtbl->Navigate(_this->pCoreWebView2, L"https://google.com"); + _this->wszScriptData = malloc(sizeof(WCHAR) * EP_WEATHER_PROVIDER_GOOGLE_HTML_LEN); + if (_this->wszScriptData) + { + swprintf_s(_this->wszScriptData, EP_WEATHER_PROVIDER_GOOGLE_HTML_LEN, ep_weather_provider_google_html, _this->wszLanguage, _this->wszTerm[0] ? L" " : L"", _this->wszTerm); + hr = _this->pCoreWebView2->lpVtbl->NavigateToString(_this->pCoreWebView2, _this->wszScriptData); + if (FAILED(hr)) + { + InterlockedExchange64(&_this->bBrowserBusy, FALSE); + free(_this->wszScriptData); + } + } + else + { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + +HRESULT STDMETHODCALLTYPE _epw_Weather_ExecuteDataScript(EPWeather* _this) +{ + HRESULT hr = S_OK; + LONG64 dwProvider = InterlockedAdd64(&_this->dwProvider, 0); + if (dwProvider == EP_WEATHER_PROVIDER_TEST) + { + } + else if (dwProvider == EP_WEATHER_PROVIDER_GOOGLE) + { + _this->wszScriptData = malloc(sizeof(WCHAR) * EP_WEATHER_PROVIDER_GOOGLE_SCRIPT_LEN); + if (_this->wszScriptData) + { + LONG64 dwTemperatureUnit = InterlockedAdd64(&_this->dwTemperatureUnit, 0); + LONG64 cbx = InterlockedAdd64(&_this->cbx, 0); + swprintf_s(_this->wszScriptData, EP_WEATHER_PROVIDER_GOOGLE_SCRIPT_LEN, ep_weather_provider_google_script, dwTemperatureUnit == EP_WEATHER_TUNIT_FAHRENHEIT ? L'F' : L'C', cbx, cbx); + //wprintf(L"%s\n", _this->wszScriptData); + hr = _this->pCoreWebView2->lpVtbl->ExecuteScript(_this->pCoreWebView2, _this->wszScriptData, &EPWeather_ICoreWebView2ExecuteScriptCompletedHandler); + if (FAILED(hr)) + { + InterlockedExchange64(&_this->bBrowserBusy, FALSE); + free(_this->wszScriptData); + } + } + else + { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + +HRESULT STDMETHODCALLTYPE ICoreWebView2_CreateCoreWebView2ControllerCompleted(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler* _this2, HRESULT hr, ICoreWebView2Controller* pCoreWebView2Controller) +{ + EPWeather* _this = GetWindowLongPtrW(FindWindowW(_T(EPW_WEATHER_CLASSNAME), NULL), GWLP_USERDATA); + if (!_this->pCoreWebView2Controller) + { + _this->pCoreWebView2Controller = pCoreWebView2Controller; + _this->pCoreWebView2Controller->lpVtbl->get_CoreWebView2(_this->pCoreWebView2Controller, &_this->pCoreWebView2); + _this->pCoreWebView2Controller->lpVtbl->AddRef(_this->pCoreWebView2Controller); + } + + RECT bounds; + GetClientRect(_this->hWnd, &bounds); + _this->pCoreWebView2Controller->lpVtbl->put_Bounds(_this->pCoreWebView2Controller, bounds); + + ICoreWebView2Controller2* pCoreWebView2Controller2 = NULL; + _this->pCoreWebView2Controller->lpVtbl->QueryInterface(_this->pCoreWebView2Controller, &IID_ICoreWebView2Controller2, &pCoreWebView2Controller2); + if (pCoreWebView2Controller2) + { + COREWEBVIEW2_COLOR transparent; + transparent.A = 0; + transparent.R = 0; + transparent.G = 0; + transparent.B = 0; + pCoreWebView2Controller2->lpVtbl->put_DefaultBackgroundColor(pCoreWebView2Controller2, transparent); + pCoreWebView2Controller2->lpVtbl->Release(pCoreWebView2Controller2); + } + + ICoreWebView2Settings* pCoreWebView2Settings = NULL; + _this->pCoreWebView2->lpVtbl->get_Settings(_this->pCoreWebView2, &pCoreWebView2Settings); + if (pCoreWebView2Settings) + { + ICoreWebView2Settings6* pCoreWebView2Settings6 = NULL; + pCoreWebView2Settings->lpVtbl->QueryInterface(pCoreWebView2Settings, &IID_ICoreWebView2Settings6, &pCoreWebView2Settings6); + if (pCoreWebView2Settings6) + { + pCoreWebView2Settings6->lpVtbl->put_AreDevToolsEnabled(pCoreWebView2Settings6, FALSE); + pCoreWebView2Settings6->lpVtbl->put_IsStatusBarEnabled(pCoreWebView2Settings6, FALSE); + pCoreWebView2Settings6->lpVtbl->put_IsZoomControlEnabled(pCoreWebView2Settings6, FALSE); + pCoreWebView2Settings6->lpVtbl->put_IsGeneralAutofillEnabled(pCoreWebView2Settings6, FALSE); + pCoreWebView2Settings6->lpVtbl->put_IsPasswordAutosaveEnabled(pCoreWebView2Settings6, FALSE); + pCoreWebView2Settings6->lpVtbl->put_IsPinchZoomEnabled(pCoreWebView2Settings6, FALSE); + pCoreWebView2Settings6->lpVtbl->put_IsSwipeNavigationEnabled(pCoreWebView2Settings6, FALSE); + pCoreWebView2Settings6->lpVtbl->put_AreBrowserAcceleratorKeysEnabled(pCoreWebView2Settings6, FALSE); + pCoreWebView2Settings6->lpVtbl->put_AreDefaultContextMenusEnabled(pCoreWebView2Settings6, FALSE); + pCoreWebView2Settings6->lpVtbl->put_AreDefaultScriptDialogsEnabled(pCoreWebView2Settings6, FALSE); + pCoreWebView2Settings6->lpVtbl->Release(pCoreWebView2Settings6); + } + pCoreWebView2Settings->lpVtbl->Release(pCoreWebView2Settings); + } + + _this->pCoreWebView2->lpVtbl->add_NavigationCompleted(_this->pCoreWebView2, &EPWeather_ICoreWebView2NavigationCompletedEventHandler, &_this->tkOnNavigationCompleted); + + _epw_Weather_NavigateToProvider(_this); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ICoreWebView2_NavigationCompleted(ICoreWebView2NavigationCompletedEventHandler* _this2, ICoreWebView2* pCoreWebView2, ICoreWebView2NavigationCompletedEventArgs* pCoreWebView2NavigationCompletedEventArgs) +{ + EPWeather* _this = GetWindowLongPtrW(FindWindowW(_T(EPW_WEATHER_CLASSNAME), NULL), GWLP_USERDATA); + if (_this->wszScriptData) + { + free(_this->wszScriptData); + } + BOOL bIsSuccess = FALSE; + pCoreWebView2NavigationCompletedEventArgs->lpVtbl->get_IsSuccess(pCoreWebView2NavigationCompletedEventArgs, &bIsSuccess); + if (bIsSuccess) + { + _epw_Weather_ExecuteDataScript(_this); + } + else + { + InterlockedExchange64(&_this->bBrowserBusy, FALSE); + } + _this->pCoreWebView2Controller->lpVtbl->put_IsVisible(_this->pCoreWebView2Controller, FALSE); + _this->pCoreWebView2Controller->lpVtbl->put_IsVisible(_this->pCoreWebView2Controller, TRUE); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE ICoreWebView2_ExecuteScriptCompleted(ICoreWebView2ExecuteScriptCompletedHandler* _this2, HRESULT hr, LPCWSTR pResultObjectAsJson) +{ + EPWeather* _this = GetWindowLongPtrW(FindWindowW(_T(EPW_WEATHER_CLASSNAME), NULL), GWLP_USERDATA); + if (_this) + { + //if (_this->dwType != EP_WEATHER_FETCH_RECOMPUTE) + { + epw_Weather_LockData(_this); + } + + LONG64 dwProvider = InterlockedAdd64(&_this->dwProvider, 0); + if (dwProvider == EP_WEATHER_PROVIDER_GOOGLE) + { + if (!_wcsicmp(pResultObjectAsJson, L"\"run_part_2\"")) + { + //_this->pCoreWebView2->lpVtbl->OpenDevToolsWindow(_this->pCoreWebView2); + + //printf("running part 2\n"); + _this->pCoreWebView2->lpVtbl->ExecuteScript(_this->pCoreWebView2, ep_weather_provider_google_script2, &EPWeather_ICoreWebView2ExecuteScriptCompletedHandler); + } + else + { + free(_this->wszScriptData); + _this->wszScriptData = NULL; + + //wprintf(L"%s\n", pResultObjectAsJson); + + WCHAR* wszTemperature = pResultObjectAsJson + 1; + if (wszTemperature) + { + WCHAR* wszUnit = wcschr(wszTemperature, L'#'); + if (wszUnit) + { + wszUnit[0] = 0; + wszUnit++; + WCHAR* wszCondition = wcschr(wszUnit, L'#'); + if (wszCondition) + { + wszCondition[0] = 0; + wszCondition++; + WCHAR* wszLocation = wcschr(wszCondition, L'#'); + if (wszLocation) + { + wszLocation[0] = 0; + wszLocation++; + WCHAR* pImage = wcschr(wszLocation, L'#'); + if (pImage) + { + pImage[0] = 0; + pImage++; + WCHAR* pTerm = wcschr(pImage, L'"'); + if (pTerm) + { + pTerm[0] = 0; + if (_this->wszTemperature) + { + free(_this->wszTemperature); + } + if (_this->wszUnit) + { + free(_this->wszUnit); + } + if (_this->wszCondition) + { + free(_this->wszCondition); + } + if (_this->pImage) + { + free(_this->pImage); + } + if (_this->wszLocation) + { + free(_this->wszLocation); + } + _this->cbTemperature = (wcslen(wszTemperature) + 1) * sizeof(WCHAR); + _this->wszTemperature = malloc(_this->cbTemperature); + _this->cbUnit = (wcslen(wszUnit) + 1) * sizeof(WCHAR); + _this->wszUnit = malloc(_this->cbUnit); + _this->cbCondition = (wcslen(wszCondition) + 1) * sizeof(WCHAR); + _this->wszCondition = malloc(_this->cbCondition); + _this->cbImage = wcslen(pImage) / 2; + _this->pImage = malloc(_this->cbImage); + _this->cbLocation = (wcslen(wszLocation) + 1) * sizeof(WCHAR); + _this->wszLocation = malloc(_this->cbLocation); + if (_this->wszTemperature && _this->wszUnit && _this->wszCondition && _this->pImage && _this->wszLocation) + { + wcscpy_s(_this->wszTemperature, _this->cbTemperature / 2, wszTemperature); + wcscpy_s(_this->wszUnit, _this->cbUnit / 2, wszUnit); + wcscpy_s(_this->wszCondition, _this->cbCondition / 2, wszCondition); + wcscpy_s(_this->wszLocation, _this->cbLocation / 2, wszLocation); + + for (unsigned int i = 0; i < _this->cbImage * 2; i = i + 2) + { + WCHAR tmp[3]; + tmp[0] = pImage[i]; + tmp[1] = pImage[i + 1]; + tmp[2] = 0; + _this->pImage[i / 2] = wcstol(tmp, NULL, 16); + } + } + } + } + } + } + } + } + } + } + + //DWORD dwType = _this->dwType; + //_this->dwType = EP_WEATHER_FETCH_NONE; + + epw_Weather_UnlockData(_this); + InterlockedExchange64(&_this->bBrowserBusy, FALSE); + + //if (dwType == EP_WEATHER_FETCH_ALL_ASYNC) + { + printf("[General] Fetched data, requesting redraw.\n"); + SetTimer(_this->hWnd, EP_WEATHER_TIMER_REQUEST_REPAINT, EP_WEATHER_TIMER_REQUEST_REPAINT_DELAY, NULL); + } + } + return S_OK; +} + +ULONG STDMETHODCALLTYPE epw_Weather_AddRef(EPWeather* _this) +{ + return InterlockedIncrement64(&(_this->cbCount)); +} + +ULONG STDMETHODCALLTYPE epw_Weather_Release(EPWeather* _this) +{ + ULONG value = InterlockedDecrement64(&(_this->cbCount)); + if (value == 0) + { + if (_this->hMainThread) + { + SetEvent(_this->hSignalExitMainThread); + WaitForSingleObject(_this->hMainThread, INFINITE); + CloseHandle(_this->hMainThread); + } + if (_this->hInitializeEvent) + { + CloseHandle(_this->hInitializeEvent); + } + + if (_this->hMutexData) + { + CloseHandle(_this->hMutexData); + } + + FREE(_this); + LONG dwOutstandingObjects = InterlockedDecrement(&epw_OutstandingObjects); + LONG dwOutstandingLocks = InterlockedAdd(&epw_LockCount, 0); + if (!dwOutstandingObjects && !dwOutstandingLocks) + { + } + + return(0); + } + return value; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_QueryInterface(EPWeather* _this, REFIID riid, void** ppv) +{ + if (!IsEqualIID(riid, &IID_IEPWeather) && + !IsEqualIID(riid, &IID_IUnknown)) + { + *ppv = 0; + return(E_NOINTERFACE); + } + *ppv = _this; + _this->lpVtbl->AddRef(_this); + return(NOERROR); +} + +HRESULT STDMETHODCALLTYPE epw_Weather_About(EPWeather* _this, HWND hWnd) +{ + HRESULT hr = NOERROR; + + if (SUCCEEDED(hr)) + { + hr = !_this ? (E_NOINTERFACE) : hr; + } + if (SUCCEEDED(hr)) + { + wchar_t text[MAX_PATH]; + + DWORD dwLeftMost = 0; + DWORD dwSecondLeft = 0; + DWORD dwSecondRight = 0; + DWORD dwRightMost = 0; + + QueryVersionInfo(epw_hModule, VS_VERSION_INFO, &dwLeftMost, &dwSecondLeft, &dwSecondRight, &dwRightMost); + + swprintf_s(text, MAX_PATH, L"ExplorerPatcher Weather Host\r\n\r\nVersion %d.%d.%d.%d", dwLeftMost, dwSecondLeft, dwSecondRight, dwRightMost); + + MessageBoxW(hWnd, text, _T("ExplorerPatcher Weather Host"), MB_ICONINFORMATION); + } + + return hr; +} + +LRESULT CALLBACK epw_Weather_WindowProc(_In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam) +{ + EPWeather* _this = NULL; + if (uMsg == WM_CREATE) + { + CREATESTRUCT* pCreate = (CREATESTRUCT*)(lParam); + _this = (int*)(pCreate->lpCreateParams); + SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)_this); + } + else + { + LONG_PTR ptr = GetWindowLongPtrW(hWnd, GWLP_USERDATA); + _this = (EPWeather*)(ptr); + } + if (!_this) + { + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + + if (uMsg == WM_TIMER && wParam == EP_WEATHER_TIMER_REQUEST_REPAINT) + { + HWND hNotifyWnd = InterlockedAdd64(&_this->hNotifyWnd, 0); + printf("[Timer Repaint] Request posted to window %x.\n", hNotifyWnd); + if (hNotifyWnd) + { + InvalidateRect(hNotifyWnd, NULL, TRUE); + //Sleep(100); + //InvalidateRect(hNotifyWnd, NULL, TRUE); + } + KillTimer(_this->hWnd, EP_WEATHER_TIMER_REQUEST_REPAINT); + return 0; + } + else if (uMsg == WM_TIMER && wParam == EP_WEATHER_TIMER_SCHEDULE_REFRESH) + { + if (SendMessageW(_this->hWnd, EP_WEATHER_WM_FETCH_DATA, 0, 0)) + { + printf("[Timer Scheduled Refresh] Browser is busy, waiting a minute and retrying...\n"); + KillTimer(_this->hWnd, EP_WEATHER_TIMER_SCHEDULE_REFRESH); + SetTimer(_this->hWnd, EP_WEATHER_TIMER_SCHEDULE_REFRESH, 1000 * 60, NULL); + } + else + { + KillTimer(_this->hWnd, EP_WEATHER_TIMER_SCHEDULE_REFRESH); + LONG64 dwUpdateSchedule = InterlockedAdd64(&_this->dwUpdateSchedule, 0); + printf("[Timer Scheduled Refresh] Fetching data, sleeping for %lld more ms.\n", dwUpdateSchedule); + SetTimer(_this->hWnd, EP_WEATHER_TIMER_SCHEDULE_REFRESH, dwUpdateSchedule, NULL); + } + return 0; + } + else if (uMsg == WM_TIMER && wParam == EP_WEATHER_TIMER_REBOUND_BROWSER) + { + RECT bounds; + GetClientRect(_this->hWnd, &bounds); + _this->pCoreWebView2Controller->lpVtbl->put_Bounds(_this->pCoreWebView2Controller, bounds); + KillTimer(_this->hWnd, EP_WEATHER_TIMER_REBOUND_BROWSER); + } + else if (uMsg == EP_WEATHER_WM_FETCH_DATA) + { + INT64 bWasBrowserBusy = InterlockedCompareExchange64(&_this->bBrowserBusy, TRUE, FALSE); + if (!bWasBrowserBusy) + { + return _epw_Weather_NavigateToProvider(_this); + } + return HRESULT_FROM_WIN32(ERROR_BUSY); + } + else if ((uMsg == WM_KEYUP && wParam == VK_ESCAPE) || (uMsg == WM_ACTIVATEAPP && wParam == FALSE && GetAncestor(GetForegroundWindow(), GA_ROOT) != _this->hWnd)) + { + epw_Weather_Hide(_this); + return 0; + } + else if (uMsg == WM_NCHITTEST) + { + LRESULT lRes = DefWindowProcW(hWnd, uMsg, wParam, lParam); + if (lRes == HTCAPTION) + { + return HTCLIENT; + } + } + else if (uMsg == WM_WINDOWPOSCHANGING) + { + if (IsWindowVisible(hWnd)) + { + WINDOWPOS* pwp = (WINDOWPOS*)lParam; + pwp->flags |= SWP_NOMOVE | SWP_NOSIZE; + } + return 0; + } + + /*if (uMsg == WM_CREATE) + { + SetRectEmpty(&_this->rcBorderThickness); + if (GetWindowLongPtrW(hWnd, GWL_STYLE) & WS_THICKFRAME) + { + AdjustWindowRectEx(&_this->rcBorderThickness, GetWindowLongPtr(hWnd, GWL_STYLE) & ~WS_CAPTION, FALSE, NULL); + _this->rcBorderThickness.left *= -1; + _this->rcBorderThickness.top *= -1; + } + else if (GetWindowLongPtrW(hWnd, GWL_STYLE) & WS_BORDER) + { + SetRect(&_this->rcBorderThickness, 1, 1, 1, 1); + } + SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + } + else if (uMsg == WM_NCCALCSIZE) + { + if (lParam) + { + NCCALCSIZE_PARAMS* sz = (NCCALCSIZE_PARAMS*)lParam; + sz->rgrc[0].left += _this->rcBorderThickness.left; + sz->rgrc[0].right -= _this->rcBorderThickness.right; + sz->rgrc[0].bottom -= _this->rcBorderThickness.bottom; + return 0; + } + } + else if (uMsg == WM_NCHITTEST) + { + LRESULT lRes = DefWindowProcW(hWnd, uMsg, wParam, lParam); + if (lRes == HTCLIENT) + { + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + ScreenToClient(hWnd, &pt); + if (pt.y < _this->rcBorderThickness.top) + { + return HTTOP; + } + else + { + return HTCAPTION; + } + } + else + { + return lRes; + } + } + else if (uMsg == WM_NCACTIVATE) + { + return 0; + }*/ + return DefWindowProcW(hWnd, uMsg, wParam, lParam); +} + +DWORD WINAPI epw_Weather_MainThread(EPWeather* _this) +{ + HRESULT hr = S_OK; + + SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + + _this->hrLastError = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (FAILED(_this->hrLastError)) + { + goto cleanup; + } + + _this->hrLastError = CoCreateInstance( + &CLSID_TaskbarList, + NULL, + CLSCTX_INPROC, + &IID_ITaskbarList, + (LPVOID*)&_this->pTaskList + ); + if (FAILED(_this->hrLastError)) + { + goto cleanup; + } + + WNDCLASSW wc; + ZeroMemory(&wc, sizeof(WNDCLASSW)); + wc.style = CS_DBLCLKS; + wc.lpfnWndProc = epw_Weather_WindowProc; + wc.hInstance = epw_hModule; + wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wc.lpszClassName = _T(EPW_WEATHER_CLASSNAME); + wc.hCursor = LoadCursorW(NULL, IDC_ARROW); + if (!RegisterClassW(&wc)) + { + _this->hrLastError = HRESULT_FROM_WIN32(GetLastError()); + goto cleanup; + } + + _this->hWnd = CreateWindowExW(0, _T(EPW_WEATHER_CLASSNAME), L"", WS_OVERLAPPED | WS_CAPTION, 100, 100, 825 * _this->dpi, 515 * _this->dpi, NULL, NULL, epw_hModule, _this); // 1030, 630 + if (!_this->hWnd) + { + _this->hrLastError = HRESULT_FROM_WIN32(GetLastError()); + goto cleanup; + } + + SetPropW(_this->hWnd, L"valinet.ExplorerPatcher.ShellManagedWindow", TRUE); + + _this->hrLastError = _this->pTaskList->lpVtbl->DeleteTab(_this->pTaskList, _this->hWnd); + if (FAILED(_this->hrLastError)) + { + goto cleanup; + } + + WCHAR wszWorkFolder[MAX_PATH]; + ZeroMemory(wszWorkFolder, MAX_PATH * sizeof(WCHAR)); + SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wszWorkFolder); + wcscat_s(wszWorkFolder, MAX_PATH, L"\\ExplorerPatcher\\ep_weather_host"); + BOOL bRet = CreateDirectoryW(wszWorkFolder, NULL); + if (!(bRet || (!bRet && GetLastError() == ERROR_ALREADY_EXISTS))) + { + _this->hrLastError = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); + goto cleanup; + } + + MARGINS marGlassInset = { -1, -1, -1, -1 }; // -1 means the whole window + DwmExtendFrameIntoClientArea(_this->hWnd, &marGlassInset); + BOOL value = 1; + DwmSetWindowAttribute(_this->hWnd, 1029, &value, sizeof(BOOL)); + + InterlockedExchange64(&_this->bBrowserBusy, TRUE); + + _this->hrLastError = CreateCoreWebView2EnvironmentWithOptions(NULL, wszWorkFolder, &EPWeather_ICoreWebView2EnvironmentOptions, &EPWeather_ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler); + if (FAILED(_this->hrLastError)) + { + goto cleanup; + } + + INetworkListManager* spManager = NULL; + IConnectionPointContainer* spConnectionPoints = NULL; + IConnectionPoint* spConnectionPoint = NULL; + IUnknown* spSink = NULL; + DWORD dwCookie = 0; + + if (SUCCEEDED(hr = CoCreateInstance(&CLSID_NetworkListManager, NULL, CLSCTX_ALL, &IID_INetworkListManager, &spManager) && spManager)) + { + if (SUCCEEDED(hr = spManager->lpVtbl->QueryInterface(spManager, &IID_IConnectionPointContainer, &spConnectionPoints))) + { + if (SUCCEEDED(hr = spConnectionPoints->lpVtbl->FindConnectionPoint(spConnectionPoints, &IID_INetworkListManagerEvents, &spConnectionPoint))) + { + if (SUCCEEDED(hr = INetworkListManagerEvents_Instance.lpVtbl->QueryInterface(&INetworkListManagerEvents_Instance, &IID_IUnknown, &spSink))) + { + if (SUCCEEDED(hr = spConnectionPoint->lpVtbl->Advise(spConnectionPoint, spSink, &dwCookie))) + { + } + } + } + } + } + + LONG64 dwUpdateSchedule = InterlockedAdd64(&_this->dwUpdateSchedule, 0); + SetTimer(_this->hWnd, EP_WEATHER_TIMER_SCHEDULE_REFRESH, dwUpdateSchedule, NULL); + + SetEvent(_this->hInitializeEvent); + + MSG msg; + while (TRUE) + { + DWORD dwRes = MsgWaitForMultipleObjects(EP_WEATHER_NUM_SIGNALS, &_this->hSignalExitMainThread, FALSE, INFINITE, QS_ALLINPUT); + if (dwRes == WAIT_OBJECT_0) + { + break; + } + else if (dwRes == WAIT_OBJECT_0 + EP_WEATHER_NUM_SIGNALS) + { + BOOL bRet = 0, bQuit = FALSE; + while (bRet = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (bRet == 0 || bRet == -1) + { + bQuit = TRUE; + break; + } + else + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + if (bQuit) + { + break; + } + } + else if (dwRes == WAIT_ABANDONED_0 + 1 || dwRes == WAIT_OBJECT_0 + 1) + { + CloseHandle(_this->hSignalKillSwitch); + TerminateProcess(GetCurrentProcess(), 0); + } + } + + if (SUCCEEDED(hr)) + { + spConnectionPoint->lpVtbl->Unadvise(spConnectionPoint, dwCookie); + } + if (spSink) + { + spSink->lpVtbl->Release(spSink); + } + if (spConnectionPoint) + { + spConnectionPoint->lpVtbl->Release(spConnectionPoint); + } + if (spConnectionPoints) + { + spConnectionPoints->lpVtbl->Release(spConnectionPoints); + } + if (spManager) + { + spManager->lpVtbl->Release(spManager); + } + + cleanup: + + if (_this->pCoreWebView2) + { + _this->pCoreWebView2->lpVtbl->Release(_this->pCoreWebView2); + } + if (_this->pCoreWebView2Controller) + { + _this->pCoreWebView2Controller->lpVtbl->Release(_this->pCoreWebView2Controller); + } + if (_this->cbTemperature && _this->wszTemperature) + { + free(_this->wszTemperature); + } + if (_this->cbUnit && _this->wszUnit) + { + free(_this->wszUnit); + } + if (_this->cbCondition && _this->wszCondition) + { + free(_this->wszCondition); + } + if (_this->cbImage && _this->pImage) + { + free(_this->pImage); + } + if (_this->cbLocation && _this->wszLocation) + { + free(_this->wszLocation); + } + if (_this->hWnd) + { + DestroyWindow(_this->hWnd); + } + UnregisterClassW(_T(EPW_WEATHER_CLASSNAME), epw_hModule); + if (_this->pTaskList) + { + _this->pTaskList->lpVtbl->Release(_this->pTaskList); + } + CoUninitialize(); + SetEvent(_this->hInitializeEvent); + + return 0; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_Initialize(EPWeather* _this, WCHAR wszName[MAX_PATH], BOOL bAllocConsole, LONG64 dwProvider, LONG64 cbx, LONG64 cby, LONG64 dwTemperatureUnit, LONG64 dwUpdateSchedule, double dpi) +{ + if (bAllocConsole) + { + FILE* conout; + AllocConsole(); + freopen_s( + &conout, + "CONOUT$", + "w", + stdout + ); + } + + _this->dpi = dpi; + + if (dwUpdateSchedule < 0) + { + return E_INVALIDARG; + } + InterlockedExchange64(&_this->dwUpdateSchedule, dwUpdateSchedule); + + if (dwTemperatureUnit < 0 || dwTemperatureUnit > EP_WEATHER_NUM_TUNITS) + { + return E_INVALIDARG; + } + InterlockedExchange64(&_this->dwTemperatureUnit, dwTemperatureUnit); + + if (dwProvider < 0 || dwProvider > EP_WEATHER_NUM_PROVIDERS) + { + return E_INVALIDARG; + } + InterlockedExchange64(&_this->dwProvider, dwProvider); + + if (!cbx || !cby) + { + return E_INVALIDARG; + } + InterlockedExchange64(&_this->cbx, cbx); + InterlockedExchange64(&_this->cby, cby); + + _this->hSignalKillSwitch = CreateMutexW(NULL, FALSE, wszName); + if (!_this->hSignalKillSwitch || GetLastError() != ERROR_ALREADY_EXISTS) + { + return E_INVALIDARG; + } + + _this->hMutexData = CreateMutexW(NULL, FALSE, NULL); + if (!_this->hMutexData) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + _this->hInitializeEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!_this->hInitializeEvent) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + _this->hSignalExitMainThread = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!_this->hSignalExitMainThread) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + _this->hMainThread = CreateThread(NULL, 0, epw_Weather_MainThread, _this, 0, NULL); + if (!_this->hMainThread) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + WaitForSingleObject(_this->hInitializeEvent, INFINITE); + if (FAILED(_this->hrLastError)) + { + return _this->hrLastError; + } + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_Show(EPWeather* _this) +{ + SetTimer(_this->hWnd, EP_WEATHER_TIMER_REBOUND_BROWSER, EP_WEATHER_TIMER_REBOUND_BROWSER_DELAY, NULL); + ShowWindow(_this->hWnd, SW_SHOW); + _this->pTaskList->lpVtbl->DeleteTab(_this->pTaskList, _this->hWnd); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_Hide(EPWeather* _this) +{ + ShowWindow(_this->hWnd, SW_HIDE); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_GetWindowHandle(EPWeather* _this, HWND* phWnd) +{ + *phWnd = _this->hWnd; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_LockData(EPWeather* _this) +{ + DWORD dwRes = WaitForSingleObject(_this->hMutexData, INFINITE); + if (dwRes == WAIT_ABANDONED) + { + return HRESULT_FROM_WIN32(ERROR_ABANDONED_WAIT_0); + } + else if (dwRes == WAIT_FAILED) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_GetDataSizes(EPWeather* _this, LPDWORD pcbTemperature, LPDWORD pcbUnit, LPDWORD pcbCondition, LPDWORD pcbImage) +{ + *pcbTemperature = _this->cbTemperature; + *pcbUnit = _this->cbUnit; + *pcbCondition = _this->cbCondition; + *pcbImage = _this->cbImage; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_GetData(EPWeather* _this, DWORD cbTemperature, LPCWSTR wszTemperature, DWORD cbUnit, LPCWSTR wszUnit, DWORD cbCondition, LPCWSTR wszCondition, DWORD cbImage, char* pImage) +{ + if (cbTemperature) + { + memcpy_s(wszTemperature, cbTemperature, _this->wszTemperature, _this->cbTemperature); + } + if (cbUnit) + { + memcpy_s(wszUnit, cbUnit, _this->wszUnit, _this->cbUnit); + } + if (cbCondition) + { + memcpy_s(wszCondition, cbCondition, _this->wszCondition, _this->cbCondition); + } + if (cbImage) + { + memcpy_s(pImage, cbImage, _this->pImage, _this->cbImage); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_GetTitle(EPWeather* _this, DWORD cbTitle, LPCWSTR wszTitle, DWORD dwType) +{ + WCHAR wszBuffer[MAX_PATH]; + if (cbTitle) + { + switch (dwType) + { + case EP_WEATHER_VIEW_ICONTEXT: + swprintf_s(wszBuffer, MAX_PATH, L"%s", _this->wszLocation); + break; + case EP_WEATHER_VIEW_ICONTEMP: + swprintf_s(wszBuffer, MAX_PATH, L"%s - %s", _this->wszLocation, _this->wszCondition); + break; + case EP_WEATHER_VIEW_ICONONLY: + swprintf_s(wszBuffer, MAX_PATH, L"%s %s | %s - %s", _this->wszTemperature, _this->wszUnit, _this->wszLocation, _this->wszCondition); + break; + } + memcpy_s(wszTitle, cbTitle, wszBuffer, MAX_PATH); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_UnlockData(EPWeather* _this) +{ + if (!ReleaseMutex(_this->hMutexData)) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_IsInitialized(EPWeather* _this, BOOL* bIsInitialized) +{ + *bIsInitialized = _this->hInitializeEvent; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_SetNotifyWindow(EPWeather* _this, HWND hWndNotify) +{ + InterlockedExchange64(&_this->hNotifyWnd, hWndNotify); +} + +HRESULT STDMETHODCALLTYPE epw_Weather_SetTemperatureUnit(EPWeather* _this, LONG64 dwTemperatureUnit) +{ + if (dwTemperatureUnit < 0 || dwTemperatureUnit > EP_WEATHER_NUM_TUNITS) + { + return E_INVALIDARG; + } + InterlockedExchange64(&_this->dwTemperatureUnit, dwTemperatureUnit); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_SetUpdateSchedule(EPWeather* _this, LONG64 dwUpdateSchedule) +{ + if (dwUpdateSchedule < 0) + { + return E_INVALIDARG; + } + LONG64 dwOldUpdateSchedule = InterlockedExchange64(&_this->dwUpdateSchedule, dwUpdateSchedule); + if (dwOldUpdateSchedule != dwUpdateSchedule) + { + KillTimer(_this->hWnd, EP_WEATHER_TIMER_SCHEDULE_REFRESH); + SetTimer(_this->hWnd, EP_WEATHER_TIMER_SCHEDULE_REFRESH, dwUpdateSchedule, NULL); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_SetTerm(EPWeather* _this, DWORD cbTerm, LPCWSTR wszTerm) +{ + if (cbTerm) + { + memcpy_s(_this->wszTerm, sizeof(WCHAR) * MAX_PATH, wszTerm, cbTerm); + } + else + { + ZeroMemory(&_this->wszTerm, sizeof(WCHAR) * MAX_PATH); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_SetLanguage(EPWeather* _this, DWORD cbLanguage, LPCWSTR wszLanguage) +{ + if (cbLanguage) + { + memcpy_s(_this->wszLanguage, sizeof(WCHAR) * MAX_PATH, wszLanguage, cbLanguage); + } + else + { + ZeroMemory(&_this->wszLanguage, sizeof(WCHAR) * MAX_PATH); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_SetIconSize(EPWeather* _this, LONG64 cbx, LONG64 cby) +{ + DWORD dwOldX = InterlockedAdd64(&_this->cbx, 0); + DWORD dwOldY = InterlockedAdd64(&_this->cby, 0); + if (dwOldX != cbx) + { + InterlockedExchange64(&_this->cbx, cbx); + InterlockedExchange64(&_this->cby, cby); + PostMessageW(_this->hWnd, EP_WEATHER_WM_FETCH_DATA, 0, 0); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE epw_Weather_GetIconSize(EPWeather* _this, LONG64* cbx, LONG64* cby) +{ + if (cbx) *cbx = InterlockedAdd64(&_this->cbx, 0); + if (cby) *cby = InterlockedAdd64(&_this->cby, 0); + return S_OK; +} \ No newline at end of file diff --git a/ep_weather_host/ep_weather_host.h b/ep_weather_host/ep_weather_host.h new file mode 100644 index 0000000..29b65de --- /dev/null +++ b/ep_weather_host/ep_weather_host.h @@ -0,0 +1,210 @@ +#ifndef _H_AS_SERVICE_P_H_ +#define _H_AS_SERVICE_P_H_ +#include "ep_weather.h" +#include "ep_weather_utility.h" +#include "../ep_weather_host_stub/ep_weather_host_h.h" +#include +#include +#include +#include +#pragma comment(lib, "Dwmapi.lib") +#include +#include +#pragma comment(lib, "IPHLPAPI.lib") +#include "WebView2.h" + +DEFINE_GUID(IID_ITaskbarList, + 0x56FDF342, 0xFD6D, 0x11d0, 0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90); + +#define EP_WEATHER_NUM_SIGNALS 2 + +#define EP_WEATHER_TIMER_REQUEST_REPAINT 1 +#define EP_WEATHER_TIMER_REQUEST_REPAINT_DELAY 1000 +#define EP_WEATHER_TIMER_REBOUND_BROWSER 2 +#define EP_WEATHER_TIMER_REBOUND_BROWSER_DELAY 1 +#define EP_WEATHER_TIMER_SCHEDULE_REFRESH 10 + +typedef interface EPWeather +{ + CONST_VTBL IEPWeatherVtbl* lpVtbl; + unsigned int cbCount; + HRESULT hrLastError; + HANDLE hMainThread; + HANDLE hInitializeEvent; + HWND hWnd; + + INT64 bBrowserBusy; // interlocked + HWND hNotifyWnd; // interlocked + LONG64 dwTemperatureUnit; // interlocked + LONG64 dwUpdateSchedule; // interlocked + WCHAR wszTerm[MAX_PATH]; + WCHAR wszLanguage[MAX_PATH]; + LONG64 cbx; // interlocked + LONG64 cby; // interlocked + LONG64 dwProvider; // interlocked + + double dpi; + + HANDLE hMutexData; // protects the following: + DWORD cbTemperature; + LPCWSTR wszTemperature; + DWORD cbUnit; + LPCWSTR wszUnit; + DWORD cbCondition; + LPCWSTR wszCondition; + DWORD cbImage; + char* pImage; + DWORD cbLocation; + LPCWSTR wszLocation; + + RECT rcBorderThickness; // local variables: + ITaskbarList* pTaskList; + ICoreWebView2Controller* pCoreWebView2Controller; + ICoreWebView2* pCoreWebView2; + EventRegistrationToken* tkOnNavigationCompleted; + LPCWSTR wszScriptData; + + HANDLE hSignalExitMainThread; + HANDLE hSignalKillSwitch; +} EPWeather; + +ULONG STDMETHODCALLTYPE epw_Weather_AddRef(EPWeather* _this); +ULONG STDMETHODCALLTYPE epw_Weather_Release(EPWeather* _this); +HRESULT STDMETHODCALLTYPE epw_Weather_QueryInterface(EPWeather* _this, REFIID riid, void** ppv); +HRESULT STDMETHODCALLTYPE epw_Weather_About(EPWeather* _this, HWND hWnd); + +HRESULT STDMETHODCALLTYPE epw_Weather_Initialize(EPWeather* _this, WCHAR wszName[MAX_PATH], BOOL bAllocConsole, LONG64 dwProvider, LONG64 cbx, LONG64 cby, LONG64 dwTemperatureUnit, LONG64 dwUpdateSchedule, double dpi); + +HRESULT STDMETHODCALLTYPE epw_Weather_Show(EPWeather* _this); +HRESULT STDMETHODCALLTYPE epw_Weather_Hide(EPWeather* _this); +HRESULT STDMETHODCALLTYPE epw_Weather_GetWindowHandle(EPWeather* _this, HWND* phWnd); +HRESULT STDMETHODCALLTYPE epw_Weather_IsInitialized(EPWeather* _this, BOOL* bIsInitialized); + +HRESULT STDMETHODCALLTYPE epw_Weather_LockData(EPWeather* _this); +HRESULT STDMETHODCALLTYPE epw_Weather_GetDataSizes(EPWeather* _this, LPDWORD pcbTemperature, LPDWORD pcbUnit, LPDWORD pcbCondition, LPDWORD pcbImage); +HRESULT STDMETHODCALLTYPE epw_Weather_GetData(EPWeather* _this, DWORD cbTemperature, LPCWSTR wszTemperature, DWORD cbUnit, LPCWSTR wszUnit, DWORD cbCondition, LPCWSTR wszCondition, DWORD cbImage, char* pImage); +HRESULT STDMETHODCALLTYPE epw_Weather_GetTitle(EPWeather* _this, DWORD cbTitle, LPCWSTR wszTitle, DWORD dwType); +HRESULT STDMETHODCALLTYPE epw_Weather_UnlockData(EPWeather* _this); + +HRESULT STDMETHODCALLTYPE epw_Weather_SetNotifyWindow(EPWeather* _this, HWND hWndNotify); +HRESULT STDMETHODCALLTYPE epw_Weather_SetTemperatureUnit(EPWeather* _this, LONG64 dwTemperatureUnit); +HRESULT STDMETHODCALLTYPE epw_Weather_SetUpdateSchedule(EPWeather* _this, LONG64 dwUpdateSchedule); +HRESULT STDMETHODCALLTYPE epw_Weather_SetTerm(EPWeather* _this, DWORD cbTerm, LPCWSTR wszTerm); +HRESULT STDMETHODCALLTYPE epw_Weather_SetLanguage(EPWeather* _this, DWORD cbLanguage, LPCWSTR wszLanguage); +HRESULT STDMETHODCALLTYPE epw_Weather_SetIconSize(EPWeather* _this, LONG64 cbx, LONG64 cby); +HRESULT STDMETHODCALLTYPE epw_Weather_GetIconSize(EPWeather* _this, LONG64* cbx, LONG64* cby); + +static const IEPWeatherVtbl IEPWeather_Vtbl = { + .QueryInterface = epw_Weather_QueryInterface, + .AddRef = epw_Weather_AddRef, + .Release = epw_Weather_Release, + .About = epw_Weather_About, + .Initialize = epw_Weather_Initialize, + .Show = epw_Weather_Show, + .Hide = epw_Weather_Hide, + .GetWindowHandle = epw_Weather_GetWindowHandle, + .LockData = epw_Weather_LockData, + .GetDataSizes = epw_Weather_GetDataSizes, + .GetData = epw_Weather_GetData, + .UnlockData = epw_Weather_UnlockData, + .SetNotifyWindow = epw_Weather_SetNotifyWindow, + .IsInitialized = epw_Weather_IsInitialized, + .GetTitle = epw_Weather_GetTitle, + .SetTemperatureUnit = epw_Weather_SetTemperatureUnit, + .SetTerm = epw_Weather_SetTerm, + .SetLanguage = epw_Weather_SetLanguage, + .SetIconSize = epw_Weather_SetIconSize, + .GetIconSize = epw_Weather_GetIconSize, + .SetUpdateSchedule = epw_Weather_SetUpdateSchedule, +}; + +HRESULT STDMETHODCALLTYPE epw_Weather_static_Stub(void* _this); +ULONG STDMETHODCALLTYPE epw_Weather_static_AddRefRelease(EPWeather* _this); +HRESULT STDMETHODCALLTYPE epw_Weather_static_QueryInterface(EPWeather* _this, REFIID riid, void** ppv); + +HRESULT STDMETHODCALLTYPE ICoreWebView2_CreateCoreWebView2EnvironmentCompleted(ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler* _this, HRESULT errorCode, ICoreWebView2Environment* pCoreWebView2Environment); +HRESULT STDMETHODCALLTYPE ICoreWebView2_CreateCoreWebView2ControllerCompleted(ICoreWebView2CreateCoreWebView2ControllerCompletedHandler* _this, HRESULT hr, ICoreWebView2Controller* pCoreWebView2Controller); +HRESULT STDMETHODCALLTYPE ICoreWebView2_NavigationCompleted(ICoreWebView2NavigationCompletedEventHandler* _this, ICoreWebView2* pCoreWebView2, ICoreWebView2NavigationCompletedEventArgs* pCoreWebView2NavigationCompletedEventArgs); +HRESULT STDMETHODCALLTYPE ICoreWebView2_ExecuteScriptCompleted(ICoreWebView2ExecuteScriptCompletedHandler* _this, HRESULT hr, LPCWSTR pResultObjectAsJson); +HRESULT STDMETHODCALLTYPE ICoreWebView2_get_AdditionalBrowserArguments(ICoreWebView2EnvironmentOptions* _this, LPWSTR* value); +HRESULT STDMETHODCALLTYPE ICoreWebView2_get_Language(ICoreWebView2EnvironmentOptions* _this, LPWSTR* value); +HRESULT STDMETHODCALLTYPE ICoreWebView2_get_TargetCompatibleBrowserVersion(ICoreWebView2EnvironmentOptions* _this, LPWSTR* value); +HRESULT STDMETHODCALLTYPE ICoreWebView2_get_AllowSingleSignOnUsingOSPrimaryAccount(ICoreWebView2EnvironmentOptions* _this, BOOL* allow); + +static const ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl EPWeather_ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl = { + .QueryInterface = epw_Weather_static_QueryInterface, + .AddRef = epw_Weather_static_AddRefRelease, + .Release = epw_Weather_static_AddRefRelease, + .Invoke = ICoreWebView2_CreateCoreWebView2EnvironmentCompleted, +}; + +static const ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler EPWeather_ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler = { + &EPWeather_ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandlerVtbl +}; + +static const ICoreWebView2CreateCoreWebView2ControllerCompletedHandlerVtbl EPWeather_ICoreWebView2CreateCoreWebView2ControllerCompletedHandlerVtbl = { + .QueryInterface = epw_Weather_static_QueryInterface, + .AddRef = epw_Weather_static_AddRefRelease, + .Release = epw_Weather_static_AddRefRelease, + .Invoke = ICoreWebView2_CreateCoreWebView2ControllerCompleted, +}; + +static const ICoreWebView2CreateCoreWebView2ControllerCompletedHandler EPWeather_ICoreWebView2CreateCoreWebView2ControllerCompletedHandler = { + &EPWeather_ICoreWebView2CreateCoreWebView2ControllerCompletedHandlerVtbl +}; + +static const ICoreWebView2NavigationCompletedEventHandlerVtbl EPWeather_ICoreWebView2NavigationCompletedEventHandlerVtbl = { + .QueryInterface = epw_Weather_static_QueryInterface, + .AddRef = epw_Weather_static_AddRefRelease, + .Release = epw_Weather_static_AddRefRelease, + .Invoke = ICoreWebView2_NavigationCompleted, +}; + +static const ICoreWebView2NavigationCompletedEventHandler EPWeather_ICoreWebView2NavigationCompletedEventHandler = { + &EPWeather_ICoreWebView2NavigationCompletedEventHandlerVtbl +}; + +static const ICoreWebView2ExecuteScriptCompletedHandlerVtbl EPWeather_ICoreWebView2ExecuteScriptCompletedHandlerVtbl = { + .QueryInterface = epw_Weather_static_QueryInterface, + .AddRef = epw_Weather_static_AddRefRelease, + .Release = epw_Weather_static_AddRefRelease, + .Invoke = ICoreWebView2_ExecuteScriptCompleted, +}; + +static const ICoreWebView2ExecuteScriptCompletedHandler EPWeather_ICoreWebView2ExecuteScriptCompletedHandler = { + &EPWeather_ICoreWebView2ExecuteScriptCompletedHandlerVtbl +}; + +static const ICoreWebView2EnvironmentOptionsVtbl EPWeather_ICoreWebView2EnvironmentOptionsVtbl = { + .QueryInterface = epw_Weather_static_QueryInterface, + .AddRef = epw_Weather_static_AddRefRelease, + .Release = epw_Weather_static_AddRefRelease, + .get_AdditionalBrowserArguments = ICoreWebView2_get_AdditionalBrowserArguments, + .put_AdditionalBrowserArguments = epw_Weather_static_Stub, + .get_Language = ICoreWebView2_get_Language, + .put_Language = epw_Weather_static_Stub, + .get_TargetCompatibleBrowserVersion = ICoreWebView2_get_TargetCompatibleBrowserVersion, + .put_TargetCompatibleBrowserVersion = epw_Weather_static_Stub, + .get_AllowSingleSignOnUsingOSPrimaryAccount = ICoreWebView2_get_AllowSingleSignOnUsingOSPrimaryAccount, + .put_AllowSingleSignOnUsingOSPrimaryAccount = epw_Weather_static_Stub, +}; + +static const ICoreWebView2EnvironmentOptions EPWeather_ICoreWebView2EnvironmentOptions = { + &EPWeather_ICoreWebView2EnvironmentOptionsVtbl +}; + +HRESULT STDMETHODCALLTYPE INetworkListManagerEvents_QueryInterface(void* _this, REFIID riid, void** ppv); +ULONG STDMETHODCALLTYPE INetworkListManagerEvents_AddRefRelease(void* _this); +HRESULT STDMETHODCALLTYPE INetworkListManagerEvents_ConnectivityChanged(void* _this, NLM_CONNECTIVITY newConnectivity); + +static const INetworkListManagerEventsVtbl INetworkListManagerEvents_Vtbl = { + .QueryInterface = INetworkListManagerEvents_QueryInterface, + .AddRef = INetworkListManagerEvents_AddRefRelease, + .Release = INetworkListManagerEvents_AddRefRelease, + .ConnectivityChanged = INetworkListManagerEvents_ConnectivityChanged, +}; + +static const INetworkListManagerEvents INetworkListManagerEvents_Instance = { + .lpVtbl = &INetworkListManagerEvents_Vtbl, +}; +#endif diff --git a/ep_weather_host/ep_weather_host.rc b/ep_weather_host/ep_weather_host.rc new file mode 100644 index 0000000..53e0932 --- /dev/null +++ b/ep_weather_host/ep_weather_host.rc @@ -0,0 +1,100 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "VALINET Solutions SRL" + VALUE "FileDescription", "ExplorerPatcher Weather Host" + VALUE "FileVersion", "1.0.0.0" + VALUE "InternalName", "ep_weather_host.exe" + VALUE "LegalCopyright", "Copyright (C) 2006-2022 VALINET Solutions SRL. All rights reserved." + VALUE "OriginalFilename", "ep_weather_host.exe" + VALUE "ProductName", "ExplorerPatcher" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/ep_weather_host/ep_weather_host.vcxproj b/ep_weather_host/ep_weather_host.vcxproj new file mode 100644 index 0000000..cf3b567 --- /dev/null +++ b/ep_weather_host/ep_weather_host.vcxproj @@ -0,0 +1,183 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {314a50c1-f0a0-4d0c-89e1-ad8f3951043e} + epweatherhost + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(Configuration) + + + false + $(SolutionDir)\build\$(Configuration) + + + true + $(SolutionDir)\build\$(Configuration) + + + false + $(SolutionDir)\build\$(Configuration) + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDebug + + + Windows + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDebug + + + Windows + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/ep_weather_host/ep_weather_host.vcxproj.filters b/ep_weather_host/ep_weather_host.vcxproj.filters new file mode 100644 index 0000000..8277af6 --- /dev/null +++ b/ep_weather_host/ep_weather_host.vcxproj.filters @@ -0,0 +1,67 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Source Files + + + + + + \ No newline at end of file diff --git a/ep_weather_host/ep_weather_provider_google_html.h b/ep_weather_host/ep_weather_provider_google_html.h new file mode 100644 index 0000000..16f4804 --- /dev/null +++ b/ep_weather_host/ep_weather_provider_google_html.h @@ -0,0 +1,51 @@ +#ifndef _H_EP_WEATHER_PROVIDER_GOOGLE_HTML_H_ +#define _H_EP_WEATHER_PROVIDER_GOOGLE_HTML_H_ +#include +#define EP_WEATHER_PROVIDER_GOOGLE_HTML_LEN 2000 +LPCWSTR ep_weather_provider_google_html = L"\ +\n\ +\n\ +\n\ +\n\ +Weather\n\ +\n\ +\n\ +\n\ +
\n\ +
\n\ +\n\ +
\n\ +
\n\ +\n\ +"; +#endif \ No newline at end of file diff --git a/ep_weather_host/ep_weather_provider_google_script.h b/ep_weather_host/ep_weather_provider_google_script.h new file mode 100644 index 0000000..d3c7da3 --- /dev/null +++ b/ep_weather_host/ep_weather_provider_google_script.h @@ -0,0 +1,93 @@ +#ifndef _H_EP_WEATHER_PROVIDER_GOOGLE_SCRIPT_H_ +#define _H_EP_WEATHER_PROVIDER_GOOGLE_SCRIPT_H_ +#include +// many thanks to https://stackoverflow.com/questions/23202966/google-weather-widget-on-my-website +#define EP_WEATHER_PROVIDER_GOOGLE_SCRIPT_LEN 4000 +LPCWSTR ep_weather_provider_google_script = L"\ +function ep_weather_utf8ToHex(str) {\n\ + return Array.from(str).map(c => \n\ + c.charCodeAt(0) < 128 ? c.charCodeAt(0).toString(16) : \n\ + encodeURIComponent(c).replace(/\\%%/g,'').toLowerCase()\n\ + ).join('');\n\ +}\n\ +function ep_weather_drawImageToCanvas(image) {\n\ + const canvas = document.createElement('canvas');\n\ + const w = image.width;\n\ + const h = image.height;\n\ + canvas.width = w;\n\ + canvas.height = h;\n\ + canvas.getContext('2d').drawImage(image, 0, 0);\n\ + return canvas;\n\ +}\n\ +function ep_weather_toHexString (byteArray) {\n\ + //const chars = new Buffer(byteArray.length * 2);\n\ + const chars = new Uint8Array(byteArray.length * 2);\n\ + const alpha = 'a'.charCodeAt(0) - 10;\n\ + const digit = '0'.charCodeAt(0);\n\ + \n\ + let p = 0;\n\ + for (let i = 0; i < byteArray.length; i++) {\n\ + let nibble = byteArray[i] >>> 4;\n\ + chars[p++] = nibble > 9 ? nibble + alpha : nibble + digit;\n\ + nibble = byteArray[i] & 0xF;\n\ + chars[p++] = nibble > 9 ? nibble + alpha : nibble + digit;\n\ + }\n\ + \n\ + //return chars.toString('utf8');\n\ + return String.fromCharCode.apply(null, chars);\n\ +}\n\ +function ep_weather_getData(imageBitmap, ch) {\n\ + const canvas = ep_weather_drawImageToCanvas(imageBitmap);\n\ + const ctx = canvas.getContext('2d');\n\ + \n\ + let result = [];\n\ + for (let y = 0; y < canvas.height; y++) {\n\ + for (let x = 0; x < canvas.width; x++) {\n\ + let data = ctx.getImageData(x, y, 1, 1).data;\n\ + result.push(data[2] * data[3] / 255);\n\ + result.push(data[1] * data[3] / 255);\n\ + result.push(data[0] * data[3] / 255);\n\ + result.push(data[3]);\n\ + }\n\ + }\n\ + let res = (\n\ + document.getElementById(\"frame\").contentWindow.document.getElementById(ch.includes('x') ? \"wob_ttm\" : \"wob_tm\").innerText + \"#\" + \n\ + Array.from(document.getElementById(\"frame\").contentWindow.document.getElementsByClassName('wob-unit')[0].getElementsByTagName('span')).filter(e => e.className == 'wob_t').filter(e => !e.style.display.toString().includes(\"none\"))[0].innerText + \"#\" + \n\ + document.getElementById(\"frame\").contentWindow.document.getElementById(\"wob_tci\").alt + \"#\" + \n\ + document.getElementById(\"frame\").contentWindow.document.getElementById(\"wob_loc\").innerText + \"#\" + \n\ + ep_weather_toHexString(result)\n\ + );\n\ + console.log(res);\n\ + document.body.style.backgroundColor='transparent';\n\ + document.getElementById(\"frame\").contentWindow.document.body.style.backgroundColor='transparent';\n\ + return res;\n\ +}\n\ +var ep_result;\n\ +let unit = Array.from(document.getElementById(\"frame\").contentWindow.document.getElementsByClassName('wob-unit')[0].getElementsByTagName('span')).filter(e => e.className == 'wob_t')[0].innerText;\n\ +let p = '%c';\n\ +if (!unit.includes(p)) {\n\ + Array.from(document.getElementById(\"frame\").contentWindow.document.getElementsByClassName('wob-unit')[0].getElementsByTagName('a')).filter(e => e.className == 'wob_t').filter(e => e.innerText.includes(p))[0].click();\n\ + unit = 'x';\n\ +}\n\ +createImageBitmap(\n\ + document.getElementById(\"frame\").contentWindow.document.getElementById('wob_tci'), \n\ + { resizeWidth: %d, resizeHeight: %d, resizeQuality: 'high' }\n\ +)\n\ +.then(imageBitmap => \n\ + ep_result = ep_weather_getData(imageBitmap, unit)\n\ +);\n\ +function ep_weather_part1() {\n\ +return \"run_part_2\";\n\ +}\n\ +ep_weather_part1();\n\ +"; + +LPCWSTR ep_weather_provider_google_script2 = L"\ +function ep_weather_part2() {\n\ +document.getElementById(\"frame\").contentWindow.document.getElementsByClassName(\"KFFQ0c\")[0].style.display = 'none';\n\ +document.getElementById(\"frame\").contentWindow.document.getElementById(\"search\").scrollIntoView(true);\n\ +return ep_result;\n\ +}\n\ +ep_weather_part2();\n\ +"; +#endif \ No newline at end of file diff --git a/ep_weather_host/ep_weather_utility.h b/ep_weather_host/ep_weather_utility.h new file mode 100644 index 0000000..ed899f7 --- /dev/null +++ b/ep_weather_host/ep_weather_utility.h @@ -0,0 +1,34 @@ +#ifndef _H_EP_WEATHER_UTILITY_H_ +#define _H_EP_WEATHER_UTILITY_H_ +#include +#include +inline void QueryVersionInfo(HMODULE hModule, WORD Resource, DWORD* dwLeftMost, DWORD* dwSecondLeft, DWORD* dwSecondRight, DWORD* dwRightMost) +{ + HRSRC hResInfo; + DWORD dwSize; + HGLOBAL hResData; + LPVOID pRes, pResCopy; + UINT uLen; + VS_FIXEDFILEINFO* lpFfi; + + hResInfo = FindResource(hModule, MAKEINTRESOURCE(Resource), RT_VERSION); + dwSize = SizeofResource(hModule, hResInfo); + hResData = LoadResource(hModule, hResInfo); + pRes = LockResource(hResData); + pResCopy = LocalAlloc(LMEM_FIXED, dwSize); + CopyMemory(pResCopy, pRes, dwSize); + FreeResource(hResData); + + VerQueryValue(pResCopy, TEXT("\\"), (LPVOID*)&lpFfi, &uLen); + + DWORD dwFileVersionMS = lpFfi->dwFileVersionMS; + DWORD dwFileVersionLS = lpFfi->dwFileVersionLS; + + *dwLeftMost = HIWORD(dwFileVersionMS); + *dwSecondLeft = LOWORD(dwFileVersionMS); + *dwSecondRight = HIWORD(dwFileVersionLS); + *dwRightMost = LOWORD(dwFileVersionLS); + + LocalFree(pResCopy); +} +#endif \ No newline at end of file diff --git a/ep_weather_host/packages.config b/ep_weather_host/packages.config new file mode 100644 index 0000000..81668dc --- /dev/null +++ b/ep_weather_host/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ep_weather_host/resource.h b/ep_weather_host/resource.h new file mode 100644 index 0000000..e664c61 --- /dev/null +++ b/ep_weather_host/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ep_weather_host.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/ep_weather_host_stub/ep_weather_host.idl b/ep_weather_host_stub/ep_weather_host.idl new file mode 100644 index 0000000..5498d73 --- /dev/null +++ b/ep_weather_host_stub/ep_weather_host.idl @@ -0,0 +1,61 @@ +import "oaidl.idl"; +import "ocidl.idl"; +import "unknwn.idl"; + +[ + object, + uuid(CDBF3734-F847-4F1B-B953-A605434DC1E7), + oleautomation, + helpstring("ExplorerPatcher Weather Information") +] interface IEPWeather : IUnknown +{ + HRESULT About([in] HWND hWnd); + + HRESULT Initialize([in] WCHAR wszName[260], [in] BOOL bAllocConsole, [in] LONG64 dwProvider, [in] LONG64 cbx, [in] LONG64 cby, [in] LONG64 dwTemperatureUnit, [in] LONG64 dwUpdateSchedule, [in] double dpi); + + HRESULT Show(); + + HRESULT Hide(); + + HRESULT GetWindowHandle([out] HWND* phWnd); + + HRESULT LockData(); + + HRESULT GetDataSizes( + [out] LPDWORD pcbTemperature, + [out] LPDWORD pcbUnit, + [out] LPDWORD pcbCondition, + [out] LPDWORD pcbImage + ); + + HRESULT GetData( + [in] DWORD cbTemperature, + [out, size_is(cbTemperature)] BYTE* wszTemperature, + [in] DWORD cbUnit, + [ out, size_is(cbUnit)] BYTE* wszUnit, + [in] DWORD cbCondition, + [out, size_is(cbCondition)] BYTE* wszCondition, + [in] DWORD cbImage, + [out, size_is(cbImage)] BYTE* pImage + ); + + HRESULT UnlockData(); + + HRESULT SetNotifyWindow([in] HWND hWndNotify); + + HRESULT IsInitialized([out] BOOL* bIsInitialized); + + HRESULT GetTitle([in] DWORD cbTitle, [out, size_is(cbTitle)] BYTE* wszTitle, [in] DWORD dwType); + + HRESULT SetTemperatureUnit([in] LONG64 dwTemperatureUnit); + + HRESULT SetTerm([in] DWORD cbTerm, [in, size_is(cbTerm)] BYTE* wszTerm); + + HRESULT SetLanguage([in] DWORD cblanguage, [in, size_is(cblanguage)] BYTE* wszLanguage); + + HRESULT SetUpdateSchedule([in] LONG64 dwUpdateSchedule); + + HRESULT SetIconSize([in] LONG64 cbx, [in] LONG64 cby); + + HRESULT GetIconSize([out] LONG64* cbx, [out] LONG64* cby); +}; \ No newline at end of file diff --git a/ep_weather_host_stub/ep_weather_host_stub.def b/ep_weather_host_stub/ep_weather_host_stub.def new file mode 100644 index 0000000..b21e017 --- /dev/null +++ b/ep_weather_host_stub/ep_weather_host_stub.def @@ -0,0 +1,6 @@ +LIBRARY ep_weather_host_stub.dll +DESCRIPTION 'ExplorerPatcher Weather Stub DLL' +EXPORTS DllGetClassObject @1 PRIVATE + DllCanUnloadNow @2 PRIVATE + DllRegisterServer @4 PRIVATE + DllUnregisterServer @5 PRIVATE \ No newline at end of file diff --git a/ep_weather_host_stub/ep_weather_host_stub.vcxproj b/ep_weather_host_stub/ep_weather_host_stub.vcxproj new file mode 100644 index 0000000..550457b --- /dev/null +++ b/ep_weather_host_stub/ep_weather_host_stub.vcxproj @@ -0,0 +1,180 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {af02abac-eaeb-471c-9957-73d430b8b4de} + epweatherhoststub + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(Configuration) + + + false + $(SolutionDir)\build\$(Configuration) + + + true + $(SolutionDir)\build\$(Configuration) + + + false + $(SolutionDir)\build\$(Configuration) + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + RpcRT4.lib;%(AdditionalDependencies) + ep_weather_host_stub.def + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + RpcRT4.lib;%(AdditionalDependencies) + ep_weather_host_stub.def + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + RpcRT4.lib;%(AdditionalDependencies) + ep_weather_host_stub.def + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + RpcRT4.lib;%(AdditionalDependencies) + ep_weather_host_stub.def + + + + + + + + REGISTER_PROXY_DLL;%(PreprocessorDefinitions) + REGISTER_PROXY_DLL;%(PreprocessorDefinitions) + REGISTER_PROXY_DLL;%(PreprocessorDefinitions) + REGISTER_PROXY_DLL;%(PreprocessorDefinitions) + + + + REGISTER_PROXY_DLL;%(PreprocessorDefinitions) + REGISTER_PROXY_DLL;%(PreprocessorDefinitions) + REGISTER_PROXY_DLL;%(PreprocessorDefinitions) + REGISTER_PROXY_DLL;%(PreprocessorDefinitions) + + + + + + + + + + + + \ No newline at end of file diff --git a/ep_weather_host_stub/ep_weather_host_stub.vcxproj.filters b/ep_weather_host_stub/ep_weather_host_stub.vcxproj.filters new file mode 100644 index 0000000..f47935c --- /dev/null +++ b/ep_weather_host_stub/ep_weather_host_stub.vcxproj.filters @@ -0,0 +1,43 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/libs/sws b/libs/sws index ebbdacb..a3e51eb 160000 --- a/libs/sws +++ b/libs/sws @@ -1 +1 @@ -Subproject commit ebbdacbcabd8e0a50c470f07ccf3796d01f7324a +Subproject commit a3e51eb335f2421d137cc9bb89ec10ca54103dd1 diff --git a/version.h b/version.h index 5b861a7..adc681c 100644 --- a/version.h +++ b/version.h @@ -1,7 +1,7 @@ #define VER_MAJOR 22000 #define VER_MINOR 469 -#define VER_BUILD_HI 41 -#define VER_BUILD_LO 16 +#define VER_BUILD_HI 42 +#define VER_BUILD_LO 0 #define VER_FLAGS VS_FF_PRERELEASE @@ -12,5 +12,5 @@ #define VER_STR(arg) #arg // The String form of the version numbers -#define VER_FILE_STRING VALUE "FileVersion", "22000.469.41.16" -#define VER_PRODUCT_STRING VALUE "ProductVersion", "22000.469.41.16" +#define VER_FILE_STRING VALUE "FileVersion", "22000.469.42.0" +#define VER_PRODUCT_STRING VALUE "ProductVersion", "22000.469.42.0"