2021-10-01 01:26:10 +03:00
|
|
|
#include "utility.h"
|
2022-02-20 18:14:07 +02:00
|
|
|
#include <Wininet.h>
|
|
|
|
#pragma comment(lib, "Wininet.lib")
|
2021-10-01 01:26:10 +03:00
|
|
|
|
2022-03-05 06:56:09 +02:00
|
|
|
RTL_OSVERSIONINFOW global_rovi;
|
2022-03-06 00:04:30 +02:00
|
|
|
DWORD32 global_ubr;
|
2022-03-05 06:56:09 +02:00
|
|
|
|
2021-10-01 01:26:10 +03:00
|
|
|
#pragma region "Weird stuff"
|
2021-11-14 18:29:07 +02:00
|
|
|
INT64 STDMETHODCALLTYPE nimpl4_1(INT64 a1, DWORD* a2)
|
2021-10-01 01:26:10 +03:00
|
|
|
{
|
|
|
|
*a2 = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2021-11-14 18:29:07 +02:00
|
|
|
INT64 STDMETHODCALLTYPE nimpl4_0(INT64 a1, DWORD* a2)
|
2021-10-01 01:26:10 +03:00
|
|
|
{
|
|
|
|
*a2 = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
2021-11-14 18:29:07 +02:00
|
|
|
__int64 STDMETHODCALLTYPE nimpl2(__int64 a1, uintptr_t* a2)
|
2021-10-01 01:26:10 +03:00
|
|
|
{
|
|
|
|
__int64 v2; // rax
|
|
|
|
|
|
|
|
v2 = a1 + 8;
|
|
|
|
if (!a1)
|
|
|
|
v2 = 0i64;
|
|
|
|
|
|
|
|
*a2 = v2;
|
|
|
|
return 0i64;
|
|
|
|
}
|
2021-11-14 18:29:07 +02:00
|
|
|
ULONG STDMETHODCALLTYPE nimpl3()
|
2021-10-01 01:26:10 +03:00
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
2021-11-14 18:29:07 +02:00
|
|
|
HRESULT STDMETHODCALLTYPE nimpl()
|
2021-10-01 01:26:10 +03:00
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
2021-11-14 18:29:07 +02:00
|
|
|
HRESULT STDMETHODCALLTYPE nimpl1(__int64 a1, uintptr_t* a2, uintptr_t* a3)
|
2021-10-01 01:26:10 +03:00
|
|
|
{
|
|
|
|
__int64 v4 = a1; // rcx
|
|
|
|
|
|
|
|
if (*a2 != 0x5FADCA5C34A95314i64 || a2[1] != 0xC1661118901A7CAEui64)
|
|
|
|
return E_NOTIMPL;
|
|
|
|
|
|
|
|
*a3 = v4;
|
|
|
|
return S_OK;
|
|
|
|
}
|
2021-11-14 18:29:07 +02:00
|
|
|
HRESULT STDMETHODCALLTYPE nimpl1_2(__int64 a1, uintptr_t* a2, uintptr_t* a3)
|
2021-10-01 01:26:10 +03:00
|
|
|
{
|
|
|
|
__int64 v4 = a1 - sizeof(__int64); // rcx
|
|
|
|
|
|
|
|
if (*a2 != 0x5FADCA5C34A95314i64 || a2[1] != 0xC1661118901A7CAEui64)
|
|
|
|
return E_NOTIMPL;
|
|
|
|
|
|
|
|
*a3 = v4;
|
|
|
|
return S_OK;
|
|
|
|
}
|
2021-11-14 18:29:07 +02:00
|
|
|
HRESULT STDMETHODCALLTYPE nimpl1_3(__int64 a1, uintptr_t* a2, uintptr_t* a3)
|
2021-10-01 01:26:10 +03:00
|
|
|
{
|
|
|
|
__int64 v4 = a1 - 2 * sizeof(__int64); // rcx
|
|
|
|
|
|
|
|
if (*a2 != 0x5FADCA5C34A95314i64 || a2[1] != 0xC1661118901A7CAEui64)
|
|
|
|
return E_NOTIMPL;
|
|
|
|
|
|
|
|
*a3 = v4;
|
|
|
|
return S_OK;
|
|
|
|
}
|
2021-11-14 18:29:07 +02:00
|
|
|
__int64 STDMETHODCALLTYPE nimpl4(__int64 a1, __int64 a2, __int64 a3, BYTE* a4)
|
2021-10-01 01:26:10 +03:00
|
|
|
{
|
|
|
|
*a4 = 0;
|
|
|
|
return 0i64;
|
|
|
|
}
|
|
|
|
const IActivationFactoryVtbl _IActivationFactoryVtbl = {
|
|
|
|
.QueryInterface = nimpl1,
|
|
|
|
.AddRef = nimpl3,
|
|
|
|
.Release = nimpl3,
|
|
|
|
.GetIids = nimpl,
|
|
|
|
.GetRuntimeClassName = nimpl,
|
|
|
|
.GetTrustLevel = nimpl,
|
|
|
|
.ActivateInstance = nimpl2
|
|
|
|
};
|
|
|
|
const IActivationFactoryVtbl _IActivationFactoryVtbl2 = {
|
|
|
|
.QueryInterface = nimpl1_2,
|
|
|
|
.AddRef = nimpl3,
|
|
|
|
.Release = nimpl3,
|
|
|
|
.GetIids = nimpl,
|
|
|
|
.GetRuntimeClassName = nimpl,
|
|
|
|
.GetTrustLevel = nimpl,
|
|
|
|
.ActivateInstance = nimpl
|
|
|
|
};
|
|
|
|
const IActivationFactoryVtbl _IActivationFactoryVtbl3 = {
|
|
|
|
.QueryInterface = nimpl1_3,
|
|
|
|
.AddRef = nimpl3,
|
|
|
|
.Release = nimpl3,
|
|
|
|
.GetIids = nimpl,
|
|
|
|
.GetRuntimeClassName = nimpl,
|
|
|
|
.GetTrustLevel = nimpl,
|
|
|
|
.ActivateInstance = nimpl4
|
|
|
|
};
|
|
|
|
const IActivationFactoryAA XamlExtensionsFactory = {
|
|
|
|
.lpVtbl = &_IActivationFactoryVtbl,
|
|
|
|
.lpVtbl2 = &_IActivationFactoryVtbl2,
|
|
|
|
.lpVtbl3 = &_IActivationFactoryVtbl3
|
|
|
|
};
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
void printf_guid(GUID guid)
|
|
|
|
{
|
|
|
|
printf("Guid = {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}\n",
|
|
|
|
guid.Data1, guid.Data2, guid.Data3,
|
|
|
|
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
|
|
|
|
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
|
|
|
|
}
|
|
|
|
|
|
|
|
LRESULT CALLBACK BalloonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
if (msg == WM_CREATE)
|
|
|
|
{
|
|
|
|
LPCREATESTRUCT lpCs = lParam;
|
|
|
|
|
|
|
|
NOTIFYICONDATA ni = { 0 };
|
|
|
|
ni.cbSize = sizeof(ni);
|
|
|
|
ni.hWnd = hWnd;
|
|
|
|
ni.uID = 1;
|
|
|
|
ni.uFlags = NIF_INFO;
|
|
|
|
ni.dwInfoFlags = NIIF_INFO;
|
|
|
|
ni.uTimeout = 2000;
|
|
|
|
_tcscpy_s(ni.szInfo, _countof(ni.szInfo), lpCs->lpCreateParams);
|
|
|
|
_tcscpy_s(ni.szInfoTitle, _countof(ni.szInfoTitle), _T("ExplorerPatcher"));
|
|
|
|
|
|
|
|
Shell_NotifyIcon(NIM_ADD, &ni);
|
|
|
|
|
|
|
|
free(lpCs->lpCreateParams);
|
|
|
|
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
__declspec(dllexport) CALLBACK ZZTestBalloon(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow)
|
|
|
|
{
|
|
|
|
TCHAR* lpwszCmdLine = calloc((strlen(lpszCmdLine) + 1), sizeof(TCHAR));
|
|
|
|
if (!lpwszCmdLine) exit(0);
|
|
|
|
size_t numChConv = 0;
|
|
|
|
mbstowcs_s(&numChConv, lpwszCmdLine, strlen(lpszCmdLine) + 1, lpszCmdLine, strlen(lpszCmdLine) + 1);
|
|
|
|
|
|
|
|
WNDCLASSEX wc;
|
|
|
|
HWND hwnd;
|
|
|
|
MSG msg;
|
|
|
|
|
|
|
|
wc.cbSize = sizeof(WNDCLASSEX);
|
|
|
|
wc.style = 0;
|
|
|
|
wc.lpfnWndProc = BalloonWndProc;
|
|
|
|
wc.cbClsExtra = 0;
|
|
|
|
wc.cbWndExtra = 0;
|
|
|
|
wc.hInstance = hInstance;
|
|
|
|
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
|
|
wc.lpszMenuName = NULL;
|
|
|
|
wc.lpszClassName = L"ExplorerPatcherBalloon";
|
|
|
|
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
|
|
|
|
|
|
|
|
if (!RegisterClassEx(&wc)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
hwnd = CreateWindowEx(0, L"ExplorerPatcherBalloon", L"",
|
|
|
|
0, 0, 0, 0, 0,
|
|
|
|
HWND_MESSAGE, NULL, hInstance, lpwszCmdLine);
|
|
|
|
|
|
|
|
while (GetMessage(&msg, NULL, 0, 0) > 0) {
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const wchar_t TestToastXML[] =
|
2022-01-02 19:02:59 +02:00
|
|
|
L"<toast scenario=\"reminder\" "
|
2021-10-01 01:26:10 +03:00
|
|
|
L"activationType=\"protocol\" launch=\"https://github.com/valinet/ExplorerPatcher\" duration=\"%s\">\r\n"
|
|
|
|
L" <visual>\r\n"
|
|
|
|
L" <binding template=\"ToastGeneric\">\r\n"
|
|
|
|
L" <text><![CDATA[%s]]></text>\r\n"
|
|
|
|
L" <text placement=\"attribution\"><![CDATA[ExplorerPatcher]]></text>\r\n"
|
|
|
|
L" </binding>\r\n"
|
|
|
|
L" </visual>\r\n"
|
|
|
|
L" <audio src=\"ms-winsoundevent:Notification.Default\" loop=\"false\" silent=\"false\"/>\r\n"
|
|
|
|
L"</toast>\r\n";
|
|
|
|
__declspec(dllexport) CALLBACK ZZTestToast(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow)
|
|
|
|
{
|
|
|
|
TCHAR* lpwszCmdLine = calloc((strlen(lpszCmdLine) + 1), sizeof(TCHAR));
|
|
|
|
if (!lpwszCmdLine) exit(0);
|
|
|
|
size_t numChConv = 0;
|
|
|
|
mbstowcs_s(&numChConv, lpwszCmdLine, strlen(lpszCmdLine) + 1, lpszCmdLine, strlen(lpszCmdLine) + 1);
|
|
|
|
TCHAR* buffer = calloc((sizeof(TestToastXML) / sizeof(wchar_t) + strlen(lpszCmdLine) + 10), sizeof(TCHAR));
|
|
|
|
if (buffer)
|
|
|
|
{
|
|
|
|
wsprintf(
|
|
|
|
buffer,
|
|
|
|
TestToastXML,
|
|
|
|
L"short",
|
|
|
|
lpwszCmdLine
|
|
|
|
);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
__x_ABI_CWindows_CData_CXml_CDom_CIXmlDocument* inputXml = NULL;
|
|
|
|
hr = String2IXMLDocument(
|
|
|
|
buffer,
|
|
|
|
wcslen(buffer),
|
|
|
|
&inputXml,
|
|
|
|
#ifdef DEBUG
|
|
|
|
stdout
|
|
|
|
#else
|
|
|
|
NULL
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
hr = ShowToastMessage(
|
|
|
|
inputXml,
|
|
|
|
APPID,
|
|
|
|
sizeof(APPID) / sizeof(TCHAR) - 1,
|
|
|
|
#ifdef DEBUG
|
|
|
|
stdout
|
|
|
|
#else
|
|
|
|
NULL
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
free(buffer);
|
|
|
|
}
|
|
|
|
free(lpwszCmdLine);
|
|
|
|
}
|
|
|
|
|
|
|
|
__declspec(dllexport) CALLBACK ZZLaunchExplorer(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow)
|
|
|
|
{
|
|
|
|
Sleep(100);
|
|
|
|
TCHAR wszExplorerPath[MAX_PATH + 1];
|
|
|
|
GetWindowsDirectory(wszExplorerPath, MAX_PATH + 1);
|
|
|
|
wcscat_s(wszExplorerPath, MAX_PATH + 1, L"\\explorer.exe");
|
|
|
|
STARTUPINFO si = { sizeof(si) };
|
|
|
|
PROCESS_INFORMATION pi;
|
|
|
|
BOOL b = CreateProcess(
|
|
|
|
NULL,
|
|
|
|
wszExplorerPath,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
TRUE,
|
|
|
|
CREATE_UNICODE_ENVIRONMENT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&si,
|
|
|
|
&pi
|
|
|
|
);
|
|
|
|
FreeConsole();
|
|
|
|
TerminateProcess(
|
|
|
|
OpenProcess(
|
|
|
|
PROCESS_TERMINATE,
|
|
|
|
FALSE,
|
|
|
|
GetCurrentProcessId()
|
|
|
|
),
|
|
|
|
0
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
__declspec(dllexport) CALLBACK ZZLaunchExplorerDelayed(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow)
|
|
|
|
{
|
|
|
|
Sleep(2000);
|
|
|
|
ZZLaunchExplorer(hWnd, hInstance, lpszCmdLine, nCmdShow);
|
|
|
|
}
|
|
|
|
|
2021-10-25 05:42:03 +03:00
|
|
|
__declspec(dllexport) CALLBACK ZZRestartExplorer(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow)
|
|
|
|
{
|
|
|
|
BeginExplorerRestart();
|
|
|
|
FinishExplorerRestart();
|
|
|
|
}
|
|
|
|
|
2021-10-21 09:01:59 +03:00
|
|
|
void* ReadFromFile(wchar_t* wszFileName, DWORD* dwSize)
|
|
|
|
{
|
|
|
|
void* ok = NULL;
|
|
|
|
HANDLE hImage = CreateFileW(wszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (hImage)
|
|
|
|
{
|
2021-10-30 07:17:25 +03:00
|
|
|
LARGE_INTEGER dwFileSize;
|
2021-10-21 09:01:59 +03:00
|
|
|
GetFileSizeEx(hImage, &dwFileSize);
|
2021-10-30 07:17:25 +03:00
|
|
|
if (dwFileSize.LowPart)
|
2021-10-21 09:01:59 +03:00
|
|
|
{
|
2021-10-30 07:17:25 +03:00
|
|
|
void* pImage = malloc(dwFileSize.LowPart);
|
2021-10-21 09:01:59 +03:00
|
|
|
if (pImage)
|
|
|
|
{
|
|
|
|
DWORD dwNumberOfBytesRead = 0;
|
2021-10-30 07:17:25 +03:00
|
|
|
ReadFile(hImage, pImage, dwFileSize.LowPart, &dwNumberOfBytesRead, NULL);
|
|
|
|
if (dwFileSize.LowPart == dwNumberOfBytesRead)
|
2021-10-21 09:01:59 +03:00
|
|
|
{
|
|
|
|
ok = pImage;
|
|
|
|
*dwSize = dwNumberOfBytesRead;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CloseHandle(hImage);
|
|
|
|
}
|
|
|
|
return ok;
|
2021-11-13 07:59:14 +02:00
|
|
|
}
|
|
|
|
|
2022-01-22 21:12:18 +02:00
|
|
|
int ComputeFileHash(LPCWSTR filename, LPSTR hash, DWORD dwHash)
|
2021-11-13 07:59:14 +02:00
|
|
|
{
|
|
|
|
DWORD dwStatus = 0;
|
|
|
|
BOOL bResult = FALSE;
|
|
|
|
HCRYPTPROV hProv = 0;
|
|
|
|
HCRYPTHASH hHash = 0;
|
|
|
|
HANDLE hFile = NULL;
|
|
|
|
BYTE* rgbFile;
|
|
|
|
DWORD cbRead = 0;
|
|
|
|
BYTE rgbHash[16];
|
|
|
|
DWORD cbHash = 0;
|
|
|
|
WCHAR rgbDigits[] = L"0123456789abcdef";
|
|
|
|
// Logic to check usage goes here.
|
|
|
|
|
|
|
|
hFile = CreateFile(filename,
|
|
|
|
GENERIC_READ,
|
|
|
|
FILE_SHARE_READ,
|
|
|
|
NULL,
|
|
|
|
OPEN_EXISTING,
|
|
|
|
FILE_FLAG_SEQUENTIAL_SCAN,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (INVALID_HANDLE_VALUE == hFile)
|
|
|
|
{
|
|
|
|
dwStatus = GetLastError();
|
|
|
|
return dwStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
LARGE_INTEGER dwFileSize;
|
|
|
|
GetFileSizeEx(hFile, &dwFileSize);
|
|
|
|
if (!dwFileSize.LowPart)
|
|
|
|
{
|
|
|
|
dwStatus = GetLastError();
|
|
|
|
CloseHandle(hFile);
|
|
|
|
return dwStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
rgbFile = malloc(dwFileSize.LowPart);
|
|
|
|
if (!rgbFile)
|
|
|
|
{
|
|
|
|
dwStatus = E_OUTOFMEMORY;
|
|
|
|
CloseHandle(hFile);
|
|
|
|
return dwStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get handle to the crypto provider
|
|
|
|
if (!CryptAcquireContext(&hProv,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
PROV_RSA_FULL,
|
|
|
|
CRYPT_VERIFYCONTEXT))
|
|
|
|
{
|
|
|
|
dwStatus = GetLastError();
|
|
|
|
CloseHandle(hFile);
|
|
|
|
return dwStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
|
|
|
|
{
|
|
|
|
dwStatus = GetLastError();
|
|
|
|
CloseHandle(hFile);
|
|
|
|
CryptReleaseContext(hProv, 0);
|
|
|
|
return dwStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (bResult = ReadFile(hFile, rgbFile, dwFileSize.LowPart, &cbRead, NULL))
|
|
|
|
{
|
|
|
|
if (0 == cbRead)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CryptHashData(hHash, rgbFile, cbRead, 0))
|
|
|
|
{
|
|
|
|
dwStatus = GetLastError();
|
|
|
|
CryptReleaseContext(hProv, 0);
|
|
|
|
CryptDestroyHash(hHash);
|
|
|
|
CloseHandle(hFile);
|
|
|
|
return dwStatus;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bResult)
|
|
|
|
{
|
|
|
|
dwStatus = GetLastError();
|
|
|
|
CryptReleaseContext(hProv, 0);
|
|
|
|
CryptDestroyHash(hHash);
|
|
|
|
CloseHandle(hFile);
|
|
|
|
return dwStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
cbHash = 16;
|
|
|
|
if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
|
|
|
|
{
|
|
|
|
for (DWORD i = 0; i < cbHash; i++)
|
|
|
|
{
|
2021-11-14 18:29:07 +02:00
|
|
|
sprintf_s(hash + (i * 2), 3, "%c%c", rgbDigits[rgbHash[i] >> 4], rgbDigits[rgbHash[i] & 0xf]);
|
2021-11-13 07:59:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dwStatus = GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
CryptDestroyHash(hHash);
|
|
|
|
CryptReleaseContext(hProv, 0);
|
|
|
|
CloseHandle(hFile);
|
|
|
|
free(rgbFile);
|
|
|
|
|
|
|
|
return dwStatus;
|
2021-11-14 18:29:07 +02:00
|
|
|
}
|
|
|
|
|
2022-01-22 21:12:18 +02:00
|
|
|
int ComputeFileHash2(HMODULE hModule, LPCWSTR filename, LPSTR hash, DWORD dwHash)
|
|
|
|
{
|
|
|
|
if (dwHash < 33)
|
|
|
|
{
|
|
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
|
|
}
|
|
|
|
if (!hModule)
|
|
|
|
{
|
|
|
|
return ERROR_INVALID_ADDRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD dwLeftMost = 0;
|
|
|
|
DWORD dwSecondLeft = 0;
|
|
|
|
DWORD dwSecondRight = 0;
|
|
|
|
DWORD dwRightMost = 0;
|
|
|
|
QueryVersionInfo(hModule, VS_VERSION_INFO, &dwLeftMost, &dwSecondLeft, &dwSecondRight, &dwRightMost);
|
|
|
|
|
General: Support EP as version 22621
The final Windows 11 22H2 that is shipped to users is OS build 22621.
Unfortunately, I updated EP some time ago to 22622. This creates a
discrepancy between the OS build most people have and the version of
EP that they might have installed. Furthermore, I currently test EP
against OS build 22621. To make things more clear, the next version of
EP will have the major build number set to 22621.
In order to have EP use version 22621 from now on and not prevent
updating from EP 22622... to EP 22621..., I devised this workaround
where the EP version is kept to 22622 as far as updates are concerned,
but the internal build number of EP really is set to 22621.
In the future, if we want to bump the EP version to 22622 again, a
regular change in `version.h` will have the setup patcher insert a `!`
as the first character in the hash part of the version string, which
tells the updater to display that version as a real 22622 build and not
artificially decrement it to 22621.
The only slight inconvenience is that, when the next update arrives,
people will be told they upgrade to EP 22622... still, but they will
receive an EP 22621... build. But at least the updater will work and
detect the new version. From there on, subsequent versions will be
shown as 22621 in the notification if the build number for that version
really is 22621.
2022-10-02 23:03:16 +03:00
|
|
|
sprintf_s(hash, 33, "%d.%d.%d.%d.", dwLeftMost == 22621 ? 22622 : dwLeftMost, dwSecondLeft, dwSecondRight, dwRightMost);
|
2022-01-22 21:12:18 +02:00
|
|
|
|
|
|
|
char real_hash[33];
|
|
|
|
ComputeFileHash(filename, real_hash, 33);
|
2022-02-17 22:50:44 +02:00
|
|
|
strncpy_s(hash + strlen(hash), dwHash - strlen(hash), real_hash, 32 - strlen(hash));
|
General: Support EP as version 22621
The final Windows 11 22H2 that is shipped to users is OS build 22621.
Unfortunately, I updated EP some time ago to 22622. This creates a
discrepancy between the OS build most people have and the version of
EP that they might have installed. Furthermore, I currently test EP
against OS build 22621. To make things more clear, the next version of
EP will have the major build number set to 22621.
In order to have EP use version 22621 from now on and not prevent
updating from EP 22622... to EP 22621..., I devised this workaround
where the EP version is kept to 22622 as far as updates are concerned,
but the internal build number of EP really is set to 22621.
In the future, if we want to bump the EP version to 22622 again, a
regular change in `version.h` will have the setup patcher insert a `!`
as the first character in the hash part of the version string, which
tells the updater to display that version as a real 22622 build and not
artificially decrement it to 22621.
The only slight inconvenience is that, when the next update arrives,
people will be told they upgrade to EP 22622... still, but they will
receive an EP 22621... build. But at least the updater will work and
detect the new version. From there on, subsequent versions will be
shown as 22621 in the notification if the build number for that version
really is 22621.
2022-10-02 23:03:16 +03:00
|
|
|
if (dwLeftMost == 22622) *(strchr(strchr(strchr(strchr(hash, '.') + 1, '.') + 1, '.') + 1, '.') + 1) = '!';
|
2022-01-22 21:12:18 +02:00
|
|
|
hash[33] = 0;
|
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2021-11-14 18:29:07 +02:00
|
|
|
void LaunchPropertiesGUI(HMODULE hModule)
|
|
|
|
{
|
|
|
|
//CreateThread(0, 0, ZZGUI, 0, 0, 0);
|
|
|
|
wchar_t wszPath[MAX_PATH * 2];
|
|
|
|
ZeroMemory(
|
|
|
|
wszPath,
|
|
|
|
(MAX_PATH * 2) * sizeof(wchar_t)
|
|
|
|
);
|
|
|
|
wszPath[0] = '\"';
|
|
|
|
GetSystemDirectoryW(
|
|
|
|
wszPath + 1,
|
|
|
|
MAX_PATH
|
|
|
|
);
|
|
|
|
wcscat_s(
|
|
|
|
wszPath,
|
|
|
|
MAX_PATH * 2,
|
|
|
|
L"\\rundll32.exe\" \""
|
|
|
|
);
|
|
|
|
GetModuleFileNameW(
|
|
|
|
hModule,
|
|
|
|
wszPath + wcslen(wszPath),
|
|
|
|
MAX_PATH
|
|
|
|
);
|
|
|
|
wcscat_s(
|
|
|
|
wszPath,
|
|
|
|
MAX_PATH * 2,
|
|
|
|
L"\",ZZGUI"
|
|
|
|
);
|
|
|
|
wprintf(L"Launching : %s\n", wszPath);
|
|
|
|
STARTUPINFO si;
|
|
|
|
ZeroMemory(&si, sizeof(STARTUPINFO));
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
PROCESS_INFORMATION pi;
|
|
|
|
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
|
|
|
if (CreateProcessW(
|
|
|
|
NULL,
|
|
|
|
wszPath,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
2021-12-15 04:44:09 +02:00
|
|
|
FALSE,
|
2021-11-14 18:29:07 +02:00
|
|
|
CREATE_UNICODE_ENVIRONMENT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&si,
|
|
|
|
&pi
|
|
|
|
))
|
|
|
|
{
|
|
|
|
CloseHandle(pi.hThread);
|
|
|
|
CloseHandle(pi.hProcess);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL SystemShutdown(BOOL reboot)
|
|
|
|
{
|
|
|
|
HANDLE hToken;
|
|
|
|
TOKEN_PRIVILEGES tkp;
|
|
|
|
|
|
|
|
// Get a token for this process.
|
|
|
|
|
|
|
|
if (!OpenProcessToken(GetCurrentProcess(),
|
|
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
|
|
|
return(FALSE);
|
|
|
|
|
|
|
|
// Get the LUID for the shutdown privilege.
|
|
|
|
|
|
|
|
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
|
|
|
|
&tkp.Privileges[0].Luid);
|
|
|
|
|
|
|
|
tkp.PrivilegeCount = 1; // one privilege to set
|
|
|
|
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
|
|
|
|
// Get the shutdown privilege for this process.
|
|
|
|
|
|
|
|
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
|
|
|
|
(PTOKEN_PRIVILEGES)NULL, 0);
|
|
|
|
|
|
|
|
if (GetLastError() != ERROR_SUCCESS)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
// Shut down the system and force all applications to close.
|
|
|
|
|
|
|
|
if (!ExitWindowsEx((reboot ? EWX_REBOOT : EWX_SHUTDOWN) | EWX_FORCE,
|
|
|
|
SHTDN_REASON_MAJOR_OPERATINGSYSTEM |
|
|
|
|
SHTDN_REASON_MINOR_UPGRADE |
|
|
|
|
SHTDN_REASON_FLAG_PLANNED))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
//shutdown was successful
|
|
|
|
return TRUE;
|
|
|
|
}
|
2021-12-09 17:00:50 +02:00
|
|
|
|
2021-12-09 17:25:25 +02:00
|
|
|
HRESULT FindDesktopFolderView(REFIID riid, void** ppv)
|
2021-12-09 17:00:50 +02:00
|
|
|
{
|
2021-12-09 17:25:25 +02:00
|
|
|
HRESULT hr = E_FAIL;
|
2021-12-09 17:00:50 +02:00
|
|
|
IShellWindows* spShellWindows = NULL;
|
2021-12-09 17:25:25 +02:00
|
|
|
hr = CoCreateInstance(
|
2021-12-09 17:00:50 +02:00
|
|
|
&CLSID_ShellWindows,
|
|
|
|
NULL,
|
|
|
|
CLSCTX_ALL,
|
|
|
|
&IID_IShellWindows,
|
|
|
|
&spShellWindows
|
|
|
|
);
|
|
|
|
if (spShellWindows)
|
|
|
|
{
|
|
|
|
VARIANT vtEmpty;
|
|
|
|
ZeroMemory(&vtEmpty, sizeof(VARIANT));
|
|
|
|
VARIANT vtLoc;
|
|
|
|
ZeroMemory(&vtLoc, sizeof(VARIANT));
|
|
|
|
vtLoc.vt = VT_INT;
|
|
|
|
vtLoc.intVal = CSIDL_DESKTOP;
|
|
|
|
long lhwnd = 0;
|
|
|
|
IDispatch* spdisp = NULL;
|
2021-12-09 17:25:25 +02:00
|
|
|
hr = spShellWindows->lpVtbl->FindWindowSW(
|
2021-12-09 17:00:50 +02:00
|
|
|
spShellWindows,
|
|
|
|
&vtLoc,
|
|
|
|
&vtEmpty,
|
|
|
|
SWC_DESKTOP,
|
|
|
|
&lhwnd,
|
|
|
|
SWFO_NEEDDISPATCH,
|
|
|
|
&spdisp
|
|
|
|
);
|
|
|
|
if (spdisp)
|
|
|
|
{
|
|
|
|
IServiceProvider* spdisp2 = NULL;
|
2021-12-09 17:25:25 +02:00
|
|
|
hr = spdisp->lpVtbl->QueryInterface(spdisp, &IID_IServiceProvider, &spdisp2);
|
2021-12-09 17:00:50 +02:00
|
|
|
if (spdisp2)
|
|
|
|
{
|
|
|
|
IShellBrowser* spBrowser = NULL;
|
2021-12-09 17:25:25 +02:00
|
|
|
hr = spdisp2->lpVtbl->QueryService(spdisp2, &SID_STopLevelBrowser, &IID_IShellBrowser, &spBrowser);
|
2021-12-09 17:00:50 +02:00
|
|
|
if (spBrowser)
|
|
|
|
{
|
|
|
|
IShellView* spView = NULL;
|
2021-12-09 17:25:25 +02:00
|
|
|
hr = spBrowser->lpVtbl->QueryActiveShellView(spBrowser, &spView);
|
2021-12-09 17:00:50 +02:00
|
|
|
if (spView)
|
|
|
|
{
|
2021-12-09 17:25:25 +02:00
|
|
|
hr = spView->lpVtbl->QueryInterface(spView, riid, ppv);
|
2021-12-09 17:00:50 +02:00
|
|
|
spView->lpVtbl->Release(spView);
|
|
|
|
}
|
|
|
|
spBrowser->lpVtbl->Release(spBrowser);
|
|
|
|
}
|
|
|
|
spdisp2->lpVtbl->Release(spdisp2);
|
|
|
|
}
|
|
|
|
spdisp->lpVtbl->Release(spdisp);
|
|
|
|
}
|
|
|
|
spShellWindows->lpVtbl->Release(spShellWindows);
|
|
|
|
}
|
2021-12-09 17:25:25 +02:00
|
|
|
return hr;
|
2021-12-09 17:00:50 +02:00
|
|
|
}
|
|
|
|
|
2021-12-09 17:25:25 +02:00
|
|
|
HRESULT GetDesktopAutomationObject(REFIID riid, void** ppv)
|
2021-12-09 17:00:50 +02:00
|
|
|
{
|
2021-12-09 17:25:25 +02:00
|
|
|
HRESULT hr = E_FAIL;
|
2021-12-09 17:00:50 +02:00
|
|
|
IShellView* spsv = NULL;
|
2021-12-09 17:25:25 +02:00
|
|
|
hr = FindDesktopFolderView(&IID_IShellView, &spsv);
|
2021-12-09 17:00:50 +02:00
|
|
|
if (spsv)
|
|
|
|
{
|
|
|
|
IDispatch* spdispView = NULL;
|
2021-12-09 17:25:25 +02:00
|
|
|
hr = spsv->lpVtbl->GetItemObject(spsv, SVGIO_BACKGROUND, &IID_IDispatch, &spdispView);
|
2021-12-09 17:00:50 +02:00
|
|
|
if (spdispView)
|
|
|
|
{
|
2021-12-09 17:25:25 +02:00
|
|
|
hr = spdispView->lpVtbl->QueryInterface(spdispView, riid, ppv);
|
2021-12-09 17:00:50 +02:00
|
|
|
spdispView->lpVtbl->Release(spdispView);
|
|
|
|
}
|
|
|
|
spsv->lpVtbl->Release(spsv);
|
|
|
|
}
|
2021-12-09 17:25:25 +02:00
|
|
|
return hr;
|
2021-12-09 17:00:50 +02:00
|
|
|
}
|
|
|
|
|
2021-12-09 17:25:25 +02:00
|
|
|
HRESULT ShellExecuteFromExplorer(
|
2021-12-09 17:00:50 +02:00
|
|
|
PCWSTR pszFile,
|
|
|
|
PCWSTR pszParameters,
|
|
|
|
PCWSTR pszDirectory,
|
|
|
|
PCWSTR pszOperation,
|
|
|
|
int nShowCmd
|
|
|
|
)
|
|
|
|
{
|
2021-12-09 17:25:25 +02:00
|
|
|
HRESULT hr = E_FAIL;
|
2021-12-09 17:00:50 +02:00
|
|
|
IShellFolderViewDual* spFolderView = NULL;
|
2021-12-10 03:06:04 +02:00
|
|
|
GetDesktopAutomationObject(&IID_IShellFolderViewDual, &spFolderView);
|
2021-12-09 17:00:50 +02:00
|
|
|
if (spFolderView)
|
|
|
|
{
|
|
|
|
IDispatch* spdispShell = NULL;
|
2021-12-10 03:06:04 +02:00
|
|
|
spFolderView->lpVtbl->get_Application(spFolderView, &spdispShell);
|
2021-12-09 17:00:50 +02:00
|
|
|
if (spdispShell)
|
|
|
|
{
|
|
|
|
IShellDispatch2* spdispShell2 = NULL;
|
2021-12-10 03:06:04 +02:00
|
|
|
spdispShell->lpVtbl->QueryInterface(spdispShell, &IID_IShellDispatch2, &spdispShell2);
|
2021-12-09 17:00:50 +02:00
|
|
|
if (spdispShell2)
|
|
|
|
{
|
|
|
|
BSTR a_pszFile = pszFile ? SysAllocString(pszFile): SysAllocString(L"");
|
|
|
|
VARIANT a_pszParameters, a_pszDirectory, a_pszOperation, a_nShowCmd;
|
|
|
|
ZeroMemory(&a_pszParameters, sizeof(VARIANT));
|
|
|
|
ZeroMemory(&a_pszDirectory, sizeof(VARIANT));
|
|
|
|
ZeroMemory(&a_pszOperation, sizeof(VARIANT));
|
|
|
|
ZeroMemory(&a_nShowCmd, sizeof(VARIANT));
|
|
|
|
a_pszParameters.vt = VT_BSTR;
|
|
|
|
a_pszParameters.bstrVal = pszParameters ? SysAllocString(pszParameters) : SysAllocString(L"");
|
|
|
|
a_pszDirectory.vt = VT_BSTR;
|
|
|
|
a_pszDirectory.bstrVal = pszDirectory ? SysAllocString(pszDirectory) : SysAllocString(L"");
|
|
|
|
a_pszOperation.vt = VT_BSTR;
|
|
|
|
a_pszOperation.bstrVal = pszOperation ? SysAllocString(pszOperation) : SysAllocString(L"");
|
|
|
|
a_nShowCmd.vt = VT_INT;
|
|
|
|
a_nShowCmd.intVal = nShowCmd;
|
2021-12-09 17:25:25 +02:00
|
|
|
hr = spdispShell2->lpVtbl->ShellExecuteW(spdispShell2, a_pszFile, a_pszParameters, a_pszDirectory, a_pszOperation, a_nShowCmd);
|
2021-12-09 17:00:50 +02:00
|
|
|
if (a_pszOperation.bstrVal)
|
|
|
|
{
|
|
|
|
SysFreeString(a_pszOperation.bstrVal);
|
|
|
|
}
|
|
|
|
if (a_pszDirectory.bstrVal)
|
|
|
|
{
|
|
|
|
SysFreeString(a_pszDirectory.bstrVal);
|
|
|
|
}
|
|
|
|
if (a_pszParameters.bstrVal)
|
|
|
|
{
|
|
|
|
SysFreeString(a_pszParameters.bstrVal);
|
|
|
|
}
|
|
|
|
if (a_pszFile)
|
|
|
|
{
|
|
|
|
SysFreeString(a_pszFile);
|
|
|
|
}
|
|
|
|
spdispShell2->lpVtbl->Release(spdispShell2);
|
|
|
|
}
|
|
|
|
spdispShell->lpVtbl->Release(spdispShell);
|
|
|
|
}
|
|
|
|
spFolderView->lpVtbl->Release(spFolderView);
|
|
|
|
}
|
2021-12-09 17:25:25 +02:00
|
|
|
return hr;
|
2021-12-09 17:00:50 +02:00
|
|
|
}
|
2022-01-04 03:40:57 +02:00
|
|
|
|
|
|
|
void ToggleTaskbarAutohide()
|
|
|
|
{
|
|
|
|
APPBARDATA abd;
|
|
|
|
abd.cbSize = sizeof(APPBARDATA);
|
|
|
|
if (SHAppBarMessage(ABM_GETSTATE, &abd) == ABS_AUTOHIDE)
|
|
|
|
{
|
|
|
|
abd.lParam = 0;
|
|
|
|
SHAppBarMessage(ABM_SETSTATE, &abd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
abd.lParam = ABS_AUTOHIDE;
|
|
|
|
SHAppBarMessage(ABM_SETSTATE, &abd);
|
|
|
|
}
|
|
|
|
}
|
2022-01-24 18:33:06 +02:00
|
|
|
|
|
|
|
LSTATUS RegisterDWMService(DWORD dwDesiredState, DWORD dwOverride)
|
|
|
|
{
|
|
|
|
WCHAR wszPath[MAX_PATH];
|
|
|
|
GetSystemDirectoryW(wszPath, MAX_PATH);
|
|
|
|
wcscat_s(wszPath, MAX_PATH, L"\\cmd.exe");
|
|
|
|
|
|
|
|
WCHAR wszSCPath[MAX_PATH];
|
|
|
|
GetSystemDirectoryW(wszSCPath, MAX_PATH);
|
|
|
|
wcscat_s(wszSCPath, MAX_PATH, L"\\sc.exe");
|
|
|
|
|
|
|
|
WCHAR wszRundll32[MAX_PATH];
|
|
|
|
SHGetFolderPathW(NULL, SPECIAL_FOLDER, NULL, SHGFP_TYPE_CURRENT, wszRundll32);
|
|
|
|
wcscat_s(wszRundll32, MAX_PATH, _T(APP_RELATIVE_PATH));
|
|
|
|
wcscat_s(wszRundll32, MAX_PATH, L"\\ep_dwm.exe");
|
|
|
|
|
|
|
|
WCHAR wszEP[MAX_PATH];
|
|
|
|
GetWindowsDirectoryW(wszEP, MAX_PATH);
|
|
|
|
wcscat_s(wszEP, MAX_PATH, L"\\dxgi.dll");
|
|
|
|
|
|
|
|
WCHAR wszTaskkill[MAX_PATH];
|
|
|
|
GetSystemDirectoryW(wszTaskkill, MAX_PATH);
|
|
|
|
wcscat_s(wszTaskkill, MAX_PATH, L"\\taskkill.exe");
|
|
|
|
|
|
|
|
WCHAR wszArgumentsRegister[MAX_PATH * 10];
|
|
|
|
swprintf_s(
|
|
|
|
wszArgumentsRegister,
|
|
|
|
MAX_PATH * 10,
|
|
|
|
L"/c \""
|
|
|
|
L"\"%s\" create " _T(EP_DWM_SERVICENAME) L" binPath= \"\\\"%s\\\" %s\" DisplayName= \"ExplorerPatcher Desktop Window Manager Service\" start= auto & "
|
|
|
|
L"\"%s\" description " _T(EP_DWM_SERVICENAME) L" \"Service for managing aspects related to the Desktop Window Manager.\" & "
|
|
|
|
L"\"%s\" %s " _T(EP_DWM_SERVICENAME)
|
|
|
|
L"\"",
|
|
|
|
wszSCPath,
|
|
|
|
wszRundll32,
|
|
|
|
_T(EP_DWM_SERVICENAME) L" " _T(EP_DWM_EVENTNAME),
|
|
|
|
wszSCPath,
|
|
|
|
wszSCPath,
|
|
|
|
(!dwOverride || dwOverride == 3) ? L"start" : L"query"
|
|
|
|
);
|
|
|
|
WCHAR wszArgumentsUnRegister[MAX_PATH * 10];
|
|
|
|
swprintf_s(
|
|
|
|
wszArgumentsUnRegister,
|
|
|
|
MAX_PATH * 10,
|
|
|
|
L"/c \""
|
|
|
|
L"\"%s\" stop " _T(EP_DWM_SERVICENAME) L" & "
|
|
|
|
L"\"%s\" delete " _T(EP_DWM_SERVICENAME) L" & "
|
|
|
|
L"\"",
|
|
|
|
wszSCPath,
|
|
|
|
wszSCPath
|
|
|
|
);
|
|
|
|
wprintf(L"%s\n", wszArgumentsRegister);
|
|
|
|
|
|
|
|
BOOL bAreRoundedCornersDisabled = FALSE;
|
|
|
|
if (dwOverride)
|
|
|
|
{
|
|
|
|
bAreRoundedCornersDisabled = !(dwOverride - 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
HANDLE h_exists = CreateEventW(NULL, FALSE, FALSE, _T(EP_DWM_EVENTNAME));
|
|
|
|
if (h_exists)
|
|
|
|
{
|
|
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
|
|
|
{
|
|
|
|
bAreRoundedCornersDisabled = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bAreRoundedCornersDisabled = FALSE;
|
|
|
|
}
|
|
|
|
CloseHandle(h_exists);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (GetLastError() == ERROR_ACCESS_DENIED)
|
|
|
|
{
|
|
|
|
bAreRoundedCornersDisabled = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bAreRoundedCornersDisabled = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((bAreRoundedCornersDisabled && dwDesiredState) || (!bAreRoundedCornersDisabled && !dwDesiredState))
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SHELLEXECUTEINFO ShExecInfo = { 0 };
|
|
|
|
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
|
|
|
|
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
|
|
|
ShExecInfo.hwnd = NULL;
|
|
|
|
ShExecInfo.lpVerb = L"runas";
|
|
|
|
ShExecInfo.lpFile = wszPath;
|
|
|
|
ShExecInfo.lpParameters = !bAreRoundedCornersDisabled ? wszArgumentsRegister : wszArgumentsUnRegister;
|
|
|
|
ShExecInfo.lpDirectory = NULL;
|
|
|
|
ShExecInfo.nShow = SW_HIDE;
|
|
|
|
ShExecInfo.hInstApp = NULL;
|
|
|
|
if (ShellExecuteExW(&ShExecInfo) && ShExecInfo.hProcess)
|
|
|
|
{
|
|
|
|
WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
|
|
|
|
DWORD dwExitCode = 0;
|
|
|
|
GetExitCodeProcess(ShExecInfo.hProcess, &dwExitCode);
|
|
|
|
CloseHandle(ShExecInfo.hProcess);
|
|
|
|
}
|
|
|
|
return TRUE;
|
2022-01-27 04:35:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-01-28 04:45:04 +02:00
|
|
|
HRESULT InputBox(BOOL bPassword, HWND hWnd, LPCWSTR wszPrompt, LPCWSTR wszTitle, LPCWSTR wszDefault, LPWSTR wszAnswer, DWORD cbAnswer, BOOL* bCancelled)
|
2022-01-27 04:35:27 +02:00
|
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
2022-01-28 04:45:04 +02:00
|
|
|
if (!wszPrompt || !wszTitle || !wszDefault || !wszAnswer || !cbAnswer || !bCancelled)
|
|
|
|
{
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
2022-01-27 04:35:27 +02:00
|
|
|
GUID guidBuffer;
|
2022-01-28 04:39:42 +02:00
|
|
|
hr = getEngineGuid(L".vbs", &guidBuffer);
|
2022-01-27 04:35:27 +02:00
|
|
|
|
|
|
|
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;
|
2022-01-28 04:39:42 +02:00
|
|
|
hr = CoCreateInstance(FAILED(hr) ? &CLSID_VBScript : &guidBuffer, 0, CLSCTX_ALL,
|
2022-01-27 04:35:27 +02:00
|
|
|
&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);
|
|
|
|
|
2022-01-28 04:45:04 +02:00
|
|
|
*bCancelled = (result.vt == VT_EMPTY);
|
|
|
|
|
2022-01-27 04:35:27 +02:00
|
|
|
UnhookWindowsHookEx(hHook);
|
|
|
|
|
|
|
|
free(wszEvaluation2);
|
|
|
|
|
2022-01-28 04:45:04 +02:00
|
|
|
if (result.bstrVal)
|
|
|
|
{
|
|
|
|
memcpy(wszAnswer, result.bstrVal, cbAnswer * sizeof(WCHAR));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (result.vt != VT_EMPTY)
|
|
|
|
{
|
|
|
|
wszAnswer[0] = 0;
|
|
|
|
}
|
|
|
|
}
|
2022-01-27 04:35:27 +02:00
|
|
|
|
|
|
|
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;
|
2022-02-14 02:42:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
UINT PleaseWaitTimeout = 0;
|
|
|
|
HHOOK PleaseWaitHook = NULL;
|
|
|
|
HWND PleaseWaitHWND = NULL;
|
|
|
|
void* PleaseWaitCallbackData = NULL;
|
|
|
|
BOOL (*PleaseWaitCallbackFunc)(void* data) = NULL;
|
|
|
|
BOOL PleaseWait_UpdateTimeout(int timeout)
|
|
|
|
{
|
|
|
|
if (PleaseWaitHWND)
|
|
|
|
{
|
|
|
|
KillTimer(PleaseWaitHWND, 'EPPW');
|
|
|
|
PleaseWaitTimeout = timeout;
|
|
|
|
return SetTimer(PleaseWaitHWND, 'EPPW', PleaseWaitTimeout, PleaseWait_TimerProc);
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID CALLBACK PleaseWait_TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
|
|
|
|
{
|
|
|
|
if (idEvent == 'EPPW')
|
|
|
|
{
|
|
|
|
if (PleaseWaitCallbackFunc)
|
|
|
|
{
|
|
|
|
if (PleaseWaitCallbackFunc(PleaseWaitCallbackData))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PleaseWaitCallbackData = NULL;
|
|
|
|
PleaseWaitCallbackFunc = NULL;
|
|
|
|
}
|
|
|
|
KillTimer(hWnd, 'EPPW');
|
|
|
|
SetTimer(hWnd, 'EPPW', 0, NULL); // <- this closes the message box
|
|
|
|
PleaseWaitHWND = NULL;
|
|
|
|
PleaseWaitTimeout = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LRESULT CALLBACK PleaseWait_HookProc(int code, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
if (code < 0)
|
|
|
|
{
|
|
|
|
return CallNextHookEx(NULL, code, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
CWPSTRUCT* msg = (CWPSTRUCT*)lParam;
|
|
|
|
/*if (msg->message == WM_CREATE)
|
|
|
|
{
|
|
|
|
CREATESTRUCT* pCS = (CREATESTRUCT*)msg->lParam;
|
|
|
|
if (pCS->lpszClass == RegisterWindowMessageW(L"Button"))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
LRESULT result = CallNextHookEx(NULL, code, wParam, lParam);
|
|
|
|
|
|
|
|
if (msg->message == WM_INITDIALOG)
|
|
|
|
{
|
|
|
|
PleaseWaitHWND = msg->hwnd;
|
2022-02-14 07:41:02 +02:00
|
|
|
EnableWindow(PleaseWaitHWND, FALSE);
|
2022-02-14 02:42:57 +02:00
|
|
|
LONG_PTR style = GetWindowLongPtrW(PleaseWaitHWND, GWL_STYLE);
|
|
|
|
SetWindowLongPtrW(PleaseWaitHWND, GWL_STYLE, style & ~WS_SYSMENU);
|
|
|
|
RECT rc;
|
|
|
|
GetWindowRect(PleaseWaitHWND, &rc);
|
|
|
|
SetWindowPos(PleaseWaitHWND, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top - MulDiv(50, GetDpiForWindow(PleaseWaitHWND), 96), SWP_NOMOVE | SWP_FRAMECHANGED);
|
|
|
|
SetTimer(PleaseWaitHWND, 'EPPW', PleaseWaitTimeout, PleaseWait_TimerProc);
|
|
|
|
UnhookWindowsHookEx(PleaseWaitHook);
|
|
|
|
PleaseWaitHook = NULL;
|
|
|
|
}
|
|
|
|
return result;
|
2022-02-20 18:35:33 +02:00
|
|
|
}
|
2022-02-20 18:14:07 +02:00
|
|
|
|
|
|
|
BOOL DownloadAndInstallWebView2Runtime()
|
|
|
|
{
|
|
|
|
BOOL bOK = FALSE;
|
|
|
|
HINTERNET hInternet = NULL;
|
|
|
|
if (hInternet = InternetOpenA(
|
2022-02-25 00:19:25 +02:00
|
|
|
"ExplorerPatcher",
|
2022-02-20 18:14:07 +02:00
|
|
|
INTERNET_OPEN_TYPE_PRECONFIG,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
))
|
|
|
|
{
|
|
|
|
HINTERNET hConnect = InternetOpenUrlA(
|
|
|
|
hInternet,
|
|
|
|
"https://go.microsoft.com/fwlink/p/?LinkId=2124703",
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
INTERNET_FLAG_RAW_DATA |
|
|
|
|
INTERNET_FLAG_RELOAD |
|
|
|
|
INTERNET_FLAG_RESYNCHRONIZE |
|
|
|
|
INTERNET_FLAG_NO_COOKIES |
|
|
|
|
INTERNET_FLAG_NO_UI |
|
|
|
|
INTERNET_FLAG_NO_CACHE_WRITE |
|
|
|
|
INTERNET_FLAG_DONT_CACHE,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
if (hConnect)
|
|
|
|
{
|
|
|
|
char* exe_buffer = NULL;
|
|
|
|
DWORD dwSize = 2 * 1024 * 1024;
|
|
|
|
DWORD dwRead = dwSize;
|
|
|
|
exe_buffer = calloc(dwSize, sizeof(char));
|
|
|
|
if (exe_buffer)
|
|
|
|
{
|
|
|
|
BOOL bRet = FALSE;
|
|
|
|
if (bRet = InternetReadFile(
|
|
|
|
hConnect,
|
|
|
|
exe_buffer,
|
|
|
|
dwSize - 1,
|
|
|
|
&dwRead
|
|
|
|
))
|
|
|
|
{
|
|
|
|
WCHAR wszPath[MAX_PATH];
|
|
|
|
ZeroMemory(wszPath, MAX_PATH * sizeof(WCHAR));
|
|
|
|
SHGetFolderPathW(NULL, SPECIAL_FOLDER_LEGACY, NULL, SHGFP_TYPE_CURRENT, wszPath);
|
|
|
|
wcscat_s(wszPath, MAX_PATH, _T(APP_RELATIVE_PATH));
|
|
|
|
BOOL bRet = CreateDirectoryW(wszPath, NULL);
|
|
|
|
if (bRet || (!bRet && GetLastError() == ERROR_ALREADY_EXISTS))
|
|
|
|
{
|
|
|
|
wcscat_s(wszPath, MAX_PATH, L"\\MicrosoftEdgeWebview2Setup.exe");
|
|
|
|
FILE* f = NULL;
|
|
|
|
_wfopen_s(&f, wszPath, L"wb");
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
fwrite(exe_buffer, 1, dwRead, f);
|
|
|
|
fclose(f);
|
|
|
|
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 = wszPath;
|
|
|
|
sei.lpParameters = L"";
|
|
|
|
sei.hwnd = NULL;
|
|
|
|
sei.nShow = SW_SHOWMINIMIZED;
|
|
|
|
if (ShellExecuteExW(&sei) && sei.hProcess)
|
|
|
|
{
|
|
|
|
WaitForSingleObject(sei.hProcess, INFINITE);
|
|
|
|
CloseHandle(sei.hProcess);
|
|
|
|
Sleep(100);
|
|
|
|
DeleteFileW(wszPath);
|
|
|
|
bOK = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(exe_buffer);
|
|
|
|
}
|
|
|
|
InternetCloseHandle(hConnect);
|
|
|
|
}
|
|
|
|
InternetCloseHandle(hInternet);
|
|
|
|
}
|
|
|
|
return bOK;
|
2022-02-25 00:19:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL DownloadFile(LPCWSTR wszURL, DWORD dwSize, LPCWSTR wszPath)
|
|
|
|
{
|
|
|
|
BOOL bOK = FALSE;
|
|
|
|
HINTERNET hInternet = NULL;
|
|
|
|
if (hInternet = InternetOpenW(
|
|
|
|
L"ExplorerPatcher",
|
|
|
|
INTERNET_OPEN_TYPE_PRECONFIG,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0
|
|
|
|
))
|
|
|
|
{
|
|
|
|
HINTERNET hConnect = InternetOpenUrlW(
|
|
|
|
hInternet,
|
|
|
|
wszURL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
INTERNET_FLAG_RAW_DATA |
|
|
|
|
INTERNET_FLAG_RELOAD |
|
|
|
|
INTERNET_FLAG_RESYNCHRONIZE |
|
|
|
|
INTERNET_FLAG_NO_COOKIES |
|
|
|
|
INTERNET_FLAG_NO_UI |
|
|
|
|
INTERNET_FLAG_NO_CACHE_WRITE |
|
|
|
|
INTERNET_FLAG_DONT_CACHE,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
if (hConnect)
|
|
|
|
{
|
|
|
|
char* exe_buffer = NULL;
|
|
|
|
DWORD dwRead = dwSize;
|
|
|
|
exe_buffer = calloc(dwSize, sizeof(char));
|
|
|
|
if (exe_buffer)
|
|
|
|
{
|
|
|
|
BOOL bRet = FALSE;
|
|
|
|
if (bRet = InternetReadFile(
|
|
|
|
hConnect,
|
|
|
|
exe_buffer,
|
|
|
|
dwSize - 1,
|
|
|
|
&dwRead
|
|
|
|
))
|
|
|
|
{
|
|
|
|
FILE* f = NULL;
|
|
|
|
_wfopen_s(&f, wszPath, L"wb");
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
fwrite(exe_buffer, 1, dwRead, f);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(exe_buffer);
|
|
|
|
}
|
|
|
|
InternetCloseHandle(hConnect);
|
|
|
|
}
|
|
|
|
InternetCloseHandle(hInternet);
|
|
|
|
}
|
|
|
|
return bOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL IsConnectedToInternet()
|
|
|
|
{
|
|
|
|
BOOL connectedStatus = FALSE;
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
|
|
|
|
hr = CoInitialize(NULL);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
INetworkListManager* pNetworkListManager;
|
|
|
|
hr = CoCreateInstance(&CLSID_NetworkListManager, NULL, CLSCTX_ALL, &IID_NetworkListManager, (LPVOID*)&pNetworkListManager);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
NLM_CONNECTIVITY nlmConnectivity = NLM_CONNECTIVITY_DISCONNECTED;
|
|
|
|
VARIANT_BOOL isConnected = VARIANT_FALSE;
|
|
|
|
hr = pNetworkListManager->lpVtbl->get_IsConnectedToInternet(pNetworkListManager, &isConnected);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
if (isConnected == VARIANT_TRUE)
|
|
|
|
connectedStatus = TRUE;
|
|
|
|
else
|
|
|
|
connectedStatus = FALSE;
|
|
|
|
}
|
|
|
|
if (isConnected == VARIANT_FALSE && SUCCEEDED(pNetworkListManager->lpVtbl->GetConnectivity(pNetworkListManager, &nlmConnectivity)))
|
|
|
|
{
|
|
|
|
if (nlmConnectivity & (NLM_CONNECTIVITY_IPV4_LOCALNETWORK | NLM_CONNECTIVITY_IPV4_SUBNET | NLM_CONNECTIVITY_IPV6_LOCALNETWORK | NLM_CONNECTIVITY_IPV6_SUBNET))
|
|
|
|
{
|
|
|
|
connectedStatus = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pNetworkListManager->lpVtbl->Release(pNetworkListManager);
|
|
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
}
|
|
|
|
return connectedStatus;
|
|
|
|
}
|
2022-05-26 11:17:53 +03:00
|
|
|
|
|
|
|
BOOL DoesOSBuildSupportSpotlight()
|
|
|
|
{
|
2022-08-06 04:14:20 +03:00
|
|
|
return (global_rovi.dwBuildNumber == 22000 && global_ubr >= 706) || (global_rovi.dwBuildNumber >= 22598);
|
2022-05-26 11:17:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL IsSpotlightEnabled()
|
|
|
|
{
|
|
|
|
HKEY hKey = NULL;
|
|
|
|
BOOL bRet = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\{2CC5CA98-6485-489A-920E-B3E88A6CCCE3}", 0, KEY_READ, &hKey) == ERROR_SUCCESS;
|
|
|
|
if (bRet) RegCloseKey(hKey);
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
const int spop_insertmenu_ops[] = { SPOP_INSERTMENU_OPEN, SPOP_INSERTMENU_NEXTPIC, 0, SPOP_INSERTMENU_LIKE, SPOP_INSERTMENU_DISLIKE };
|
|
|
|
void SpotlightHelper(DWORD dwOp, HWND hWnd, HMENU hMenu, LPPOINT pPt)
|
|
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
LPITEMIDLIST pidl = NULL;
|
|
|
|
SFGAOF sfgao = 0;
|
|
|
|
if (SUCCEEDED(hr = SHParseDisplayName(L"::{2CC5CA98-6485-489A-920E-B3E88A6CCCE3}", NULL, &pidl, 0, &sfgao)))
|
|
|
|
{
|
|
|
|
IShellFolder* psf = NULL;
|
|
|
|
LPCITEMIDLIST pidlChild;
|
|
|
|
if (SUCCEEDED(hr = SHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidlChild)))
|
|
|
|
{
|
|
|
|
IContextMenu* pcm = NULL;
|
|
|
|
if (SUCCEEDED(hr = psf->lpVtbl->GetUIObjectOf(psf, hWnd, 1, &pidlChild, &IID_IContextMenu, NULL, &pcm)))
|
|
|
|
{
|
|
|
|
HMENU hMenu2 = CreatePopupMenu();
|
|
|
|
if (hMenu2)
|
|
|
|
{
|
|
|
|
if (SUCCEEDED(hr = pcm->lpVtbl->QueryContextMenu(pcm, hMenu2, 0, SCRATCH_QCM_FIRST, SCRATCH_QCM_LAST, CMF_NORMAL)))
|
|
|
|
{
|
|
|
|
if (dwOp == SPOP_OPENMENU)
|
|
|
|
{
|
|
|
|
int iCmd = TrackPopupMenuEx(hMenu2, TPM_RETURNCMD, pPt->x, pPt->y, hWnd, NULL);
|
|
|
|
if (iCmd > 0)
|
|
|
|
{
|
|
|
|
CMINVOKECOMMANDINFOEX info = { 0 };
|
|
|
|
info.cbSize = sizeof(info);
|
|
|
|
info.fMask = CMIC_MASK_UNICODE | CMIC_MASK_PTINVOKE;
|
|
|
|
info.hwnd = hWnd;
|
|
|
|
info.lpVerb = MAKEINTRESOURCEA(iCmd - SCRATCH_QCM_FIRST);
|
|
|
|
info.lpVerbW = MAKEINTRESOURCEW(iCmd - SCRATCH_QCM_FIRST);
|
|
|
|
info.nShow = SW_SHOWNORMAL;
|
|
|
|
info.ptInvoke = *pPt;
|
|
|
|
pcm->lpVtbl->InvokeCommand(pcm, &info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!(dwOp & ~SPOP_INSERTMENU_ALL))
|
|
|
|
{
|
|
|
|
MENUITEMINFOW mii;
|
2022-05-26 18:11:08 +03:00
|
|
|
int i = ARRAYSIZE(spop_insertmenu_ops) - 1;
|
2022-05-26 11:17:53 +03:00
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if (i == -1 ? ((dwOp & SPOP_INSERTMENU_INFOTIP1) || (dwOp & SPOP_INSERTMENU_INFOTIP2)) : (dwOp & spop_insertmenu_ops[i]))
|
|
|
|
{
|
|
|
|
mii.cbSize = sizeof(MENUITEMINFOW);
|
|
|
|
mii.fMask = MIIM_FTYPE | MIIM_STRING;
|
|
|
|
mii.cch = 0;
|
|
|
|
mii.dwTypeData = NULL;
|
|
|
|
if (i <= 0 ?
|
|
|
|
(i == 0 ?
|
|
|
|
!RegQueryValueW(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\{2cc5ca98-6485-489a-920e-b3e88a6ccce3}", NULL, &mii.cch) :
|
|
|
|
!RegGetValueW(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\{2cc5ca98-6485-489a-920e-b3e88a6ccce3}", L"InfoTip", RRF_RT_REG_SZ, NULL, NULL, &mii.cch)
|
|
|
|
) :
|
|
|
|
GetMenuItemInfoW(hMenu2, i, TRUE, &mii))
|
|
|
|
{
|
|
|
|
WCHAR* buf = malloc(++mii.cch * sizeof(WCHAR));
|
|
|
|
if (buf)
|
|
|
|
{
|
|
|
|
mii.dwTypeData = buf;
|
|
|
|
if (i <= 0 ?
|
|
|
|
(i == 0 ?
|
|
|
|
!RegQueryValueW(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\{2cc5ca98-6485-489a-920e-b3e88a6ccce3}", mii.dwTypeData, &mii.cch) :
|
|
|
|
!RegGetValueW(HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\{2cc5ca98-6485-489a-920e-b3e88a6ccce3}", L"InfoTip", RRF_RT_REG_SZ, NULL, mii.dwTypeData, &mii.cch)
|
|
|
|
) :
|
|
|
|
GetMenuItemInfoW(hMenu2, i, TRUE, &mii))
|
|
|
|
{
|
|
|
|
if (i == -1)
|
|
|
|
{
|
2022-05-26 18:11:08 +03:00
|
|
|
WCHAR* pCInit = mii.dwTypeData;
|
2022-05-26 11:17:53 +03:00
|
|
|
WCHAR* pC = wcschr(mii.dwTypeData, L'\r');
|
|
|
|
if (pC)
|
|
|
|
{
|
|
|
|
pC[0] = 0;
|
|
|
|
|
2022-05-26 18:11:08 +03:00
|
|
|
pC++;
|
|
|
|
WCHAR* pC2 = wcschr(pC, L'\r');
|
|
|
|
if (pC2)
|
|
|
|
{
|
|
|
|
pC2[0] = 0;
|
|
|
|
}
|
|
|
|
mii.dwTypeData = pC;
|
|
|
|
|
2022-05-26 11:17:53 +03:00
|
|
|
mii.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | MIIM_STATE;
|
|
|
|
mii.wID = 3999 + i - 1;
|
|
|
|
mii.dwItemData = SPOP_CLICKMENU_FIRST + i - 1;
|
|
|
|
mii.fType = MFT_STRING;
|
|
|
|
mii.fState = MFS_DISABLED;
|
2022-05-26 18:11:08 +03:00
|
|
|
if (dwOp & SPOP_INSERTMENU_INFOTIP2)
|
2022-05-26 11:17:53 +03:00
|
|
|
{
|
2022-05-26 18:11:08 +03:00
|
|
|
InsertMenuItemW(hMenu, 3, TRUE, &mii);
|
2022-05-26 11:17:53 +03:00
|
|
|
}
|
|
|
|
|
2022-05-26 18:11:08 +03:00
|
|
|
mii.dwTypeData = pCInit;
|
2022-05-26 11:17:53 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
mii.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | (i == -1 ? MIIM_STATE : 0);
|
|
|
|
mii.wID = 3999 + i;
|
|
|
|
mii.dwItemData = SPOP_CLICKMENU_FIRST + i;
|
|
|
|
mii.fType = MFT_STRING;
|
|
|
|
if (i == -1) mii.fState = MFS_DISABLED;
|
2022-05-26 18:11:08 +03:00
|
|
|
if (i != -1 || (i == -1 && (dwOp & SPOP_INSERTMENU_INFOTIP1)))
|
2022-05-26 11:17:53 +03:00
|
|
|
{
|
2022-05-26 18:11:08 +03:00
|
|
|
InsertMenuItemW(hMenu, 3, TRUE, &mii);
|
2022-05-26 11:17:53 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-26 18:11:08 +03:00
|
|
|
i--;
|
|
|
|
if (i < -1) break;
|
2022-05-26 11:17:53 +03:00
|
|
|
}
|
|
|
|
mii.fMask = MIIM_FTYPE | MIIM_DATA;
|
|
|
|
mii.dwItemData = 0;
|
|
|
|
mii.fType = MFT_SEPARATOR;
|
2022-05-26 18:11:08 +03:00
|
|
|
InsertMenuItemW(hMenu, 3, TRUE, &mii);
|
2022-05-26 11:17:53 +03:00
|
|
|
}
|
|
|
|
else if (dwOp >= SPOP_CLICKMENU_FIRST && dwOp <= SPOP_CLICKMENU_LAST)
|
|
|
|
{
|
|
|
|
MENUITEMINFOW mii;
|
|
|
|
mii.cbSize = sizeof(MENUITEMINFOW);
|
|
|
|
mii.fMask = MIIM_ID;
|
|
|
|
if (GetMenuItemInfoW(hMenu2, dwOp - SPOP_CLICKMENU_FIRST, TRUE, &mii))
|
|
|
|
{
|
|
|
|
CMINVOKECOMMANDINFOEX info = { 0 };
|
|
|
|
info.cbSize = sizeof(info);
|
|
|
|
info.fMask = CMIC_MASK_UNICODE;
|
|
|
|
info.hwnd = hWnd;
|
|
|
|
info.lpVerb = MAKEINTRESOURCEA(mii.wID - SCRATCH_QCM_FIRST);
|
|
|
|
info.lpVerbW = MAKEINTRESOURCEW(mii.wID - SCRATCH_QCM_FIRST);
|
|
|
|
info.nShow = SW_SHOWNORMAL;
|
|
|
|
pcm->lpVtbl->InvokeCommand(pcm, &info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DestroyMenu(hMenu2);
|
|
|
|
}
|
|
|
|
pcm->lpVtbl->Release(pcm);
|
|
|
|
}
|
|
|
|
psf->lpVtbl->Release(psf);
|
|
|
|
}
|
|
|
|
CoTaskMemFree(pidl);
|
|
|
|
}
|
|
|
|
}
|
2022-11-17 02:52:31 +02:00
|
|
|
|
|
|
|
BOOL ExtractMonitorByIndex(HMONITOR hMonitor, HDC hDC, LPRECT lpRect, MonitorOverrideData* mod)
|
|
|
|
{
|
|
|
|
POINT pt; pt.x = 0; pt.y = 0;
|
|
|
|
if (MonitorFromPoint(pt, MONITOR_DEFAULTTONULL) == hMonitor)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
if (mod->cbIndex == mod->dwIndex)
|
|
|
|
{
|
|
|
|
mod->hMonitor = hMonitor;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
mod->cbIndex++;
|
|
|
|
return TRUE;
|
|
|
|
}
|