Files
Katayama Hirofumi MZ cbc75d17e0 [SHLWAPI_APITEST] Add AssocQueryKey testcase (#9073)
JIRA issue: CORE-20467
Add AssocQueryKey testcase.
2026-06-05 11:17:28 +09:00

405 lines
10 KiB
C

/*
* PROJECT: ReactOS api tests
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Tests for AssocQueryKey
* COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ ([email protected])
*/
#include <apitest.h>
#include <windef.h>
#include <shlwapi.h>
#include <pseh/pseh2.h>
typedef enum _MY_KEY_INFORMATION_CLASS
{
MyKeyBasicInformation = 0,
MyKeyNodeInformation = 1,
MyKeyFullInformation = 2,
MyKeyNameInformation = 3,
} MY_KEY_INFORMATION_CLASS;
typedef struct _MY_KEY_NAME_INFORMATION
{
ULONG NameLength;
WCHAR Name[1];
} MY_KEY_NAME_INFORMATION, *PMY_KEY_NAME_INFORMATION;
// ntdll!NtQueryKey can get the key path from HKEY
typedef NTSTATUS (__stdcall *FN_NtQueryKey)(HANDLE, MY_KEY_INFORMATION_CLASS, PVOID, ULONG, PULONG);
static FN_NtQueryKey g_NtQueryKey = NULL;
static BOOL InitNtQueryKey(VOID)
{
HMODULE hNTDLL = GetModuleHandleW(L"ntdll.dll");
if (!hNTDLL) return FALSE;
g_NtQueryKey = (FN_NtQueryKey)GetProcAddress(hNTDLL, "NtQueryKey");
return g_NtQueryKey != NULL;
}
// Get path of HKEY
static LPWSTR GetKeyPath(HKEY hKey)
{
if (!g_NtQueryKey || !hKey)
return NULL;
ULONG needed = 0;
g_NtQueryKey(hKey, MyKeyNameInformation, NULL, 0, &needed);
if (!needed)
return NULL;
SIZE_T cb = needed + sizeof(WCHAR);
PBYTE buf = (PBYTE)_alloca(cb);
ZeroMemory(buf, cb);
ULONG returned = 0;
NTSTATUS status = g_NtQueryKey(hKey, MyKeyNameInformation, buf, (ULONG)cb, &returned);
if (status < 0)
return NULL;
PMY_KEY_NAME_INFORMATION info = (PMY_KEY_NAME_INFORMATION)buf;
return StrDupW(info->Name); // needs LocalFree
}
// Test ASSOCKEYs
static void TEST_AssocKeys(void)
{
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_NONE, ASSOCKEY_SHELLEXECCLASS, L".reg", NULL, &hKey);
ok_hr(hr, S_OK);
LPWSTR path = GetKeyPath(hKey);
if (hKey)
RegCloseKey(hKey);
ok(path &&
(StrStrIW(path, L"\\REGISTRY\\MACHINE\\") || StrStrIW(path, L"\\REGISTRY\\USER\\")) &&
StrStrIW(path, L"regfile"),
"path was %s\n", wine_dbgstr_w(path));
LocalFree(path);
}
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_NONE, ASSOCKEY_APP, L".reg", NULL, &hKey);
ok_hr(hr, S_OK);
LPWSTR path = GetKeyPath(hKey);
if (hKey)
RegCloseKey(hKey);
ok(path && StrStrIW(path,
L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\Applications\\regedit.exe"),
"path was %s\n", wine_dbgstr_w(path));
LocalFree(path);
}
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_NONE, ASSOCKEY_CLASS, L".reg", NULL, &hKey);
ok_hr(hr, S_OK);
LPWSTR path = GetKeyPath(hKey);
if (hKey)
RegCloseKey(hKey);
ok(path &&
(StrStrIW(path, L"\\REGISTRY\\MACHINE\\") || StrStrIW(path, L"\\REGISTRY\\USER\\")) &&
StrStrIW(path, L"Classes\\regfile"),
"path was %s\n", wine_dbgstr_w(path));
LocalFree(path);
}
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_NONE, ASSOCKEY_CLASS, L".exe", NULL, &hKey);
ok_hr(hr, S_OK);
LPWSTR path = GetKeyPath(hKey);
if (hKey)
RegCloseKey(hKey);
ok(path && !_wcsicmp(path, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\exefile"),
"path was %s\n", wine_dbgstr_w(path));
LocalFree(path);
}
}
// Test ASSOCF flags
static void TEST_AssocF_Flags(void)
{
const ASSOCF cases[] =
{
ASSOCF_NONE,
ASSOCF_INIT_NOREMAPCLSID,
ASSOCF_INIT_DEFAULTTOSTAR,
ASSOCF_INIT_DEFAULTTOFOLDER,
ASSOCF_NOUSERSETTINGS,
ASSOCF_NOTRUNCATE,
ASSOCF_VERIFY,
ASSOCF_REMAPRUNDLL,
ASSOCF_NOFIXUPS,
ASSOCF_IGNOREBASECLASS,
ASSOCF_INIT_IGNOREUNKNOWN,
ASSOCF_INIT_NOREMAPCLSID | ASSOCF_NOUSERSETTINGS,
ASSOCF_NOTRUNCATE | ASSOCF_VERIFY,
};
for (size_t i = 0; i < _countof(cases); ++i)
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(cases[i], ASSOCKEY_CLASS, L".reg", NULL, &hKey);
ok_hr(hr, S_OK);
LPWSTR path = GetKeyPath(hKey);
if (hKey)
RegCloseKey(hKey);
ok(path &&
(StrStrIW(path, L"\\REGISTRY\\MACHINE\\") || StrStrIW(path, L"\\REGISTRY\\USER\\")),
"path was %s\n", wine_dbgstr_w(path));
LocalFree(path);
}
}
// Test pszAssoc
static void TEST_PszAssoc(void)
{
const wchar_t* exts[] =
{
L".txt", L".htm", L".reg", L".xml", L".png", L".jpg", L".zip"
};
for (size_t i = 0; i < _countof(exts); ++i)
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_NONE, ASSOCKEY_CLASS, exts[i], NULL, &hKey);
ok_hr(hr, S_OK);
LPWSTR path = GetKeyPath(hKey);
if (hKey)
RegCloseKey(hKey);
ok(path &&
(StrStrIW(path, L"\\REGISTRY\\MACHINE\\") || StrStrIW(path, L"\\REGISTRY\\USER\\")),
"path was %s\n", wine_dbgstr_w(path));
LocalFree(path);
}
// Direct ProgID
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_NONE, ASSOCKEY_CLASS, L"regfile", NULL, &hKey);
ok_hr(hr, S_OK);
LPWSTR path = GetKeyPath(hKey);
if (hKey)
RegCloseKey(hKey);
ok(path &&
(StrStrIW(path, L"\\REGISTRY\\MACHINE\\") || StrStrIW(path, L"\\REGISTRY\\USER\\")) &&
StrStrIW(path, L"regfile"),
"path was %s\n", wine_dbgstr_w(path));
LocalFree(path);
}
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_NONE, ASSOCKEY_CLASS, L"exefile", NULL, &hKey);
ok_hr(hr, S_OK);
LPWSTR path = GetKeyPath(hKey);
if (hKey)
RegCloseKey(hKey);
ok(path && !_wcsicmp(path, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\exefile"),
"path was %s\n", wine_dbgstr_w(path));
LocalFree(path);
}
// ProgID: InternetShortcut
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_NONE, ASSOCKEY_CLASS, L"InternetShortcut", NULL, &hKey);
ok_hr(hr, S_OK);
if (hKey)
RegCloseKey(hKey);
}
}
// Test invalid arguments
static void TEST_InvalidArgs(void)
{
// phkeyOut == NULL
{
BOOL threw = FALSE;
HRESULT hr = E_UNEXPECTED;
_SEH2_TRY
{
hr = AssocQueryKeyW(ASSOCF_NONE, ASSOCKEY_CLASS, L".txt", NULL, NULL);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
hr = 0xDEADFACE;
threw = TRUE;
}
_SEH2_END;
ok_hr(hr, 0xDEADFACE);
ok_int(threw, TRUE);
}
// pszAssoc == NULL
{
BOOL threw = FALSE;
HRESULT hr = E_UNEXPECTED;
HKEY hKey = NULL;
_SEH2_TRY
{
hr = AssocQueryKeyW(ASSOCF_NONE, ASSOCKEY_CLASS, NULL, NULL, &hKey);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
hr = 0xDEADFACE;
threw = TRUE;
}
_SEH2_END;
ok(hKey == NULL, "hKey was not NULL\n");
if (hKey)
RegCloseKey(hKey);
ok_hr(hr, HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
ok_int(threw, FALSE);
}
// pszAssoc == ""
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_NONE, ASSOCKEY_CLASS, L"", NULL, &hKey);
if (hKey)
RegCloseKey(hKey);
ok_hr(hr, HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
}
// Invalid ASSOCKEY value
{
HKEY hKey = NULL;
BOOL threw = FALSE;
HRESULT hr = E_UNEXPECTED;
_SEH2_TRY
{
hr = AssocQueryKeyW(ASSOCF_NONE, (ASSOCKEY)0xFFFF, L".txt", NULL, &hKey);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
hr = 0xDEADFACE;
threw = TRUE;
}
_SEH2_END;
ok(hKey == NULL, "hKey was not NULL\n");
if (hKey)
RegCloseKey(hKey);
ok_hr(hr, HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
ok_int(threw, FALSE);
}
}
static void TEST_ByExeName(void)
{
WCHAR notepadPath[MAX_PATH];
GetSystemDirectoryW(notepadPath, MAX_PATH);
lstrcatW(notepadPath, L"\\notepad.exe");
// Full path
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_INIT_BYEXENAME, ASSOCKEY_APP, notepadPath, NULL, &hKey);
LPWSTR path = GetKeyPath(hKey);
if (hKey)
RegCloseKey(hKey);
ok_hr(hr, S_OK);
ok(path &&
!_wcsicmp(path, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\Applications\\notepad.exe"),
"path was %s\n", wine_dbgstr_w(path));
LocalFree(path);
}
// Short name
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_OPEN_BYEXENAME, ASSOCKEY_APP,
L"regedit.exe", NULL, &hKey);
LPWSTR path = GetKeyPath(hKey);
if (hKey)
RegCloseKey(hKey);
ok_hr(hr, S_OK);
ok(path &&
!_wcsicmp(path, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\Applications\\regedit.exe"),
"path was %s\n", wine_dbgstr_w(path));
LocalFree(path);
}
// Non existent
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_INIT_BYEXENAME, ASSOCKEY_APP,
L"__ghost__.exe", NULL, &hKey);
ok(hKey == NULL, "hKey was not NULL\n");
if (hKey)
RegCloseKey(hKey);
ok(FAILED(hr), "hr was 0x%08lX\n", hr);
}
}
// Check ASSOCKEY_SHELLEXECCLASS
static void TEST_ShellExecClass(void)
{
static const LPCWSTR cases[] = { L".txt", L".htm", L".html", L"txtfile" };
for (size_t i = 0; i < _countof(cases); ++i)
{
HKEY hKey = NULL;
HRESULT hr = AssocQueryKeyW(ASSOCF_NONE, ASSOCKEY_SHELLEXECCLASS, cases[i], NULL, &hKey);
ok_hr(hr, S_OK);
LPWSTR path = GetKeyPath(hKey);
if (hKey)
RegCloseKey(hKey);
ok(path && StrStrIW(path, L"\\REGISTRY\\MACHINE\\SOFTWARE\\Classes\\"),
"path was %s\n", wine_dbgstr_w(path));
LocalFree(path);
}
}
START_TEST(AssocQueryKey)
{
if (!InitNtQueryKey())
{
skip("NtQueryKey not found\n");
return;
}
HRESULT hrCoInit = CoInitialize(NULL);
TEST_AssocKeys();
TEST_AssocF_Flags();
TEST_PszAssoc();
TEST_InvalidArgs();
TEST_ByExeName();
TEST_ShellExecClass();
if (SUCCEEDED(hrCoInit))
CoUninitialize();
}