From: The Wine Synchronizer Date: Fri, 4 Apr 2008 16:43:16 +0000 (+0000) Subject: Autosyncing with Wine HEAD X-Git-Tag: backups/hyperion@33110~227 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=bd382346bb80fe847d746058ef245964d6bc6196 Autosyncing with Wine HEAD svn path=/trunk/; revision=32862 --- diff --git a/rostests/winetests/advpack/advpack.c b/rostests/winetests/advpack/advpack.c index b09a9c6158c..b90df2d4b65 100644 --- a/rostests/winetests/advpack/advpack.c +++ b/rostests/winetests/advpack/advpack.c @@ -35,6 +35,7 @@ #define REG_VAL_EXISTS(key, value) !RegQueryValueEx(key, value, NULL, NULL, NULL, NULL) #define OPEN_GUID_KEY() !RegOpenKey(HKEY_LOCAL_MACHINE, GUID_KEY, &guid) +static HMODULE hAdvPack; static HRESULT (WINAPI *pCloseINFEngine)(HINF); static HRESULT (WINAPI *pDelNode)(LPCSTR,DWORD); static HRESULT (WINAPI *pGetVersionFromFile)(LPCSTR,LPDWORD,LPDWORD,BOOL); @@ -66,7 +67,7 @@ static void get_progfiles_dir(void) static BOOL init_function_pointers(void) { - HMODULE hAdvPack = LoadLibraryA("advpack.dll"); + hAdvPack = LoadLibraryA("advpack.dll"); if (!hAdvPack) return FALSE; @@ -521,7 +522,7 @@ static void setperusersecvalues_test(void) /* set initial values */ lstrcpy(peruser.szGUID, "guid"); hr = pSetPerUserSecValues(&peruser); - ok(hr == S_OK, "Expected S_OK, got %d\n", hr); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(OPEN_GUID_KEY(), "Expected guid key to exist\n"); ok(check_reg_str(guid, NULL, "displayname"), "Expected displayname\n"); ok(check_reg_str(guid, "ComponentID", "compid"), "Expected compid\n"); @@ -538,7 +539,7 @@ static void setperusersecvalues_test(void) /* raise the version, but bRollback is FALSE, so vals not saved */ lstrcpy(peruser.szVersion, "2,1,1,1"); hr = pSetPerUserSecValues(&peruser); - ok(hr == S_OK, "Expected S_OK, got %d\n", hr); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(check_reg_str(guid, NULL, "displayname"), "Expected displayname\n"); ok(check_reg_str(guid, "ComponentID", "compid"), "Expected compid\n"); ok(check_reg_str(guid, "Locale", "locale"), "Expected locale\n"); @@ -555,7 +556,7 @@ static void setperusersecvalues_test(void) peruser.bRollback = TRUE; lstrcpy(peruser.szVersion, "3,1,1,1"); hr = pSetPerUserSecValues(&peruser); - ok(hr == S_OK, "Expected S_OK, got %d\n", hr); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(check_reg_str(guid, NULL, "displayname"), "Expected displayname\n"); ok(check_reg_str(guid, "ComponentID", "compid"), "Expected compid\n"); ok(check_reg_str(guid, "Locale", "locale"), "Expected locale\n"); @@ -594,4 +595,6 @@ START_TEST(advpack) setperusersecvalues_test(); translateinfstring_test(); translateinfstringex_test(); + + FreeLibrary(hAdvPack); } diff --git a/rostests/winetests/advpack/advpack.rbuild b/rostests/winetests/advpack/advpack.rbuild index baabd337d90..09e93fde4d9 100644 --- a/rostests/winetests/advpack/advpack.rbuild +++ b/rostests/winetests/advpack/advpack.rbuild @@ -1,17 +1,18 @@ + . 0x600 0x600 + advpack.c + files.c + install.c + testlist.c wine cabinet - user32 advapi32 kernel32 ntdll - advpack.c - files.c - install.c - testlist.c + diff --git a/rostests/winetests/advpack/files.c b/rostests/winetests/advpack/files.c index 71c1741d957..e109a88aacc 100644 --- a/rostests/winetests/advpack/files.c +++ b/rostests/winetests/advpack/files.c @@ -560,4 +560,6 @@ START_TEST(files) test_AdvInstallFile(); delete_test_files(); + + FreeLibrary(hAdvPack); } diff --git a/rostests/winetests/advpack/install.c b/rostests/winetests/advpack/install.c index 607596347f5..564ecda71c9 100644 --- a/rostests/winetests/advpack/install.c +++ b/rostests/winetests/advpack/install.c @@ -23,6 +23,7 @@ #include #include "wine/test.h" +static HMODULE hAdvPack; /* function pointers */ static HRESULT (WINAPI *pRunSetupCommand)(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, HANDLE*, DWORD, LPVOID); static HRESULT (WINAPI *pLaunchINFSection)(HWND, HINSTANCE, LPSTR, INT); @@ -32,7 +33,7 @@ static char CURR_DIR[MAX_PATH]; static BOOL init_function_pointers(void) { - HMODULE hAdvPack = LoadLibraryA("advpack.dll"); + hAdvPack = LoadLibraryA("advpack.dll"); if (!hAdvPack) return FALSE; @@ -273,4 +274,6 @@ START_TEST(install) test_RunSetupCommand(); test_LaunchINFSection(); test_LaunchINFSectionEx(); + + FreeLibrary(hAdvPack); } diff --git a/rostests/winetests/cabinet/cabinet.rbuild b/rostests/winetests/cabinet/cabinet.rbuild index c119392bc1a..dcac40f8af4 100644 --- a/rostests/winetests/cabinet/cabinet.rbuild +++ b/rostests/winetests/cabinet/cabinet.rbuild @@ -1,15 +1,16 @@ + . 0x600 0x600 + extract.c + fdi.c + testlist.c wine cabinet - user32 kernel32 ntdll - extract.c - fdi.c - testlist.c + diff --git a/rostests/winetests/cabinet/extract.c b/rostests/winetests/cabinet/extract.c index 2cf5154b7af..156df177a9b 100644 --- a/rostests/winetests/cabinet/extract.c +++ b/rostests/winetests/cabinet/extract.c @@ -28,7 +28,7 @@ #define MEDIA_SIZE 999999999 #define FOLDER_THRESHOLD 900000 -/* The following defintions were copied from dlls/cabinet/cabinet.h +/* The following definitions were copied from dlls/cabinet/cabinet.h * because they are undocumented in windows. */ diff --git a/rostests/winetests/cabinet/fdi.c b/rostests/winetests/cabinet/fdi.c index 7c10b3d1663..18745f26061 100644 --- a/rostests/winetests/cabinet/fdi.c +++ b/rostests/winetests/cabinet/fdi.c @@ -92,10 +92,6 @@ static void test_FDICreate(void) HFDI hfdi; ERF erf; - erf.erfOper = 0xcafefeed; - erf.erfType = 0xdeadbabe; - erf.fError = 0xdecaface; - /* native crashes if pfnalloc is NULL */ /* FDICreate does not crash with a NULL pfnfree, @@ -104,6 +100,9 @@ static void test_FDICreate(void) if (0) { SetLastError(0xdeadbeef); + erf.erfOper = 0xcafefeed; + erf.erfType = 0xdeadbabe; + erf.fError = 0xdecaface; hfdi = FDICreate(fdi_alloc, NULL, fdi_open, fdi_read, fdi_write, fdi_close, fdi_seek, cpuUNKNOWN, &erf); @@ -118,99 +117,121 @@ static void test_FDICreate(void) } SetLastError(0xdeadbeef); + erf.erfOper = 0xcafefeed; + erf.erfType = 0xdeadbabe; + erf.fError = 0xdecaface; hfdi = FDICreate(fdi_alloc, fdi_free, NULL, fdi_read, fdi_write, fdi_close, fdi_seek, cpuUNKNOWN, &erf); ok(hfdi != NULL, "Expected non-NULL context\n"); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); - ok(erf.erfOper == 0xcafefeed, "Expected 0xcafefeed, got %d\n", erf.erfOper); - ok(erf.erfType == 0xdeadbabe, "Expected 0xdeadbabe, got %d\n", erf.erfType); - ok(erf.fError == 0xdecaface, "Expected 0xdecaface, got %d\n", erf.fError); + ok((erf.erfOper == 0xcafefeed || erf.erfOper == 0 /* Vista */), "Expected 0xcafefeed or 0, got %d\n", erf.erfOper); + ok((erf.erfType == 0xdeadbabe || erf.erfType == 0 /* Vista */), "Expected 0xdeadbabe or 0, got %d\n", erf.erfType); + ok((erf.fError == 0xdecaface || erf.fError == 0 /* Vista */), "Expected 0xdecaface or 0, got %d\n", erf.fError); FDIDestroy(hfdi); SetLastError(0xdeadbeef); + erf.erfOper = 0xcafefeed; + erf.erfType = 0xdeadbabe; + erf.fError = 0xdecaface; hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, NULL, fdi_write, fdi_close, fdi_seek, cpuUNKNOWN, &erf); ok(hfdi != NULL, "Expected non-NULL context\n"); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); - ok(erf.erfOper == 0xcafefeed, "Expected 0xcafefeed, got %d\n", erf.erfOper); - ok(erf.erfType == 0xdeadbabe, "Expected 0xdeadbabe, got %d\n", erf.erfType); - ok(erf.fError == 0xdecaface, "Expected 0xdecaface, got %d\n", erf.fError); + ok((erf.erfOper == 0xcafefeed || erf.erfOper == 0 /* Vista */), "Expected 0xcafefeed or 0, got %d\n", erf.erfOper); + ok((erf.erfType == 0xdeadbabe || erf.erfType == 0 /* Vista */), "Expected 0xdeadbabe or 0, got %d\n", erf.erfType); + ok((erf.fError == 0xdecaface || erf.fError == 0 /* Vista */), "Expected 0xdecaface or 0, got %d\n", erf.fError); FDIDestroy(hfdi); SetLastError(0xdeadbeef); + erf.erfOper = 0xcafefeed; + erf.erfType = 0xdeadbabe; + erf.fError = 0xdecaface; hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read, NULL, fdi_close, fdi_seek, cpuUNKNOWN, &erf); ok(hfdi != NULL, "Expected non-NULL context\n"); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); - ok(erf.erfOper == 0xcafefeed, "Expected 0xcafefeed, got %d\n", erf.erfOper); - ok(erf.erfType == 0xdeadbabe, "Expected 0xdeadbabe, got %d\n", erf.erfType); - ok(erf.fError == 0xdecaface, "Expected 0xdecaface, got %d\n", erf.fError); + ok((erf.erfOper == 0xcafefeed || erf.erfOper == 0 /* Vista */), "Expected 0xcafefeed or 0, got %d\n", erf.erfOper); + ok((erf.erfType == 0xdeadbabe || erf.erfType == 0 /* Vista */), "Expected 0xdeadbabe or 0, got %d\n", erf.erfType); + ok((erf.fError == 0xdecaface || erf.fError == 0 /* Vista */), "Expected 0xdecaface or 0, got %d\n", erf.fError); FDIDestroy(hfdi); SetLastError(0xdeadbeef); + erf.erfOper = 0xcafefeed; + erf.erfType = 0xdeadbabe; + erf.fError = 0xdecaface; hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read, fdi_write, NULL, fdi_seek, cpuUNKNOWN, &erf); ok(hfdi != NULL, "Expected non-NULL context\n"); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); - ok(erf.erfOper == 0xcafefeed, "Expected 0xcafefeed, got %d\n", erf.erfOper); - ok(erf.erfType == 0xdeadbabe, "Expected 0xdeadbabe, got %d\n", erf.erfType); - ok(erf.fError == 0xdecaface, "Expected 0xdecaface, got %d\n", erf.fError); + ok((erf.erfOper == 0xcafefeed || erf.erfOper == 0 /* Vista */), "Expected 0xcafefeed or 0, got %d\n", erf.erfOper); + ok((erf.erfType == 0xdeadbabe || erf.erfType == 0 /* Vista */), "Expected 0xdeadbabe or 0, got %d\n", erf.erfType); + ok((erf.fError == 0xdecaface || erf.fError == 0 /* Vista */), "Expected 0xdecaface or 0, got %d\n", erf.fError); FDIDestroy(hfdi); SetLastError(0xdeadbeef); + erf.erfOper = 0xcafefeed; + erf.erfType = 0xdeadbabe; + erf.fError = 0xdecaface; hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read, fdi_write, fdi_close, NULL, cpuUNKNOWN, &erf); ok(hfdi != NULL, "Expected non-NULL context\n"); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); - ok(erf.erfOper == 0xcafefeed, "Expected 0xcafefeed, got %d\n", erf.erfOper); - ok(erf.erfType == 0xdeadbabe, "Expected 0xdeadbabe, got %d\n", erf.erfType); - ok(erf.fError == 0xdecaface, "Expected 0xdecaface, got %d\n", erf.fError); + ok((erf.erfOper == 0xcafefeed || erf.erfOper == 0 /* Vista */), "Expected 0xcafefeed or 0, got %d\n", erf.erfOper); + ok((erf.erfType == 0xdeadbabe || erf.erfType == 0 /* Vista */), "Expected 0xdeadbabe or 0, got %d\n", erf.erfType); + ok((erf.fError == 0xdecaface || erf.fError == 0 /* Vista */), "Expected 0xdecaface or 0, got %d\n", erf.fError); FDIDestroy(hfdi); SetLastError(0xdeadbeef); + erf.erfOper = 0xcafefeed; + erf.erfType = 0xdeadbabe; + erf.fError = 0xdecaface; hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read, fdi_write, fdi_close, fdi_seek, cpuUNKNOWN, NULL); - ok(hfdi != NULL, "Expected non-NULL context\n"); + /* XP sets hfdi to a non-NULL value, but Vista sets it to NULL! */ ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); - ok(erf.erfOper == 0xcafefeed, "Expected 0xcafefeed, got %d\n", erf.erfOper); - ok(erf.erfType == 0xdeadbabe, "Expected 0xdeadbabe, got %d\n", erf.erfType); - ok(erf.fError == 0xdecaface, "Expected 0xdecaface, got %d\n", erf.fError); + /* NULL is passed to FDICreate instead of &erf, so don't retest the erf member values. */ FDIDestroy(hfdi); /* bad cpu type */ SetLastError(0xdeadbeef); + erf.erfOper = 0xcafefeed; + erf.erfType = 0xdeadbabe; + erf.fError = 0xdecaface; hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read, fdi_write, fdi_close, fdi_seek, 0xcafebabe, &erf); ok(hfdi != NULL, "Expected non-NULL context\n"); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); - ok(erf.erfOper == 0xcafefeed, "Expected 0xcafefeed, got %d\n", erf.erfOper); - ok(erf.erfType == 0xdeadbabe, "Expected 0xdeadbabe, got %d\n", erf.erfType); - ok(erf.fError == 0xdecaface, "Expected 0xdecaface, got %d\n", erf.fError); + ok((erf.erfOper == 0xcafefeed || erf.erfOper == 0 /* Vista */), "Expected 0xcafefeed or 0, got %d\n", erf.erfOper); + ok((erf.erfType == 0xdeadbabe || erf.erfType == 0 /* Vista */), "Expected 0xdeadbabe or 0, got %d\n", erf.erfType); + ok((erf.fError == 0xdecaface || erf.fError == 0 /* Vista */), "Expected 0xdecaface or 0, got %d\n", erf.fError); FDIDestroy(hfdi); /* pfnalloc fails */ SetLastError(0xdeadbeef); + erf.erfOper = 0xcafefeed; + erf.erfType = 0xdeadbabe; + erf.fError = 0xdecaface; hfdi = FDICreate(fdi_alloc_bad, fdi_free, fdi_open, fdi_read, fdi_write, fdi_close, fdi_seek, cpuUNKNOWN, &erf); diff --git a/rostests/winetests/comcat/comcat.rbuild b/rostests/winetests/comcat/comcat.rbuild index 7fe8a38683f..dc42865a654 100644 --- a/rostests/winetests/comcat/comcat.rbuild +++ b/rostests/winetests/comcat/comcat.rbuild @@ -1,15 +1,17 @@ + . 0x600 0x600 + comcat.c + testlist.c wine ole32 advapi32 kernel32 uuid ntdll - comcat.c - testlist.c + diff --git a/rostests/winetests/comctl32/comboex.c b/rostests/winetests/comctl32/comboex.c index f3f46b3da36..ad58643f648 100644 --- a/rostests/winetests/comctl32/comboex.c +++ b/rostests/winetests/comctl32/comboex.c @@ -187,10 +187,23 @@ static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, L return 0L; } -static void init(void) { +static int init(void) +{ + HMODULE hComctl32; + BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); WNDCLASSA wc; - - InitCommonControls(); + INITCOMMONCONTROLSEX iccex; + + hComctl32 = GetModuleHandleA("comctl32.dll"); + pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); + if (!pInitCommonControlsEx) + { + skip("InitCommonControlsEx() is missing. Skipping the tests\n"); + return 0; + } + iccex.dwSize = sizeof(iccex); + iccex.dwICC = ICC_USEREX_CLASSES; + pInitCommonControlsEx(&iccex); wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; @@ -209,7 +222,7 @@ static void init(void) { assert(hComboExParentWnd != NULL); hMainHinst = GetModuleHandleA(NULL); - + return 1; } static void cleanup(void) @@ -227,7 +240,8 @@ static void cleanup(void) START_TEST(comboex) { - init(); + if (!init()) + return; test_comboboxex(); diff --git a/rostests/winetests/comctl32/comctl32.rbuild b/rostests/winetests/comctl32/comctl32.rbuild index f7ed7ae4fc4..307b6dcb217 100644 --- a/rostests/winetests/comctl32/comctl32.rbuild +++ b/rostests/winetests/comctl32/comctl32.rbuild @@ -5,14 +5,6 @@ . 0x600 0x600 - wine - comctl32 - ole32 - user32 - gdi32 - advapi32 - kernel32 - ntdll comboex.c datetime.c dpa.c @@ -36,5 +28,13 @@ updown.c rsrc.rc testlist.c + wine + comctl32 + ole32 + user32 + gdi32 + advapi32 + kernel32 + ntdll diff --git a/rostests/winetests/comctl32/datetime.c b/rostests/winetests/comctl32/datetime.c index 956f16e9db7..b194cc1b6ae 100644 --- a/rostests/winetests/comctl32/datetime.c +++ b/rostests/winetests/comctl32/datetime.c @@ -112,6 +112,7 @@ static const struct message test_dtm_set_range_swap_min_max_seq[] = { static const struct message test_dtm_set_and_get_system_time_seq[] = { { DTM_SETSYSTEMTIME, sent|wparam, 0x00000001 }, + { 0x0090, sent|optional }, /* Vista */ { WM_DESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 }, { WM_NCDESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 }, { DTM_SETSYSTEMTIME, sent|wparam, 0x00000001 }, @@ -125,6 +126,7 @@ static const struct message test_dtm_set_and_get_system_time_seq[] = { }; static const struct message destroy_window_seq[] = { + { 0x0090, sent|optional }, /* Vista */ { WM_DESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 }, { WM_NCDESTROY, sent|wparam|lparam, 0x00000000, 0x00000000 }, { 0 } @@ -191,6 +193,8 @@ static HWND create_datetime_control(DWORD style, DWORD exstyle) static void test_dtm_set_format(HWND hWndDateTime) { + CHAR txt[256]; + SYSTEMTIME systime; LRESULT r; r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0, (LPARAM)NULL); @@ -201,6 +205,17 @@ static void test_dtm_set_format(HWND hWndDateTime) expect(1, r); ok_sequence(sequences, DATETIME_SEQ_INDEX, test_dtm_set_format_seq, "test_dtm_set_format", FALSE); + + r = SendMessage(hWndDateTime, DTM_SETFORMAT, 0, + (LPARAM)"'hh' hh"); + expect(1, r); + ZeroMemory(&systime, sizeof(systime)); + systime.wYear = 2000; + systime.wMonth = systime.wDay = 1; + r = SendMessage(hWndDateTime, DTM_SETSYSTEMTIME, 0, (LPARAM)&systime); + expect(1, r); + GetWindowText(hWndDateTime, txt, 256); + todo_wine ok(strcmp(txt, "hh 12") == 0, "String mismatch (\"%s\" vs \"hh 12\")\n", txt); flush_sequences(sequences, NUM_MSG_SEQUENCES); } @@ -311,7 +326,7 @@ static void test_dtm_set_and_get_range(HWND hWndDateTime) /* initialize st[0] to lowest possible value */ fill_systime_struct(&st[0], 1601, 1, 0, 1, 0, 0, 0, 0); - /* intialize st[1] to all invalid numbers */ + /* initialize st[1] to all invalid numbers */ fill_systime_struct(&st[1], 0, 0, 7, 0, 24, 60, 60, 1000); r = SendMessage(hWndDateTime, DTM_SETRANGE, GDTR_MIN, (LPARAM)st); @@ -560,7 +575,21 @@ static void test_datetime_control(void) START_TEST(datetime) { - InitCommonControls(); + HMODULE hComctl32; + BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); + INITCOMMONCONTROLSEX iccex; + + hComctl32 = GetModuleHandleA("comctl32.dll"); + pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); + if (!pInitCommonControlsEx) + { + skip("InitCommonControlsEx() is missing. Skipping the tests\n"); + return; + } + iccex.dwSize = sizeof(iccex); + iccex.dwICC = ICC_DATE_CLASSES; + pInitCommonControlsEx(&iccex); + init_msg_sequences(sequences, NUM_MSG_SEQUENCES); test_datetime_control(); diff --git a/rostests/winetests/comctl32/dpa.c b/rostests/winetests/comctl32/dpa.c index f1ca8f23e25..b2ea3d8c327 100644 --- a/rostests/winetests/comctl32/dpa.c +++ b/rostests/winetests/comctl32/dpa.c @@ -219,7 +219,7 @@ static void test_dpa(void) /* Set item with out of bound index */ ok(pDPA_SetPtr(dpa, 1, (PVOID)6), "\n"); - /* Fill the greated gap */ + /* Fill the created gap */ ok(pDPA_SetPtr(dpa, 0, (PVOID)5), "\n"); rc=CheckDPA(dpa, 0x56, &dw); ok(rc, "dw=0x%x\n", dw); @@ -454,6 +454,4 @@ START_TEST(dpa) test_dpa(); else trace("skipping tests\n"); - - FreeLibrary(hcomctl32); } diff --git a/rostests/winetests/comctl32/header.c b/rostests/winetests/comctl32/header.c index fa75d49046f..6f8b46250f8 100644 --- a/rostests/winetests/comctl32/header.c +++ b/rostests/winetests/comctl32/header.c @@ -1156,7 +1156,7 @@ static void test_hdm_index_messages(HWND hParent) ok_sequence(sequences, HEADER_SEQ_INDEX, orderArray_seq, "set_get_orderArray sequence testing", FALSE); - /* check if the array order is set correctly and the size of the array is corret. */ + /* check if the array order is set correctly and the size of the array is correct. */ expect(2, iSize); expect(lpiarray[0], lpiarrayReceived[0]); expect(lpiarray[1], lpiarrayReceived[1]); @@ -1480,10 +1480,24 @@ static LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LP return 0L; } -static void init(void) { +static int init(void) +{ + HMODULE hComctl32; + BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); WNDCLASSA wc; + INITCOMMONCONTROLSEX iccex; + + hComctl32 = GetModuleHandleA("comctl32.dll"); + pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); + if (!pInitCommonControlsEx) + { + skip("InitCommonControlsEx() is missing. Skipping the tests\n"); + return 0; + } - InitCommonControls(); + iccex.dwSize = sizeof(iccex); + iccex.dwICC = ICC_USEREX_CLASSES; + pInitCommonControlsEx(&iccex); wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; @@ -1503,13 +1517,15 @@ static void init(void) { NULL, NULL, GetModuleHandleA(NULL), 0); assert(hHeaderParentWnd != NULL); ShowWindow(hHeaderParentWnd, SW_SHOW); + return 1; } START_TEST(header) { HWND parent_hwnd; - init(); + if (!init()) + return; test_header_control(); test_header_order(); diff --git a/rostests/winetests/comctl32/listview.c b/rostests/winetests/comctl32/listview.c index 30a81a8948f..ad82579af00 100644 --- a/rostests/winetests/comctl32/listview.c +++ b/rostests/winetests/comctl32/listview.c @@ -539,6 +539,44 @@ static void test_checkboxes(void) r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); ok(item.state == 0x1aaa, "state %x\n", item.state); + /* Toggle checkbox tests (bug 9934) */ + memset (&item, 0xcc, sizeof(item)); + item.mask = LVIF_STATE; + item.iItem = 3; + item.iSubItem = 0; + item.state = LVIS_FOCUSED; + item.stateMask = LVIS_FOCUSED; + r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item); + expect(1, r); + + item.iItem = 3; + item.mask = LVIF_STATE; + item.stateMask = 0xffff; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); + ok(item.state == 0x1aab, "state %x\n", item.state); + + r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0); + expect(0, r); + r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0); + expect(0, r); + + item.iItem = 3; + item.mask = LVIF_STATE; + item.stateMask = 0xffff; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); + ok(item.state == 0x2aab, "state %x\n", item.state); + + r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0); + expect(0, r); + r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0); + expect(0, r); + + item.iItem = 3; + item.mask = LVIF_STATE; + item.stateMask = 0xffff; + r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item); + ok(item.state == 0x1aab, "state %x\n", item.state); + DestroyWindow(hwnd); } @@ -547,7 +585,7 @@ static void insert_column(HWND hwnd, int idx) LVCOLUMN column; DWORD rc; - memset(&column, 0xaa, sizeof(column)); + memset(&column, 0xcc, sizeof(column)); column.mask = LVCF_SUBITEM; column.iSubItem = idx; @@ -562,7 +600,7 @@ static void insert_item(HWND hwnd, int idx) LVITEMA item; DWORD rc; - memset(&item, 0xaa, sizeof (item)); + memset(&item, 0xcc, sizeof (item)); item.mask = LVIF_TEXT; item.iItem = idx; item.iSubItem = 0; @@ -593,7 +631,7 @@ static void test_items(void) insert_column(hwnd, 1); /* Insert an item with just a param */ - memset (&item, 0xaa, sizeof (item)); + memset (&item, 0xcc, sizeof (item)); item.mask = LVIF_PARAM; item.iItem = 0; item.iSubItem = 0; @@ -602,7 +640,7 @@ static void test_items(void) ok(r == 0, "ret %d\n", r); /* Test getting of the param */ - memset (&item, 0xaa, sizeof (item)); + memset (&item, 0xcc, sizeof (item)); item.mask = LVIF_PARAM; item.iItem = 0; item.iSubItem = 0; @@ -611,7 +649,7 @@ static void test_items(void) ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest); /* Set up a subitem */ - memset (&item, 0xaa, sizeof (item)); + memset (&item, 0xcc, sizeof (item)); item.mask = LVIF_TEXT; item.iItem = 0; item.iSubItem = 1; @@ -620,7 +658,7 @@ static void test_items(void) ok(r != 0, "ret %d\n", r); /* Query param from subitem: returns main item param */ - memset (&item, 0xaa, sizeof (item)); + memset (&item, 0xcc, sizeof (item)); item.mask = LVIF_PARAM; item.iItem = 0; item.iSubItem = 1; @@ -629,7 +667,7 @@ static void test_items(void) ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest); /* Set up param on first subitem: no effect */ - memset (&item, 0xaa, sizeof (item)); + memset (&item, 0xcc, sizeof (item)); item.mask = LVIF_PARAM; item.iItem = 0; item.iSubItem = 1; @@ -638,7 +676,7 @@ static void test_items(void) ok(r == 0, "ret %d\n", r); /* Query param from subitem again: should still return main item param */ - memset (&item, 0xaa, sizeof (item)); + memset (&item, 0xcc, sizeof (item)); item.mask = LVIF_PARAM; item.iItem = 0; item.iSubItem = 1; @@ -647,7 +685,7 @@ static void test_items(void) ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest); /**** Some tests of state highlighting ****/ - memset (&item, 0xaa, sizeof (item)); + memset (&item, 0xcc, sizeof (item)); item.mask = LVIF_STATE; item.iItem = 0; item.iSubItem = 0; @@ -660,7 +698,7 @@ static void test_items(void) r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item); ok(r != 0, "ret %d\n", r); - memset (&item, 0xaa, sizeof (item)); + memset (&item, 0xcc, sizeof (item)); item.mask = LVIF_STATE; item.iItem = 0; item.iSubItem = 0; @@ -687,7 +725,7 @@ static void test_columns(void) ok(hwnd != NULL, "failed to create listview window\n"); /* Add a column with no mask */ - memset(&column, 0xaa, sizeof(column)); + memset(&column, 0xcc, sizeof(column)); column.mask = 0; rc = ListView_InsertColumn(hwnd, 0, &column); ok(rc==0, "Inserting column with no mask failed with %d\n", rc); @@ -1040,7 +1078,20 @@ static void test_item_position(void) START_TEST(listview) { - InitCommonControls(); + HMODULE hComctl32; + BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); + + hComctl32 = GetModuleHandleA("comctl32.dll"); + pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); + if (pInitCommonControlsEx) + { + INITCOMMONCONTROLSEX iccex; + iccex.dwSize = sizeof(iccex); + iccex.dwICC = ICC_LISTVIEW_CLASSES; + pInitCommonControlsEx(&iccex); + } + else + InitCommonControls(); init_msg_sequences(sequences, NUM_MSG_SEQUENCES); diff --git a/rostests/winetests/comctl32/monthcal.c b/rostests/winetests/comctl32/monthcal.c index d670004f8ad..7f3b4e53ab6 100644 --- a/rostests/winetests/comctl32/monthcal.c +++ b/rostests/winetests/comctl32/monthcal.c @@ -281,6 +281,7 @@ static const struct message destroy_monthcal_parent_msgs_seq[] = { /* expected message sequence for child*/ static const struct message destroy_monthcal_child_msgs_seq[] = { + { 0x0090, sent|optional }, /* Vista */ { WM_SHOWWINDOW, sent|wparam|lparam, 0, 0}, { WM_WINDOWPOSCHANGING, sent|wparam, 0}, { WM_WINDOWPOSCHANGED, sent|wparam, 0}, @@ -290,6 +291,7 @@ static const struct message destroy_monthcal_child_msgs_seq[] = { }; static const struct message destroy_monthcal_multi_sel_style_seq[] = { + { 0x0090, sent|optional }, /* Vista */ { WM_DESTROY, sent|wparam|lparam, 0, 0}, { WM_NCDESTROY, sent|wparam|lparam, 0, 0}, { 0 } @@ -297,6 +299,7 @@ static const struct message destroy_monthcal_multi_sel_style_seq[] = { /* expected message sequence for parent window*/ static const struct message destroy_parent_seq[] = { + { 0x0090, sent|optional }, /* Vista */ { WM_WINDOWPOSCHANGING, sent|wparam, 0}, { WM_WINDOWPOSCHANGED, sent|wparam, 0}, { WM_NCACTIVATE, sent|wparam|lparam, 0, 0}, @@ -316,7 +319,6 @@ static void test_monthcal(void) SYSTEMTIME st[2], st1[2]; int res, month_range; - InitCommonControls(); hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, 0, 300, 300, 0, 0, NULL, NULL); ok(hwnd != NULL, "Failed to create MonthCal\n"); @@ -479,8 +481,6 @@ static HWND create_monthcal_control(DWORD style, HWND parent_window) struct subclass_info *info; HWND hwnd; - InitCommonControls(); - info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info)); if (!info) return NULL; @@ -720,7 +720,7 @@ static void test_monthcal_unicode(HWND hwnd) static void test_monthcal_HitTest(HWND hwnd) { MCHITTESTINFO mchit; - int res; + UINT res; SYSTEMTIME st; memset(&mchit, 0, sizeof(MCHITTESTINFO)); @@ -912,7 +912,7 @@ static void test_monthcal_todaylink(HWND hwnd) MCHITTESTINFO mchit; SYSTEMTIME st_test, st_new; BOOL error = FALSE; - int res; + UINT res; memset(&mchit, 0, sizeof(MCHITTESTINFO)); @@ -1110,7 +1110,22 @@ static void test_monthcal_MaxSelDay(HWND hwnd) START_TEST(monthcal) { + HMODULE hComctl32; + BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); + INITCOMMONCONTROLSEX iccex; HWND hwnd, parent_wnd; + + hComctl32 = GetModuleHandleA("comctl32.dll"); + pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); + if (!pInitCommonControlsEx) + { + skip("InitCommonControlsEx() is missing. Skipping the tests\n"); + return; + } + iccex.dwSize = sizeof(iccex); + iccex.dwICC = ICC_DATE_CLASSES; + pInitCommonControlsEx(&iccex); + test_monthcal(); init_msg_sequences(sequences, NUM_MSG_SEQUENCES); diff --git a/rostests/winetests/comctl32/progress.c b/rostests/winetests/comctl32/progress.c index 2716f3356b4..10bbbef8a28 100644 --- a/rostests/winetests/comctl32/progress.c +++ b/rostests/winetests/comctl32/progress.c @@ -90,10 +90,22 @@ static void update_window(HWND hWnd) static void init(void) { + HMODULE hComctl32; + BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); WNDCLASSA wc; RECT rect; - InitCommonControls(); + hComctl32 = GetModuleHandleA("comctl32.dll"); + pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); + if (pInitCommonControlsEx) + { + INITCOMMONCONTROLSEX iccex; + iccex.dwSize = sizeof(iccex); + iccex.dwICC = ICC_PROGRESS_CLASS; + pInitCommonControlsEx(&iccex); + } + else + InitCommonControls(); wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; diff --git a/rostests/winetests/comctl32/rebar.c b/rostests/winetests/comctl32/rebar.c index 6bebeb770a4..e5bea381025 100644 --- a/rostests/winetests/comctl32/rebar.c +++ b/rostests/winetests/comctl32/rebar.c @@ -17,6 +17,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +/* make sure the structures work with a comctl32 v5.x */ +#define _WIN32_WINNT 0x500 +#define _WIN32_IE 0x500 + #include #include @@ -252,6 +256,21 @@ rbsize_result_t rbsize_results[] = { { {328, 0, 511, 20}, 0x00, 183}, { {511, 0, 672, 20}, 0x00, 161}, { { 0, 20, 672, 40}, 0x00, 200}, }, }, + { {0, 0, 672, 56}, 56, 2, {28, 28, }, 5, { + { { 0, 0, 114, 28}, 0x00, 40}, { {114, 0, 328, 28}, 0x00, 214}, + { {328, 0, 511, 28}, 0x00, 183}, { {511, 0, 672, 28}, 0x00, 161}, + { { 0, 28, 672, 56}, 0x00, 200}, + }, }, + { {0, 0, 672, 40}, 40, 2, {20, 20, }, 5, { + { { 0, 0, 114, 20}, 0x00, 40}, { {114, 0, 328, 20}, 0x00, 214}, + { {328, 0, 511, 20}, 0x00, 183}, { {511, 0, 672, 20}, 0x00, 161}, + { { 0, 20, 672, 40}, 0x00, 200}, + }, }, + { {0, 0, 672, 56}, 56, 2, {28, 28, }, 5, { + { { 0, 0, 114, 28}, 0x00, 40}, { {114, 0, 328, 28}, 0x00, 214}, + { {328, 0, 511, 28}, 0x00, 183}, { {511, 0, 672, 28}, 0x00, 161}, + { { 0, 28, 672, 56}, 0x00, 200}, + }, }, { {0, 0, 672, 0}, 0, 0, {0, }, 0, {{{0, 0, 0, 0}, 0, 0}, }, }, { {0, 0, 672, 65}, 65, 1, {65, }, 3, { @@ -329,6 +348,8 @@ static void layout_test(void) { HWND hRebar = NULL; REBARBANDINFO rbi; + HIMAGELIST himl; + REBARINFO ri; rebuild_rebar(&hRebar); check_sizes(); @@ -406,6 +427,27 @@ static void layout_test(void) SendMessageA(hRebar, RB_MINIMIZEBAND, 0, 0); check_sizes(); + /* an image will increase the band height */ + himl = ImageList_LoadImage(LoadLibrary("comctl32"), MAKEINTRESOURCE(121), 24, 2, CLR_NONE, IMAGE_BITMAP, LR_DEFAULTCOLOR); + ri.cbSize = sizeof(ri); + ri.fMask = RBIM_IMAGELIST; + ri.himl = himl; + ok(SendMessage(hRebar, RB_SETBARINFO, 0, (LPARAM)&ri), "RB_SETBARINFO failed\n"); + rbi.fMask = RBBIM_IMAGE; + rbi.iImage = 1; + SendMessage(hRebar, RB_SETBANDINFO, 1, (LPARAM)&rbi); + check_sizes(); + + /* after removing it everything is back to normal*/ + rbi.iImage = -1; + SendMessage(hRebar, RB_SETBANDINFO, 1, (LPARAM)&rbi); + check_sizes(); + + /* Only -1 means that the image is not present. Other invalid values increase the height */ + rbi.iImage = -2; + SendMessage(hRebar, RB_SETBANDINFO, 1, (LPARAM)&rbi); + check_sizes(); + /* VARHEIGHT resizing test on a horizontal rebar */ rebuild_rebar(&hRebar); SetWindowLong(hRebar, GWL_STYLE, GetWindowLong(hRebar, GWL_STYLE) | RBS_AUTOSIZE); @@ -786,11 +828,24 @@ static void bandinfo_test(void) START_TEST(rebar) { + HMODULE hComctl32; + BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); + INITCOMMONCONTROLSEX iccex; WNDCLASSA wc; MSG msg; RECT rc; - InitCommonControls(); + /* LoadLibrary is needed. This file has no references to functions in comctl32 */ + hComctl32 = LoadLibraryA("comctl32.dll"); + pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); + if (!pInitCommonControlsEx) + { + skip("InitCommonControlsEx() is missing. Skipping the tests\n"); + return; + } + iccex.dwSize = sizeof(iccex); + iccex.dwICC = ICC_COOL_CLASSES; + pInitCommonControlsEx(&iccex); wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; @@ -825,4 +880,6 @@ START_TEST(rebar) DispatchMessageA(&msg); } DestroyWindow(hMainWnd); + + FreeLibrary(hComctl32); } diff --git a/rostests/winetests/comctl32/toolbar.c b/rostests/winetests/comctl32/toolbar.c index b094a4bfc0d..2693025b2e3 100644 --- a/rostests/winetests/comctl32/toolbar.c +++ b/rostests/winetests/comctl32/toolbar.c @@ -40,6 +40,8 @@ static BOOL g_fExpectedHotItemOld; static BOOL g_fExpectedHotItemNew; static DWORD g_dwExpectedDispInfoMask; +#define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT)) + #define check_rect(name, val, exp) ok(val.top == exp.top && val.bottom == exp.bottom && \ val.left == exp.left && val.right == exp.right, "invalid rect (" name ") (%d,%d) (%d,%d) - expected (%d,%d) (%d,%d)\n", \ val.left, val.top, val.right, val.bottom, exp.left, exp.top, exp.right, exp.bottom); @@ -1088,6 +1090,38 @@ static void test_setrows(void) DestroyWindow(hToolbar); } +static void test_getstring(void) +{ + HWND hToolbar = NULL; + char str[10]; + WCHAR strW[10]; + static const char answer[] = "STR"; + static const WCHAR answerW[] = { 'S','T','R',0 }; + INT r; + + hToolbar = CreateWindowExA(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hMainWnd, (HMENU)5, GetModuleHandle(NULL), NULL); + ok(hToolbar != NULL, "Toolbar creation problem\n"); + + r = SendMessage(hToolbar, TB_GETSTRING, MAKEWPARAM(0, 0), (LPARAM)NULL); + expect(-1, r); + r = SendMessage(hToolbar, TB_GETSTRINGW, MAKEWPARAM(0, 0), (LPARAM)NULL); + expect(-1, r); + r = SendMessage(hToolbar, TB_ADDSTRING, 0, (LPARAM)answer); + expect(0, r); + r = SendMessage(hToolbar, TB_GETSTRING, MAKEWPARAM(0, 0), (LPARAM)NULL); + expect(lstrlenA(answer), r); + r = SendMessage(hToolbar, TB_GETSTRINGW, MAKEWPARAM(0, 0), (LPARAM)NULL); + expect(lstrlenA(answer), r); + r = SendMessage(hToolbar, TB_GETSTRING, MAKEWPARAM(sizeof(str), 0), (LPARAM)str); + expect(lstrlenA(answer), r); + expect(0, lstrcmp(answer, str)); + r = SendMessage(hToolbar, TB_GETSTRINGW, MAKEWPARAM(sizeof(strW), 0), (LPARAM)strW); + expect(lstrlenA(answer), r); + expect(0, lstrcmpW(answerW, strW)); + + DestroyWindow(hToolbar); +} + START_TEST(toolbar) { WNDCLASSA wc; @@ -1122,6 +1156,7 @@ START_TEST(toolbar) test_createtoolbarex(); test_dispinfo(); test_setrows(); + test_getstring(); PostQuitMessage(0); while(GetMessageA(&msg,0,0,0)) { diff --git a/rostests/winetests/comctl32/tooltips.c b/rostests/winetests/comctl32/tooltips.c index 713fa240368..e9bce637be8 100644 --- a/rostests/winetests/comctl32/tooltips.c +++ b/rostests/winetests/comctl32/tooltips.c @@ -1,5 +1,6 @@ /* * Copyright 2005 Dmitry Timoshkov + * Copyright 2008 Jason Edmeades * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -60,9 +61,181 @@ static void test_create_tooltip(void) DestroyWindow(parent); } +/* try to make sure pending X events have been processed before continuing */ +static void flush_events(int waitTime) +{ + MSG msg; + int diff = waitTime; + DWORD time = GetTickCount() + waitTime; + + while (diff > 0) + { + if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min(100,diff), QS_ALLEVENTS) == WAIT_TIMEOUT) break; + while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg ); + diff = time - GetTickCount(); + } +} + +static int CD_Stages; +static LRESULT CD_Result; +static HWND g_hwnd; + +#define TEST_CDDS_PREPAINT 0x00000001 +#define TEST_CDDS_POSTPAINT 0x00000002 +#define TEST_CDDS_PREERASE 0x00000004 +#define TEST_CDDS_POSTERASE 0x00000008 +#define TEST_CDDS_ITEMPREPAINT 0x00000010 +#define TEST_CDDS_ITEMPOSTPAINT 0x00000020 +#define TEST_CDDS_ITEMPREERASE 0x00000040 +#define TEST_CDDS_ITEMPOSTERASE 0x00000080 +#define TEST_CDDS_SUBITEM 0x00000100 + +static LRESULT CALLBACK CustomDrawWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) { + + case WM_DESTROY: + PostQuitMessage(0); + break; + + case WM_NOTIFY: + if (((NMHDR *)lParam)->code == NM_CUSTOMDRAW) { + NMTTCUSTOMDRAW *ttcd = (NMTTCUSTOMDRAW*) lParam; + ok(ttcd->nmcd.hdr.hwndFrom == g_hwnd, "Unexpected hwnd source %x (%x)\n", + (int)ttcd->nmcd.hdr.hwndFrom, (int) g_hwnd); + ok(ttcd->nmcd.hdr.idFrom == 0x1234ABCD, "Unexpected id %x\n", (int)ttcd->nmcd.hdr.idFrom); + + switch (ttcd->nmcd.dwDrawStage) { + case CDDS_PREPAINT : CD_Stages |= TEST_CDDS_PREPAINT; break; + case CDDS_POSTPAINT : CD_Stages |= TEST_CDDS_POSTPAINT; break; + case CDDS_PREERASE : CD_Stages |= TEST_CDDS_PREERASE; break; + case CDDS_POSTERASE : CD_Stages |= TEST_CDDS_POSTERASE; break; + case CDDS_ITEMPREPAINT : CD_Stages |= TEST_CDDS_ITEMPREPAINT; break; + case CDDS_ITEMPOSTPAINT: CD_Stages |= TEST_CDDS_ITEMPOSTPAINT; break; + case CDDS_ITEMPREERASE : CD_Stages |= TEST_CDDS_ITEMPREERASE; break; + case CDDS_ITEMPOSTERASE: CD_Stages |= TEST_CDDS_ITEMPOSTERASE; break; + case CDDS_SUBITEM : CD_Stages |= TEST_CDDS_SUBITEM; break; + default: CD_Stages = -1; + } + + if (ttcd->nmcd.dwDrawStage == CDDS_PREPAINT) return CD_Result; + } + /* drop through */ + + default: + return DefWindowProcA(hWnd, msg, wParam, lParam); + } + + return 0L; +} + +static void test_customdraw(void) { + static struct { + LRESULT FirstReturnValue; + int ExpectedCalls; + } expectedResults[] = { + /* Valid notification responses */ + {CDRF_DODEFAULT, TEST_CDDS_PREPAINT}, + {CDRF_SKIPDEFAULT, TEST_CDDS_PREPAINT}, + {CDRF_NOTIFYPOSTPAINT, TEST_CDDS_PREPAINT | TEST_CDDS_POSTPAINT}, + + /* Invalid notification responses */ + {CDRF_NOTIFYITEMDRAW, TEST_CDDS_PREPAINT}, + {CDRF_NOTIFYPOSTERASE, TEST_CDDS_PREPAINT}, + {CDRF_NOTIFYSUBITEMDRAW, TEST_CDDS_PREPAINT}, + {CDRF_NEWFONT, TEST_CDDS_PREPAINT} + }; + + int iterationNumber; + WNDCLASSA wc; + LRESULT lResult; + + /* Create a class to use the custom draw wndproc */ + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetModuleHandleA(NULL); + wc.hIcon = NULL; + wc.hCursor = LoadCursorA(NULL, IDC_ARROW); + wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); + wc.lpszMenuName = NULL; + wc.lpszClassName = "CustomDrawClass"; + wc.lpfnWndProc = CustomDrawWndProc; + RegisterClass(&wc); + + for (iterationNumber = 0; + iterationNumber < sizeof(expectedResults)/sizeof(expectedResults[0]); + iterationNumber++) { + + HWND parent, hwndTip; + TOOLINFO toolInfo = { 0 }; + + /* Create a main window */ + parent = CreateWindowEx(0, "CustomDrawClass", NULL, + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_VISIBLE, + 50, 50, + 300, 300, + NULL, NULL, NULL, 0); + ok(parent != NULL, "Creation of main window failed\n"); + + /* Make it show */ + ShowWindow(parent, SW_SHOWNORMAL); + flush_events(100); + + /* Create Tooltip */ + hwndTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, + NULL, TTS_NOPREFIX | TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + parent, NULL, GetModuleHandleA(NULL), 0); + ok(hwndTip != NULL, "Creation of tooltip window failed\n"); + + /* Set up parms for the wndproc to handle */ + CD_Stages = 0; + CD_Result = expectedResults[iterationNumber].FirstReturnValue; + g_hwnd = hwndTip; + + /* Make it topmost, as per the MSDN */ + SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + + /* Create a tool */ + toolInfo.cbSize = sizeof(TOOLINFO); + toolInfo.hwnd = parent; + toolInfo.hinst = GetModuleHandleA(NULL); + toolInfo.uFlags = TTF_SUBCLASS; + toolInfo.uId = (UINT_PTR)0x1234ABCD; + toolInfo.lpszText = (LPSTR)"This is a test tooltip"; + toolInfo.lParam = 0xdeadbeef; + GetClientRect (parent, &toolInfo.rect); + lResult = SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); + ok(lResult, "Adding the tool to the tooltip failed\n"); + + /* Make tooltip appear quickly */ + SendMessage(hwndTip, TTM_SETDELAYTIME, (WPARAM)TTDT_INITIAL, (LPARAM)MAKELONG(1,0)); + + /* Put cursor inside window, tooltip will appear immediately */ + SetCursorPos(100, 100); + flush_events(200); + + /* Check CustomDraw results */ + ok(CD_Stages == expectedResults[iterationNumber].ExpectedCalls, + "CustomDraw run %d stages %x, expected %x\n", iterationNumber, CD_Stages, + expectedResults[iterationNumber].ExpectedCalls); + + /* Clean up */ + DestroyWindow(hwndTip); + DestroyWindow(parent); + } + + +} + START_TEST(tooltips) { InitCommonControls(); test_create_tooltip(); + test_customdraw(); } diff --git a/rostests/winetests/comctl32/treeview.c b/rostests/winetests/comctl32/treeview.c index 93010d3065e..c1ba7f309be 100644 --- a/rostests/winetests/comctl32/treeview.c +++ b/rostests/winetests/comctl32/treeview.c @@ -649,10 +649,23 @@ static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa START_TEST(treeview) { + HMODULE hComctl32; + BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); WNDCLASSA wc; MSG msg; - InitCommonControls(); + hComctl32 = GetModuleHandleA("comctl32.dll"); + pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx"); + if (pInitCommonControlsEx) + { + INITCOMMONCONTROLSEX iccex; + iccex.dwSize = sizeof(iccex); + iccex.dwICC = ICC_TREEVIEW_CLASSES; + pInitCommonControlsEx(&iccex); + } + else + InitCommonControls(); + init_msg_sequences(MsgSequences, NUM_MSG_SEQUENCES); wc.style = CS_HREDRAW | CS_VREDRAW; diff --git a/rostests/winetests/comdlg32/comdlg32.rbuild b/rostests/winetests/comdlg32/comdlg32.rbuild index fc3c02ecb86..c29c693fa99 100644 --- a/rostests/winetests/comdlg32/comdlg32.rbuild +++ b/rostests/winetests/comdlg32/comdlg32.rbuild @@ -1,15 +1,17 @@ + . 0x600 0x600 + filedlg.c + printdlg.c + testlist.c wine comdlg32 user32 kernel32 ntdll - filedlg.c - printdlg.c - testlist.c + diff --git a/rostests/winetests/comdlg32/printdlg.c b/rostests/winetests/comdlg32/printdlg.c index 783773f1adc..744b6eb456f 100644 --- a/rostests/winetests/comdlg32/printdlg.c +++ b/rostests/winetests/comdlg32/printdlg.c @@ -26,6 +26,7 @@ #include "winerror.h" #include "wingdi.h" #include "winuser.h" +#include "objbase.h" #include "cderr.h" #include "commdlg.h" diff --git a/rostests/winetests/directory.rbuild b/rostests/winetests/directory.rbuild index 34fed194b83..7ec4c4153dc 100644 --- a/rostests/winetests/directory.rbuild +++ b/rostests/winetests/directory.rbuild @@ -31,6 +31,9 @@ + + + @@ -73,6 +76,9 @@ + + + diff --git a/rostests/winetests/hlink/hlink.c b/rostests/winetests/hlink/hlink.c index a2d7360a47d..6c3dff0591a 100644 --- a/rostests/winetests/hlink/hlink.c +++ b/rostests/winetests/hlink/hlink.c @@ -2,7 +2,7 @@ * Implementation of hyperlinking (hlink.dll) * * Copyright 2006 Mike McCormack - * Copyright 2007 Jacek Caban for CodeWeavers + * Copyright 2007-2008 Jacek Caban for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,34 @@ #include "wine/test.h" +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +DEFINE_EXPECT(IsSystemMoniker); +DEFINE_EXPECT(BindToStorage); +DEFINE_EXPECT(GetDisplayName); + static const char *debugstr_w(LPCWSTR str) { static char buf[1024]; @@ -37,6 +65,18 @@ static const char *debugstr_w(LPCWSTR str) return buf; } +static const char *debugstr_guid(REFIID riid) +{ + static char buf[50]; + + sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + riid->Data1, riid->Data2, riid->Data3, riid->Data4[0], + riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4], + riid->Data4[5], riid->Data4[6], riid->Data4[7]); + + return buf; +} + static void test_HlinkIsShortcut(void) { int i; @@ -292,7 +332,11 @@ static void test_persist(void) hr = HlinkCreateFromString(url, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (LPVOID*) &lnk); - ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr); + ok(hr == S_OK, "IHlinkCreateFromString failed with error 0x%08x\n", hr); + if (!lnk) { + skip("Can't create lnk, skipping test_persist. Was wineprefixcreate run properly?\n"); + return; + } test_persist_save_data("url only", lnk, expected_hlink_data, sizeof(expected_hlink_data)); IHlink_Release(lnk); @@ -444,6 +488,422 @@ static void test_HlinkCreateExtensionServices(void) IAuthenticate_Release(authenticate); } +static void test_HlinkParseDisplayName(void) +{ + IMoniker *mon = NULL; + LPWSTR name; + DWORD issys; + ULONG eaten = 0; + IBindCtx *bctx; + HRESULT hres; + + static const WCHAR winehq_urlW[] = + {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g', + '/','s','i','t','e','/','a','b','o','u','t',0}; + static const WCHAR invalid_urlW[] = {'t','e','s','t',':','1','2','3','a','b','c',0}; + static const WCHAR clsid_nameW[] = {'c','l','s','i','d',':', + '2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8', + '-','0','8','0','0','2','B','3','0','3','0','9','D',':',0}; + + CreateBindCtx(0, &bctx); + + hres = HlinkParseDisplayName(bctx, winehq_urlW, FALSE, &eaten, &mon); + ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres); + ok(eaten == sizeof(winehq_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten); + ok(mon != NULL, "mon == NULL\n"); + + hres = IMoniker_GetDisplayName(mon, bctx, 0, &name); + ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres); + ok(!lstrcmpW(name, winehq_urlW), "wrong display name %s\n", debugstr_w(name)); + CoTaskMemFree(name); + + hres = IMoniker_IsSystemMoniker(mon, &issys); + ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres); + ok(issys == MKSYS_URLMONIKER, "issys=%x\n", issys); + + IMoniker_Release(mon); + + hres = HlinkParseDisplayName(bctx, clsid_nameW, FALSE, &eaten, &mon); + ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres); + ok(eaten == sizeof(clsid_nameW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten); + ok(mon != NULL, "mon == NULL\n"); + + hres = IMoniker_IsSystemMoniker(mon, &issys); + ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres); + ok(issys == MKSYS_CLASSMONIKER, "issys=%x\n", issys); + + IMoniker_Release(mon); + + hres = HlinkParseDisplayName(bctx, invalid_urlW, FALSE, &eaten, &mon); + ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres); + ok(eaten == sizeof(invalid_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten); + ok(mon != NULL, "mon == NULL\n"); + + hres = IMoniker_GetDisplayName(mon, bctx, 0, &name); + ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres); + ok(!lstrcmpW(name, invalid_urlW), "wrong display name %s\n", debugstr_w(name)); + CoTaskMemFree(name); + + hres = IMoniker_IsSystemMoniker(mon, &issys); + ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres); + ok(issys == MKSYS_FILEMONIKER, "issys=%x\n", issys); + + IBindCtx_Release(bctx); +} + +static IBindCtx *_bctx; + +static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface) +{ + return 2; +} + +static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface) +{ + return 1; +} + +static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, + REFGUID guidService, REFIID riid, void **ppv) +{ + ok(0, "unexpected service %s\n", debugstr_guid(guidService)); + return E_NOINTERFACE; +} + +static IServiceProviderVtbl ServiceProviderVtbl = { + ServiceProvider_QueryInterface, + ServiceProvider_AddRef, + ServiceProvider_Release, + ServiceProvider_QueryService +}; + +static IServiceProvider ServiceProvider = { &ServiceProviderVtbl }; + +static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(riid, &IID_IServiceProvider)) { + *ppv = &ServiceProvider; + return S_OK; + } + + ok(0, "unexpected interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface) +{ + return 2; +} + +static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface) +{ + return 1; +} + +static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved, + IBinding *pib) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress, + ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF, + DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static IBindStatusCallbackVtbl BindStatusCallbackVtbl = { + BindStatusCallback_QueryInterface, + BindStatusCallback_AddRef, + BindStatusCallback_Release, + BindStatusCallback_OnStartBinding, + BindStatusCallback_GetPriority, + BindStatusCallback_OnLowResource, + BindStatusCallback_OnProgress, + BindStatusCallback_OnStopBinding, + BindStatusCallback_GetBindInfo, + BindStatusCallback_OnDataAvailable, + BindStatusCallback_OnObjectAvailable +}; + +static IBindStatusCallback BindStatusCallback = { &BindStatusCallbackVtbl }; + +static HRESULT WINAPI Moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + ok(0, "unexpected riid: %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI Moniker_AddRef(IMoniker *iface) +{ + return 2; +} + +static ULONG WINAPI Moniker_Release(IMoniker *iface) +{ + return 1; +} + +static HRESULT WINAPI Moniker_GetClassID(IMoniker *iface, CLSID *pClassID) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_IsDirty(IMoniker *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_Load(IMoniker *iface, IStream *pStm) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pcb, IMoniker *pmkToLeft, + REFIID riidResult, void **ppvResult) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, + REFIID riid, void **ppv) +{ + IUnknown *unk; + HRESULT hres; + + static OLECHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 }; + + CHECK_EXPECT(BindToStorage); + + ok(pbc == _bctx, "pbc != _bctx\n"); + ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft); + ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid)); + ok(ppv != NULL, "ppv == NULL\n"); + ok(*ppv == NULL, "*ppv=%p\n", *ppv); + + hres = IBindCtx_GetObjectParam(pbc, BSCBHolder, &unk); + ok(hres == S_OK, "GetObjectParam failed: %08x\n", hres); + ok(unk != NULL, "unk == NULL\n"); + + IUnknown_Release(unk); + + return S_OK; +} + +static HRESULT WINAPI Moniker_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD dwReduceHowFar, + IMoniker **ppmkToLeft, IMoniker **ppmkReduced) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight, + BOOL fOnlyIfNotGeneric, IMoniker **ppnkComposite) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_Enum(IMoniker *iface, BOOL fForwrd, IEnumMoniker **ppenumMoniker) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_Hash(IMoniker *iface, DWORD *pdwHash) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_IsRunning(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, + IMoniker *pmkNewlyRunning) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc, + IMoniker *pmkToLeft, FILETIME *pFileTime) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_Inverse(IMoniker *iface, IMoniker **ppmk) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther, + IMoniker **ppmkPrefix) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther, + IMoniker **pmkRelPath) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc, + IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName) +{ + static const WCHAR winehq_urlW[] = + {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g', + '/','s','i','t','e','/','a','b','o','u','t',0}; + + CHECK_EXPECT(GetDisplayName); + + ok(pbc != NULL, "pbc == NULL\n"); + ok(pbc != _bctx, "pbc == _bctx\n"); + ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft); + + *ppszDisplayName = CoTaskMemAlloc(sizeof(winehq_urlW)); + memcpy(*ppszDisplayName, winehq_urlW, sizeof(winehq_urlW)); + return S_OK; +} + +static HRESULT WINAPI Moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc, + IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys) +{ + CHECK_EXPECT2(IsSystemMoniker); + + *pdwMksys = MKSYS_URLMONIKER; + return S_OK; +} + +static IMonikerVtbl MonikerVtbl = { + Moniker_QueryInterface, + Moniker_AddRef, + Moniker_Release, + Moniker_GetClassID, + Moniker_IsDirty, + Moniker_Load, + Moniker_Save, + Moniker_GetSizeMax, + Moniker_BindToObject, + Moniker_BindToStorage, + Moniker_Reduce, + Moniker_ComposeWith, + Moniker_Enum, + Moniker_IsEqual, + Moniker_Hash, + Moniker_IsRunning, + Moniker_GetTimeOfLastChange, + Moniker_Inverse, + Moniker_CommonPrefixWith, + Moniker_RelativePathTo, + Moniker_GetDisplayName, + Moniker_ParseDisplayName, + Moniker_IsSystemMoniker +}; + +static IMoniker Moniker = { &MonikerVtbl }; + +static void test_HlinkResolveMonikerForData(void) +{ + IBindCtx *bctx; + HRESULT hres; + + CreateBindCtx(0, &bctx); + _bctx = bctx; + + SET_EXPECT(IsSystemMoniker); + SET_EXPECT(GetDisplayName); + SET_EXPECT(BindToStorage); + + hres = HlinkResolveMonikerForData(&Moniker, 0, bctx, 0, NULL, &BindStatusCallback, NULL); + ok(hres == S_OK, "HlinkResolveMonikerForData failed: %08x\n", hres); + + CHECK_CALLED(IsSystemMoniker); + CHECK_CALLED(GetDisplayName); + CHECK_CALLED(BindToStorage); + + IBindCtx_Release(bctx); +} + START_TEST(hlink) { CoInitialize(NULL); @@ -453,6 +913,8 @@ START_TEST(hlink) test_persist(); test_special_reference(); test_HlinkCreateExtensionServices(); + test_HlinkParseDisplayName(); + test_HlinkResolveMonikerForData(); CoUninitialize(); } diff --git a/rostests/winetests/hlink/hlink.rbuild b/rostests/winetests/hlink/hlink.rbuild index de30316adcf..a66a08a7310 100644 --- a/rostests/winetests/hlink/hlink.rbuild +++ b/rostests/winetests/hlink/hlink.rbuild @@ -5,13 +5,13 @@ . 0x600 0x600 + hlink.c + testlist.c wine hlink ole32 kernel32 uuid ntdll - hlink.c - testlist.c diff --git a/rostests/winetests/imm32/imm32.c b/rostests/winetests/imm32/imm32.c new file mode 100644 index 00000000000..d948f548895 --- /dev/null +++ b/rostests/winetests/imm32/imm32.c @@ -0,0 +1,218 @@ +/* + * Unit tests for imm32 + * + * Copyright (c) 2008 Michael Jung + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "wine/test.h" +#include "winuser.h" +#include "imm.h" + +#define NUMELEMS(array) (sizeof((array))/sizeof((array)[0])) + +/* + * msgspy - record and analyse message traces sent to a certain window + */ +static struct _msg_spy { + HWND hwnd; + HHOOK get_msg_hook; + HHOOK call_wnd_proc_hook; + CWPSTRUCT msgs[32]; + unsigned int i_msg; +} msg_spy; + +static LRESULT CALLBACK get_msg_filter(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (HC_ACTION == nCode) { + MSG *msg = (MSG*)lParam; + + if ((msg->hwnd == msg_spy.hwnd) && + (msg_spy.i_msg < NUMELEMS(msg_spy.msgs))) + { + msg_spy.msgs[msg_spy.i_msg].hwnd = msg->hwnd; + msg_spy.msgs[msg_spy.i_msg].message = msg->message; + msg_spy.msgs[msg_spy.i_msg].wParam = msg->wParam; + msg_spy.msgs[msg_spy.i_msg].lParam = msg->lParam; + msg_spy.i_msg++; + } + } + + return CallNextHookEx(msg_spy.get_msg_hook, nCode, wParam, lParam); +} + +static LRESULT CALLBACK call_wnd_proc_filter(int nCode, WPARAM wParam, + LPARAM lParam) +{ + if (HC_ACTION == nCode) { + CWPSTRUCT *cwp = (CWPSTRUCT*)lParam; + + if ((cwp->hwnd == msg_spy.hwnd) && + (msg_spy.i_msg < NUMELEMS(msg_spy.msgs))) + { + memcpy(&msg_spy.msgs[msg_spy.i_msg], cwp, sizeof(msg_spy.msgs[0])); + msg_spy.i_msg++; + } + } + + return CallNextHookEx(msg_spy.call_wnd_proc_hook, nCode, wParam, lParam); +} + +static void msg_spy_pump_msg_queue(void) { + MSG msg; + + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return; +} + +static void msg_spy_flush_msgs(void) { + msg_spy_pump_msg_queue(); + msg_spy.i_msg = 0; +} + +static CWPSTRUCT* msg_spy_find_msg(UINT message) { + int i; + + msg_spy_pump_msg_queue(); + + if (msg_spy.i_msg >= NUMELEMS(msg_spy.msgs)) + fprintf(stdout, "%s:%d: msg_spy: message buffer overflow!\n", + __FILE__, __LINE__); + + for (i = 0; i < msg_spy.i_msg; i++) + if (msg_spy.msgs[i].message == message) + return &msg_spy.msgs[i]; + + return NULL; +} + +static void msg_spy_init(HWND hwnd) { + msg_spy.hwnd = hwnd; + msg_spy.get_msg_hook = + SetWindowsHookEx(WH_GETMESSAGE, get_msg_filter, GetModuleHandle(0), + GetCurrentThreadId()); + msg_spy.call_wnd_proc_hook = + SetWindowsHookEx(WH_CALLWNDPROC, call_wnd_proc_filter, + GetModuleHandle(0), GetCurrentThreadId()); + msg_spy.i_msg = 0; + + msg_spy_flush_msgs(); +} + +static void msg_spy_cleanup() { + if (msg_spy.get_msg_hook) + UnhookWindowsHookEx(msg_spy.get_msg_hook); + if (msg_spy.call_wnd_proc_hook) + UnhookWindowsHookEx(msg_spy.call_wnd_proc_hook); + memset(&msg_spy, 0, sizeof(msg_spy)); +} + +/* + * imm32 test cases - Issue some IMM commands on a dummy window and analyse the + * messages being sent to this window in response. + */ +static const char wndcls[] = "winetest_imm32_wndcls"; +static HWND hwnd; + +static int init(void) { + WNDCLASSEX wc; + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = 0; + wc.lpfnWndProc = DefWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetModuleHandle(0); + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = NULL; + wc.lpszClassName = wndcls; + wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + if (!RegisterClassExA(&wc)) + return 0; + + hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, + 240, 120, NULL, NULL, GetModuleHandle(0), NULL); + if (!hwnd) + return 0; + + ShowWindow(hwnd, SW_SHOWNORMAL); + UpdateWindow(hwnd); + + msg_spy_init(hwnd); + + return 1; +} + +static void cleanup(void) { + msg_spy_cleanup(); + if (hwnd) + DestroyWindow(hwnd); + UnregisterClass(wndcls, GetModuleHandle(0)); +} + +static int test_ImmNotifyIME(void) { + static const char string[] = "wine"; + char resstr[16] = ""; + HIMC imc; + + imc = ImmGetContext(hwnd); + msg_spy_flush_msgs(); + + ok(ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0), "Canceling an " + "empty composition string succeeds.\n"); + ok(!msg_spy_find_msg(WM_IME_COMPOSITION), "Windows does not post " + "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if " + "the composition string being canceled is empty.\n"); + + msg_spy_flush_msgs(); + + ImmSetCompositionString(imc, SCS_SETSTR, string, sizeof(string), NULL, 0); + ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); + ok(msg_spy_find_msg(WM_IME_COMPOSITION) != NULL, "Windows does post " + "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if " + "the composition string being canceled is non empty.\n"); + ok(!ImmGetCompositionString(imc, GCS_COMPSTR, resstr, sizeof(resstr)), + "After being canceled the composition string is empty.\n"); + + msg_spy_flush_msgs(); + + ok(ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0), "Canceling an " + "empty composition string succeeds.\n"); + ok(!msg_spy_find_msg(WM_IME_COMPOSITION), "Windows does not post " + "WM_IME_COMPOSITION in response to NI_COMPOSITIONSTR / CPS_CANCEL, if " + "the composition string being canceled is empty.\n"); + + msg_spy_flush_msgs(); + ImmReleaseContext(hwnd, imc); + + return 0; +} + +START_TEST(imm32) { + if (init()) + test_ImmNotifyIME(); + cleanup(); +} diff --git a/rostests/winetests/imm32/imm32.rbuild b/rostests/winetests/imm32/imm32.rbuild new file mode 100644 index 00000000000..e61c139be59 --- /dev/null +++ b/rostests/winetests/imm32/imm32.rbuild @@ -0,0 +1,16 @@ + + + + + . + 0x600 + 0x600 + imm32.c + testlist.c + wine + imm32 + user32 + kernel32 + ntdll + + diff --git a/rostests/winetests/imm32/testlist.c b/rostests/winetests/imm32/testlist.c new file mode 100644 index 00000000000..a7911d1b0e0 --- /dev/null +++ b/rostests/winetests/imm32/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_imm32(void); + +const struct test winetest_testlist[] = +{ + { "imm32", func_imm32 }, + { 0, 0 } +}; diff --git a/rostests/winetests/lz32/lz32.rbuild b/rostests/winetests/lz32/lz32.rbuild index abe12d9353b..a9e500a7d23 100644 --- a/rostests/winetests/lz32/lz32.rbuild +++ b/rostests/winetests/lz32/lz32.rbuild @@ -1,13 +1,15 @@ + . 0x600 0x600 + lzexpand_main.c + testlist.c wine lz32 kernel32 ntdll - lzexpand_main.c - testlist.c + diff --git a/rostests/winetests/lz32/lzexpand_main.c b/rostests/winetests/lz32/lzexpand_main.c index b51067bcff3..c67883acb54 100644 --- a/rostests/winetests/lz32/lzexpand_main.c +++ b/rostests/winetests/lz32/lzexpand_main.c @@ -54,10 +54,7 @@ static char filename2[] = "testfile.yyy"; a simple text file with the contents "This is a test file." The file was created using COMPRESS.EXE from the Windows Server 2003 - Resource Kit from Microsoft. The resource kit was retrieved from the - following URL: - - http://www.microsoft.com/downloads/details.aspx?FamilyID=9d467a69-57ff-4ae7-96ee-b18c4790cffd&displaylang=en + Resource Kit from Microsoft. */ static const unsigned char compressed_file[] = {0x53,0x5A,0x44,0x44,0x88,0xF0,0x27,0x33,0x41, diff --git a/rostests/winetests/mapi32/mapi32.rbuild b/rostests/winetests/mapi32/mapi32.rbuild index 8712bb2a28d..6da38a35bc5 100644 --- a/rostests/winetests/mapi32/mapi32.rbuild +++ b/rostests/winetests/mapi32/mapi32.rbuild @@ -1,15 +1,17 @@ + . 0x600 0x600 - wine - kernel32 - uuid - ntdll imalloc.c prop.c util.c testlist.c + wine + kernel32 + uuid + ntdll + diff --git a/rostests/winetests/mapi32/prop.c b/rostests/winetests/mapi32/prop.c index d78eb3697f3..adc1d85b91a 100644 --- a/rostests/winetests/mapi32/prop.c +++ b/rostests/winetests/mapi32/prop.c @@ -24,6 +24,7 @@ #include "winuser.h" #include "winerror.h" #include "winnt.h" +#include "initguid.h" #include "mapiutil.h" #include "mapitags.h" diff --git a/rostests/winetests/mlang/mlang.rbuild b/rostests/winetests/mlang/mlang.rbuild index 748cb29d283..2f508f5ad8f 100644 --- a/rostests/winetests/mlang/mlang.rbuild +++ b/rostests/winetests/mlang/mlang.rbuild @@ -1,15 +1,17 @@ + . 0x600 0x600 + mlang.c + testlist.c wine ole32 gdi32 kernel32 uuid ntdll - mlang.c - testlist.c + diff --git a/rostests/winetests/msi/automation.c b/rostests/winetests/msi/automation.c index 90e4b1f62b0..f2e5c13abe4 100644 --- a/rostests/winetests/msi/automation.c +++ b/rostests/winetests/msi/automation.c @@ -465,85 +465,138 @@ static DISPID get_dispid( IDispatch *disp, const char *name ) static void test_dispid(void) { - ok( get_dispid( pInstaller, "CreateRecord" ) == 1, "dispid wrong\n"); - ok( get_dispid( pInstaller, "OpenPackage" ) == 2, "dispid wrong\n"); - todo_wine ok( get_dispid( pInstaller, "OpenProduct" ) == 3, "dispid wrong\n"); - ok( get_dispid( pInstaller, "OpenDatabase" ) == 4, "dispid wrong\n"); - todo_wine { - ok( get_dispid( pInstaller, "SummaryInformation" ) == 5, "dispid wrong\n"); - ok( get_dispid( pInstaller, "UILevel" ) == 6, "dispid wrong\n"); - ok( get_dispid( pInstaller, "EnableLog" ) == 7, "dispid wrong\n"); - } - ok( get_dispid( pInstaller, "InstallProduct" ) == 8, "dispid wrong\n"); - ok( get_dispid( pInstaller, "Version" ) == 9, "dispid wrong\n"); - todo_wine { - ok( get_dispid( pInstaller, "LastErrorRecord" ) == 10, "dispid wrong\n"); - } - ok( get_dispid( pInstaller, "RegistryValue" ) == 11, "dispid wrong\n"); - todo_wine { - ok( get_dispid( pInstaller, "Environment" ) == 12, "dispid wrong\n"); - ok( get_dispid( pInstaller, "FileAttributes" ) == 13, "dispid wrong\n"); + DISPID dispid; - ok( get_dispid( pInstaller, "FileSize" ) == 15, "dispid wrong\n"); - ok( get_dispid( pInstaller, "FileVersion" ) == 16, "dispid wrong\n"); + dispid = get_dispid(pInstaller, "CreateRecord"); + ok(dispid == 1, "Expected 1, got %d\n", dispid); + dispid = get_dispid(pInstaller, "OpenPackage"); + ok(dispid == 2, "Expected 2, got %d\n", dispid); + dispid = get_dispid(pInstaller, "OpenDatabase"); + ok(dispid == 4, "Expected 4, got %d\n", dispid); + dispid = get_dispid( pInstaller, "UILevel" ); + ok(dispid == 6, "Expected 6, got %d\n", dispid); + dispid = get_dispid(pInstaller, "InstallProduct"); + ok(dispid == 8, "Expected 8, got %d\n", dispid); + dispid = get_dispid(pInstaller, "Version"); + ok(dispid == 9, "Expected 9, got %d\n", dispid); + dispid = get_dispid(pInstaller, "RegistryValue"); + ok(dispid == 11, "Expected 11, got %d\n", dispid); + todo_wine + { + dispid = get_dispid(pInstaller, "OpenProduct"); + ok(dispid == 3, "Expected 3, got %d\n", dispid); + dispid = get_dispid(pInstaller, "SummaryInformation"); + ok(dispid == 5, "Expected 5, got %d\n", dispid); + dispid = get_dispid(pInstaller, "EnableLog"); + ok(dispid == 7, "Expected 7, got %d\n", dispid); + dispid = get_dispid(pInstaller, "LastErrorRecord"); + ok(dispid == 10, "Expected 10, got %d\n", dispid); + dispid = get_dispid(pInstaller, "Environment"); + ok(dispid == 12, "Expected 12, got %d\n", dispid); + dispid = get_dispid(pInstaller, "FileAttributes"); + ok(dispid == 13, "Expected 13, got %d\n", dispid); + dispid = get_dispid(pInstaller, "FileSize"); + ok(dispid == 15, "Expected 15, got %d\n", dispid); + dispid = get_dispid(pInstaller, "FileVersion"); + ok(dispid == 16, "Expected 16, got %d\n", dispid); } - ok( get_dispid( pInstaller, "ProductState" ) == 17, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ProductInfo" ) == 18, "dispid wrong\n"); - todo_wine { - ok( get_dispid( pInstaller, "ConfigureProduct" ) == 19, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ReinstallProduct" ) == 20 , "dispid wrong\n"); - ok( get_dispid( pInstaller, "CollectUserInfo" ) == 21, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ApplyPatch" ) == 22, "dispid wrong\n"); - ok( get_dispid( pInstaller, "FeatureParent" ) == 23, "dispid wrong\n"); - ok( get_dispid( pInstaller, "FeatureState" ) == 24, "dispid wrong\n"); - ok( get_dispid( pInstaller, "UseFeature" ) == 25, "dispid wrong\n"); - ok( get_dispid( pInstaller, "FeatureUsageCount" ) == 26, "dispid wrong\n"); - ok( get_dispid( pInstaller, "FeatureUsageDate" ) == 27, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ConfigureFeature" ) == 28, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ReinstallFeature" ) == 29, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ProvideComponent" ) == 30, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ComponentPath" ) == 31, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ProvideQualifiedComponent" ) == 32, "dispid wrong\n"); - ok( get_dispid( pInstaller, "QualifierDescription" ) == 33, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ComponentQualifiers" ) == 34, "dispid wrong\n"); + dispid = get_dispid(pInstaller, "ProductState"); + ok(dispid == 17, "Expected 17, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ProductInfo"); + ok(dispid == 18, "Expected 18, got %d\n", dispid); + todo_wine + { + dispid = get_dispid(pInstaller, "ConfigureProduct"); + ok(dispid == 19, "Expected 19, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ReinstallProduct"); + ok(dispid == 20 , "Expected 20, got %d\n", dispid); + dispid = get_dispid(pInstaller, "CollectUserInfo"); + ok(dispid == 21, "Expected 21, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ApplyPatch"); + ok(dispid == 22, "Expected 22, got %d\n", dispid); + dispid = get_dispid(pInstaller, "FeatureParent"); + ok(dispid == 23, "Expected 23, got %d\n", dispid); + dispid = get_dispid(pInstaller, "FeatureState"); + ok(dispid == 24, "Expected 24, got %d\n", dispid); + dispid = get_dispid(pInstaller, "UseFeature"); + ok(dispid == 25, "Expected 25, got %d\n", dispid); + dispid = get_dispid(pInstaller, "FeatureUsageCount"); + ok(dispid == 26, "Expected 26, got %d\n", dispid); + dispid = get_dispid(pInstaller, "FeatureUsageDate"); + ok(dispid == 27, "Expected 27, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ConfigureFeature"); + ok(dispid == 28, "Expected 28, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ReinstallFeature"); + ok(dispid == 29, "Expected 29, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ProvideComponent"); + ok(dispid == 30, "Expected 30, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ComponentPath"); + ok(dispid == 31, "Expected 31, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ProvideQualifiedComponent"); + ok(dispid == 32, "Expected 32, got %d\n", dispid); + dispid = get_dispid(pInstaller, "QualifierDescription"); + ok(dispid == 33, "Expected 33, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ComponentQualifiers"); + ok(dispid == 34, "Expected 34, got %d\n", dispid); } - ok( get_dispid( pInstaller, "Products" ) == 35, "dispid wrong\n"); - todo_wine { - ok( get_dispid( pInstaller, "Features" ) == 36, "dispid wrong\n"); - ok( get_dispid( pInstaller, "Components" ) == 37, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ComponentClients" ) == 38, "dispid wrong\n"); - ok( get_dispid( pInstaller, "Patches" ) == 39, "dispid wrong\n"); + dispid = get_dispid(pInstaller, "Products"); + ok(dispid == 35, "Expected 35, got %d\n", dispid); + todo_wine + { + dispid = get_dispid(pInstaller, "Features"); + ok(dispid == 36, "Expected 36, got %d\n", dispid); + dispid = get_dispid(pInstaller, "Components"); + ok(dispid == 37, "Expected 37, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ComponentClients"); + ok(dispid == 38, "Expected 38, got %d\n", dispid); + dispid = get_dispid(pInstaller, "Patches"); + ok(dispid == 39, "Expected 39, got %d\n", dispid); } - ok( get_dispid( pInstaller, "RelatedProducts" ) == 40, "dispid wrong\n"); - todo_wine { - ok( get_dispid( pInstaller, "PatchInfo" ) == 41, "dispid wrong\n"); - ok( get_dispid( pInstaller, "PatchTransforms" ) == 42, "dispid wrong\n"); - ok( get_dispid( pInstaller, "AddSource" ) == 43, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ClearSourceList" ) == 44, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ForceSourceListResolution" ) == 45, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ShortcutTarget" ) == 46, "dispid wrong\n"); - ok( get_dispid( pInstaller, "FileHash" ) == 47, "dispid wrong\n"); - ok( get_dispid( pInstaller, "FileSignatureInfo" ) == 48, "dispid wrong\n"); - ok( get_dispid( pInstaller, "RemovePatches" ) == 49, "dispid wrong\n"); - - ok( get_dispid( pInstaller, "ApplyMultiplePatches" ) == 51, "dispid wrong\n"); - ok( get_dispid( pInstaller, "ProductsEx" ) == 52, "dispid wrong\n"); - - ok( get_dispid( pInstaller, "PatchesEx" ) == 55, "dispid wrong\n"); - - ok( get_dispid( pInstaller, "ExtractPatchXMLData" ) == 57, "dispid wrong\n"); + dispid = get_dispid(pInstaller, "RelatedProducts"); + ok(dispid == 40, "Expected 40, got %d\n", dispid); + dispid = get_dispid(pInstaller, "RemovePatches"); + ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ApplyMultiplePatches"); + ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ProductsEx"); + ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid); + dispid = get_dispid(pInstaller, "PatchesEx"); + ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ExtractPatchXMLData"); + ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid); + todo_wine + { + dispid = get_dispid(pInstaller, "PatchInfo"); + ok(dispid == 41, "Expected 41, got %d\n", dispid); + dispid = get_dispid(pInstaller, "PatchTransforms"); + ok(dispid == 42, "Expected 42, got %d\n", dispid); + dispid = get_dispid(pInstaller, "AddSource"); + ok(dispid == 43, "Expected 43, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ClearSourceList"); + ok(dispid == 44, "Expected 44, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ForceSourceListResolution"); + ok(dispid == 45, "Expected 45, got %d\n", dispid); + dispid = get_dispid(pInstaller, "ShortcutTarget"); + ok(dispid == 46, "Expected 46, got %d\n", dispid); + dispid = get_dispid(pInstaller, "FileHash"); + ok(dispid == 47, "Expected 47, got %d\n", dispid); + dispid = get_dispid(pInstaller, "FileSignatureInfo"); + ok(dispid == 48, "Expected 48, got %d\n", dispid); } /* MSDN claims the following functions exist but IDispatch->GetIDsOfNames disagrees */ - if (0) - { - get_dispid( pInstaller, "ProductElevated" ); - get_dispid( pInstaller, "ProductInfoFromScript" ); - get_dispid( pInstaller, "ProvideAssembly" ); - get_dispid( pInstaller, "CreateAdvertiseScript" ); - get_dispid( pInstaller, "AdvertiseProduct" ); - get_dispid( pInstaller, "PatchFiles" ); - } + dispid = get_dispid( pInstaller, "ProductElevated" ); + ok(dispid == -1, "Expected -1, got %d\n", dispid); + dispid = get_dispid( pInstaller, "ProductInfoFromScript" ); + ok(dispid == -1, "Expected -1, got %d\n", dispid); + dispid = get_dispid( pInstaller, "ProvideAssembly" ); + ok(dispid == -1, "Expected -1, got %d\n", dispid); + dispid = get_dispid( pInstaller, "CreateAdvertiseScript" ); + ok(dispid == -1, "Expected -1, got %d\n", dispid); + dispid = get_dispid( pInstaller, "AdvertiseProduct" ); + ok(dispid == -1, "Expected -1, got %d\n", dispid); + dispid = get_dispid( pInstaller, "PatchFiles" ); + ok(dispid == -1, "Expected -1, got %d\n", dispid); } /* Test basic IDispatch functions */ @@ -1526,10 +1579,8 @@ static void test_Database(IDispatch *pDatabase, BOOL readonly) ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr); ok_exception(hr, szModifyModeRecord); - /* View::Modify with MSIMODIFY_REFRESH should undo our changes */ hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord); - /* Wine's MsiViewModify currently does not support MSIMODIFY_REFRESH */ - todo_wine ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr); /* Record::StringDataGet, confirm that the record is back to its unmodified value */ memset(szString, 0, sizeof(szString)); @@ -1762,6 +1813,7 @@ static void test_Installer_RegistryValue(void) VARIANTARG vararg; WCHAR szString[MAX_PATH]; HKEY hkey, hkey_sub; + HKEY curr_user = (HKEY)1; HRESULT hr; BOOL bRet; @@ -1769,16 +1821,16 @@ static void test_Installer_RegistryValue(void) if (!RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey )) delete_key( hkey ); /* Does our key exist? Shouldn't; check with all three possible value parameter types */ - hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet); + hr = Installer_RegistryValueE(curr_user, szKey, &bRet); ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr); ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n"); memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString); + hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString); ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR); + hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR); ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); /* Create key */ @@ -1807,87 +1859,87 @@ static void test_Installer_RegistryValue(void) /* Does our key exist? It should, and make sure we retrieve the correct default value */ bRet = FALSE; - hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet); + hr = Installer_RegistryValueE(curr_user, szKey, &bRet); ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr); ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n"); memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString); + hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString); ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne); /* Ask for the value of a nonexistent key */ memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szExpand, szString); + hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString); ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); /* Get values of keys */ memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szOne, szString); + hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString); ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne); VariantInit(&vararg); V_VT(&vararg) = VT_BSTR; V_BSTR(&vararg) = SysAllocString(szTwo); - hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_I4); + hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4); ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr); ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult)); VariantClear(&varresult); memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szThree, szString); + hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString); ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY); memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFour, szString); + hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString); ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour); memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFive, szString); + hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString); ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFiveHi); memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szSix, szString); + hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString); ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_); VariantInit(&vararg); V_VT(&vararg) = VT_BSTR; V_BSTR(&vararg) = SysAllocString(szSeven); - hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_EMPTY); + hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY); ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr); /* Get string class name for the key */ memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR); + hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR); ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank); /* Get name of a value by positive number (RegEnumValue like), valid index */ memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 2, szString, VT_BSTR); + hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR); ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); /* RegEnumValue order seems different on wine */ todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo); /* Get name of a value by positive number (RegEnumValue like), invalid index */ memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 10, szString, VT_EMPTY); + hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY); ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); /* Get name of a subkey by negative number (RegEnumValue like), valid index */ memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -1, szString, VT_BSTR); + hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR); ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight); /* Get name of a subkey by negative number (RegEnumValue like), invalid index */ memset(szString, 0, sizeof(szString)); - hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -10, szString, VT_EMPTY); + hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY); ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); /* clean up */ @@ -2116,6 +2168,12 @@ static void test_Installer_InstallProduct(void) /* Installer::InstallProduct */ hr = Installer_InstallProduct(szMsifile, NULL); + if (hr == DISP_E_EXCEPTION) + { + skip("Installer object not supported.\n"); + delete_test_files(); + return; + } ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr); /* Installer::ProductState for our product code, which has been installed */ @@ -2140,14 +2198,14 @@ static void test_Installer_InstallProduct(void) /* Package name */ memset(szString, 0, sizeof(szString)); hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString); - todo_wine ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); + ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile); /* Product name */ memset(szString, 0, sizeof(szString)); hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString); ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); - ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST); + todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST); /* Installer::Products */ test_Installer_Products(TRUE); diff --git a/rostests/winetests/msi/db.c b/rostests/winetests/msi/db.c index e912a3a0685..9be169184fa 100644 --- a/rostests/winetests/msi/db.c +++ b/rostests/winetests/msi/db.c @@ -1643,17 +1643,18 @@ static void test_msiimport(void) ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); r = add_table_to_db(hdb, endlines1); - todo_wine + if (r == ERROR_FUNCTION_FAILED) { - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + /* win9x doesn't handle this case */ + skip("endlines not handled correctly.\n"); + MsiCloseHandle(hdb); + DeleteFileA(msifile); + return; } r = add_table_to_db(hdb, endlines2); - todo_wine - { - ok(r == ERROR_FUNCTION_FAILED, - "Expected ERROR_FUNCTION_FAILED, got %d\n", r); - } + ok(r == ERROR_FUNCTION_FAILED, + "Expected ERROR_FUNCTION_FAILED, got %d\n", r); query = "SELECT * FROM `TestTable`"; r = MsiDatabaseOpenView(hdb, query, &view); @@ -1752,7 +1753,8 @@ static void test_msiimport(void) MsiCloseHandle(rec); r = MsiViewFetch(view, &rec); - ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(r == ERROR_NO_MORE_ITEMS, + "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); r = MsiViewClose(view); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); @@ -1761,37 +1763,28 @@ static void test_msiimport(void) query = "SELECT * FROM `Table`"; r = MsiDatabaseOpenView(hdb, query, &view); - todo_wine - { - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - } + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec); count = MsiRecordGetFieldCount(rec); - todo_wine - { - ok(count == 6, "Expected 6, got %d\n", count); - ok(check_record(rec, 1, "A"), "Expected A\n"); - ok(check_record(rec, 2, "B"), "Expected B\n"); - ok(check_record(rec, 3, "C"), "Expected C\n"); - ok(check_record(rec, 4, "D"), "Expected D\n"); - ok(check_record(rec, 5, "E"), "Expected E\n"); - ok(check_record(rec, 6, "F"), "Expected F\n"); - } + ok(count == 6, "Expected 6, got %d\n", count); + ok(check_record(rec, 1, "A"), "Expected A\n"); + ok(check_record(rec, 2, "B"), "Expected B\n"); + ok(check_record(rec, 3, "C"), "Expected C\n"); + ok(check_record(rec, 4, "D"), "Expected D\n"); + ok(check_record(rec, 5, "E"), "Expected E\n"); + ok(check_record(rec, 6, "F"), "Expected F\n"); MsiCloseHandle(rec); r = MsiViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec); count = MsiRecordGetFieldCount(rec); - todo_wine - { - ok(count == 6, "Expected 6, got %d\n", count); - ok(check_record(rec, 1, "s72"), "Expected s72\n"); - ok(check_record(rec, 2, "s72"), "Expected s72\n"); - ok(check_record(rec, 3, "s72"), "Expected s72\n"); - ok(check_record(rec, 4, "s72"), "Expected s72\n"); - ok(check_record(rec, 5, "s72"), "Expected s72\n"); - ok(check_record(rec, 6, "s72"), "Expected s72\n"); - } + ok(count == 6, "Expected 6, got %d\n", count); + ok(check_record(rec, 1, "s72"), "Expected s72\n"); + ok(check_record(rec, 2, "s72"), "Expected s72\n"); + ok(check_record(rec, 3, "s72"), "Expected s72\n"); + ok(check_record(rec, 4, "s72"), "Expected s72\n"); + ok(check_record(rec, 5, "s72"), "Expected s72\n"); + ok(check_record(rec, 6, "s72"), "Expected s72\n"); MsiCloseHandle(rec); MsiViewClose(view); @@ -1799,51 +1792,36 @@ static void test_msiimport(void) query = "SELECT * FROM `Table`"; r = MsiDatabaseOpenView(hdb, query, &view); - todo_wine - { - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - } + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); r = MsiViewExecute(view, 0); - todo_wine - { - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - } + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); r = MsiViewFetch(view, &rec); - todo_wine - { - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(check_record(rec, 1, "a"), "Expected 'a'\n"); - ok(check_record(rec, 2, "b"), "Expected 'b'\n"); - ok(check_record(rec, 3, "c"), "Expected 'c'\n"); - ok(check_record(rec, 4, "d"), "Expected 'd'\n"); - ok(check_record(rec, 5, "e"), "Expected 'e'\n"); - ok(check_record(rec, 6, "f"), "Expected 'f'\n"); - } + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(check_record(rec, 1, "a"), "Expected 'a'\n"); + ok(check_record(rec, 2, "b"), "Expected 'b'\n"); + ok(check_record(rec, 3, "c"), "Expected 'c'\n"); + ok(check_record(rec, 4, "d"), "Expected 'd'\n"); + ok(check_record(rec, 5, "e"), "Expected 'e'\n"); + ok(check_record(rec, 6, "f"), "Expected 'f'\n"); MsiCloseHandle(rec); r = MsiViewFetch(view, &rec); - todo_wine - { - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(check_record(rec, 1, "g"), "Expected 'g'\n"); - ok(check_record(rec, 2, "h"), "Expected 'h'\n"); - ok(check_record(rec, 3, "i"), "Expected 'i'\n"); - ok(check_record(rec, 4, "j"), "Expected 'j'\n"); - ok(check_record(rec, 5, "k"), "Expected 'k'\n"); - ok(check_record(rec, 6, "l"), "Expected 'l'\n"); - } + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(check_record(rec, 1, "g"), "Expected 'g'\n"); + ok(check_record(rec, 2, "h"), "Expected 'h'\n"); + ok(check_record(rec, 3, "i"), "Expected 'i'\n"); + ok(check_record(rec, 4, "j"), "Expected 'j'\n"); + ok(check_record(rec, 5, "k"), "Expected 'k'\n"); + ok(check_record(rec, 6, "l"), "Expected 'l'\n"); MsiCloseHandle(rec); r = MsiViewFetch(view, &rec); - todo_wine - { - ok(r == ERROR_NO_MORE_ITEMS, - "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); - } + ok(r == ERROR_NO_MORE_ITEMS, + "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); MsiViewClose(view); MsiCloseHandle(view); @@ -3235,6 +3213,11 @@ static void test_join(void) MsiViewClose(hview); MsiCloseHandle(hview); + query = "SELECT * FROM `Nonexistent`, `One`"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok( r == ERROR_BAD_QUERY_SYNTAX, + "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r ); + MsiCloseHandle(hdb); DeleteFile(msifile); } @@ -4799,6 +4782,10 @@ static void test_order(void) hdb = create_db(); ok(hdb, "failed to create db\n"); + query = "CREATE TABLE `Empty` ( `A` SHORT NOT NULL PRIMARY KEY `A`)"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + query = "CREATE TABLE `Mesa` ( `A` SHORT NOT NULL, `B` SHORT, `C` SHORT PRIMARY KEY `A`)"; r = run_query(hdb, 0, query); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); @@ -4984,6 +4971,18 @@ static void test_order(void) r = MsiViewFetch(hview, &hrec); ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + MsiViewClose(hview); + MsiCloseHandle(hview); + + query = "SELECT * FROM `Empty` ORDER BY `A`"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + MsiViewClose(hview); MsiCloseHandle(hview); MsiCloseHandle(hdb); @@ -5255,10 +5254,7 @@ static void test_quotes(void) write_file("import.idt", import_dat, (sizeof(import_dat) - 1) * sizeof(char)); r = MsiDatabaseImportA(hdb, CURR_DIR, "import.idt"); - todo_wine - { - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - } + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); DeleteFileA("import.idt"); @@ -5275,19 +5271,13 @@ static void test_quotes(void) size = MAX_PATH; r = MsiRecordGetString(hrec, 1, buf, &size); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - todo_wine - { - ok(!lstrcmp(buf, "This is a new 'string' ok"), - "Expected \"This is a new 'string' ok\", got %s\n", buf); - } + ok(!lstrcmp(buf, "This is a new 'string' ok"), + "Expected \"This is a new 'string' ok\", got %s\n", buf); MsiCloseHandle(hrec); r = MsiViewFetch(hview, &hrec); - todo_wine - { - ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); - } + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); MsiCloseHandle(hview); @@ -5501,6 +5491,360 @@ static void test_carriagereturn(void) DeleteFileA(msifile); } +static void test_noquotes(void) +{ + MSIHANDLE hdb, hview, hrec; + const char *query; + char buf[MAX_PATH]; + UINT r; + DWORD size; + + DeleteFile(msifile); + + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "CREATE TABLE Table ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + query = "CREATE TABLE `Table` ( A CHAR(72) NOT NULL PRIMARY KEY `A` )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "CREATE TABLE `Table2` ( `A` CHAR(72) NOT NULL PRIMARY KEY A )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "CREATE TABLE `Table3` ( A CHAR(72) NOT NULL PRIMARY KEY A )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `_Tables`"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetStringA(hrec, 1, buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf); + + MsiCloseHandle(hrec); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetStringA(hrec, 1, buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf); + + MsiCloseHandle(hrec); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetStringA(hrec, 1, buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf); + + MsiCloseHandle(hrec); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + + MsiViewClose(hview); + MsiCloseHandle(hview); + + query = "SELECT * FROM `_Columns`"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetStringA(hrec, 1, buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "Table"), "Expected \"Table\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(hrec, 2); + ok(r == 1, "Expected 1, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetStringA(hrec, 3, buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf); + + MsiCloseHandle(hrec); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetStringA(hrec, 1, buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "Table2"), "Expected \"Table2\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(hrec, 2); + ok(r == 1, "Expected 1, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetStringA(hrec, 3, buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf); + + MsiCloseHandle(hrec); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetStringA(hrec, 1, buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "Table3"), "Expected \"Table3\", got \"%s\"\n", buf); + + r = MsiRecordGetInteger(hrec, 2); + ok(r == 1, "Expected 1, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetStringA(hrec, 3, buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "A"), "Expected \"A\", got \"%s\"\n", buf); + + MsiCloseHandle(hrec); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + + MsiViewClose(hview); + MsiCloseHandle(hview); + + query = "INSERT INTO Table ( `A` ) VALUES ( 'hi' )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + query = "INSERT INTO `Table` ( A ) VALUES ( 'hi' )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "INSERT INTO `Table` ( `A` ) VALUES ( hi )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + query = "SELECT * FROM Table WHERE `A` = 'hi'"; + r = run_query(hdb, 0, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + query = "SELECT * FROM `Table` WHERE `A` = hi"; + r = run_query(hdb, 0, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + query = "SELECT * FROM Table"; + r = run_query(hdb, 0, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + query = "SELECT * FROM Table2"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + + MsiViewClose(hview); + MsiCloseHandle(hview); + + query = "SELECT * FROM `Table` WHERE A = 'hi'"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetStringA(hrec, 1, buf, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "hi"), "Expected \"hi\", got \"%s\"\n", buf); + + MsiCloseHandle(hrec); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + + MsiViewClose(hview); + MsiCloseHandle(hview); + + + MsiCloseHandle(hdb); + DeleteFileA(msifile); +} + +static void read_file_data(LPCSTR filename, LPSTR buffer) +{ + OFSTRUCT ofs; + HFILE file; + DWORD read; + + file = OpenFile(filename, &ofs, OF_READ); + ZeroMemory(buffer, MAX_PATH); + ReadFile((HANDLE)file, buffer, MAX_PATH, &read, NULL); + CloseHandle((HANDLE)file); +} + +static void test_forcecodepage(void) +{ + MSIHANDLE hdb; + const char *query; + char buffer[MAX_PATH]; + UINT r; + + DeleteFile(msifile); + + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `_ForceCodepage`"; + r = run_query(hdb, 0, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL PRIMARY KEY `A` )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `_ForceCodepage`"; + r = run_query(hdb, 0, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + r = MsiDatabaseCommit(hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `_ForceCodepage`"; + r = run_query(hdb, 0, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + MsiCloseHandle(hdb); + + r = MsiOpenDatabase(msifile, MSIDBOPEN_DIRECT, &hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `_ForceCodepage`"; + r = run_query(hdb, 0, query); + ok(r == ERROR_BAD_QUERY_SYNTAX, "Expected ERROR_BAD_QUERY_SYNTAX, got %d\n", r); + + r = MsiDatabaseExport(hdb, "_ForceCodepage", CURR_DIR, "forcecodepage.idt"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + read_file_data("forcecodepage.idt", buffer); + ok(!lstrcmpA(buffer, "\r\n\r\n0\t_ForceCodepage\r\n"), + "Expected \"\r\n\r\n0\t_ForceCodepage\r\n\", got \"%s\"", buffer); + + MsiCloseHandle(hdb); + DeleteFileA(msifile); + DeleteFileA("forcecodepage.idt"); +} + +static void test_viewmodify_refresh(void) +{ + MSIHANDLE hdb, hview, hrec; + const char *query; + char buffer[MAX_PATH]; + UINT r; + DWORD size; + + DeleteFile(msifile); + + r = MsiOpenDatabase(msifile, MSIDBOPEN_CREATE, &hdb); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "CREATE TABLE `Table` ( `A` CHAR(72) NOT NULL, `B` INT PRIMARY KEY `A` )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hi', 1 )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `Table`"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hi'"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetStringA(hrec, 1, buffer, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buffer, "hi"), "Expected \"hi\", got \"%s\"\n", buffer); + ok(size == 2, "Expected 2, got %d\n", size); + + r = MsiRecordGetInteger(hrec, 2); + ok(r == 2, "Expected 2, got %d\n", r); + + MsiCloseHandle(hrec); + MsiViewClose(hview); + MsiCloseHandle(hview); + + query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hello', 3 )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "SELECT * FROM `Table` WHERE `B` = 3"; + r = MsiDatabaseOpenView(hdb, query, &hview); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiViewExecute(hview, 0); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewFetch(hview, &hrec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "UPDATE `Table` SET `B` = 2 WHERE `A` = 'hello'"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + query = "INSERT INTO `Table` ( `A`, `B` ) VALUES ( 'hithere', 3 )"; + r = run_query(hdb, 0, query); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + r = MsiViewModify(hview, MSIMODIFY_REFRESH, hrec); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + size = MAX_PATH; + r = MsiRecordGetStringA(hrec, 1, buffer, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buffer, "hello"), "Expected \"hello\", got \"%s\"\n", buffer); + ok(size == 5, "Expected 5, got %d\n", size); + + r = MsiRecordGetInteger(hrec, 2); + ok(r == 2, "Expected 2, got %d\n", r); + + MsiCloseHandle(hrec); + MsiViewClose(hview); + MsiCloseHandle(hview); + MsiCloseHandle(hdb); + DeleteFileA(msifile); +} + START_TEST(db) { test_msidatabase(); @@ -5534,4 +5878,7 @@ START_TEST(db) test_deleterow(); test_quotes(); test_carriagereturn(); + test_noquotes(); + test_forcecodepage(); + test_viewmodify_refresh(); } diff --git a/rostests/winetests/msi/format.c b/rostests/winetests/msi/format.c index aec347dad73..f4c1670cf4a 100644 --- a/rostests/winetests/msi/format.c +++ b/rostests/winetests/msi/format.c @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -2176,6 +2177,7 @@ static void test_formatrecord_tables(void) CHAR buf[MAX_PATH]; CHAR curr_dir[MAX_PATH]; CHAR expected[MAX_PATH]; + CHAR root[MAX_PATH]; DWORD size; UINT r; @@ -2304,48 +2306,57 @@ static void test_formatrecord_tables(void) r = MsiDoAction(hpkg, "CostFinalize"); ok( r == ERROR_SUCCESS, "CostFinalize failed: %d\n", r); + size = MAX_PATH; + MsiGetProperty( hpkg, "ROOTDRIVE", root, &size ); + + sprintf( expected, "1: %sfrontal.txt ", root); + /* frontal full file key */ size = MAX_PATH; MsiRecordSetString( hrec, 1, "[#frontal_file]" ); r = MsiFormatRecord( hpkg, hrec, buf, &size ); ok( r == ERROR_SUCCESS, "format record failed: %d\n", r); - ok( !lstrcmp( buf, "1: C:\\frontal.txt " ), "Expected '1: C:\\frontal.txt ', got %s\n", buf); + ok( !lstrcmp( buf, expected ), "Expected \"%s\", got \"%s\"\n", expected, buf); /* frontal short file key */ size = MAX_PATH; MsiRecordSetString( hrec, 1, "[!frontal_file]" ); r = MsiFormatRecord( hpkg, hrec, buf, &size ); ok( r == ERROR_SUCCESS, "format record failed: %d\n", r); - ok( !lstrcmp( buf, "1: C:\\frontal.txt " ), "Expected '1: C:\\frontal.txt ', got %s\n", buf); + ok( !lstrcmp( buf, expected ), "Expected \"%s\", got \"%s\"\n", expected, buf); + + sprintf( expected, "1: %sI am a really long directory\\temporal.txt ", root); /* temporal full file key */ size = MAX_PATH; MsiRecordSetString( hrec, 1, "[#temporal_file]" ); r = MsiFormatRecord( hpkg, hrec, buf, &size ); ok( r == ERROR_SUCCESS, "format record failed: %d\n", r); - ok( !lstrcmp( buf, "1: C:\\I am a really long directory\\temporal.txt " ), - "Expected '1: C:\\I am a really long directory\\temporal.txt ', got %s\n", buf); + ok( !lstrcmp( buf, expected ), "Expected \"%s\", got \"%s\"\n", expected, buf); /* temporal short file key */ size = MAX_PATH; MsiRecordSetString( hrec, 1, "[!temporal_file]" ); r = MsiFormatRecord( hpkg, hrec, buf, &size ); ok( r == ERROR_SUCCESS, "format record failed: %d\n", r); - ok( !lstrcmp( buf, "1: C:\\I am a really long directory\\temporal.txt " ), - "Expected '1: C:\\I am a really long directory\\temporal.txt ', got %s\n", buf); + ok( !lstrcmp( buf, expected ), "Expected \"%s\", got \"%s\"\n", expected, buf); /* custom action 51, files don't exist */ r = MsiDoAction( hpkg, "MyCustom" ); ok( r == ERROR_SUCCESS, "MyCustom failed: %d\n", r); + sprintf( expected, "%sI am a really long directory\\temporal.txt", root); + size = MAX_PATH; r = MsiGetProperty( hpkg, "prop", buf, &size ); ok( r == ERROR_SUCCESS, "get property failed: %d\n", r); - ok( !lstrcmp( buf, "C:\\I am a really long directory\\temporal.txt" ), - "Expected 'C:\\I am a really long directory\\temporal.txt', got %s\n", buf); + ok( !lstrcmp( buf, expected ), "Expected \"%s\", got \"%s\"\n", expected, buf); + + sprintf( buf, "%sI am a really long directory", root ); + CreateDirectory( buf, NULL ); - CreateDirectory( "C:\\I am a really long directory", NULL ); - create_test_file( "C:\\I am a really long directory\\temporal.txt" ); + lstrcat( buf, "\\temporal.txt" ); + create_test_file( buf ); /* custom action 51, files exist */ r = MsiDoAction( hpkg, "MyCustom" ); @@ -2356,8 +2367,7 @@ static void test_formatrecord_tables(void) ok( r == ERROR_SUCCESS, "get property failed: %d\n", r); todo_wine { - ok( !lstrcmp( buf, "C:\\I am a really long directory\\temporal.txt" ), - "Expected 'C:\\I am a really long directory\\temporal.txt', got %s\n", buf); + ok( !lstrcmp( buf, expected ), "Expected \"%s\", got \"%s\"\n", expected, buf); } /* custom action 51, escaped text 1 */ @@ -2387,13 +2397,14 @@ static void test_formatrecord_tables(void) ok( r == ERROR_SUCCESS, "get property failed: %d\n", r); ok( !lstrcmp( buf, "" ), "Expected '', got %s\n", buf); + sprintf( expected, "1: %sI am a really long directory\\ ", root); + /* component with INSTALLSTATE_LOCAL */ size = MAX_PATH; MsiRecordSetString( hrec, 1, "[$temporal]" ); r = MsiFormatRecord( hpkg, hrec, buf, &size ); ok( r == ERROR_SUCCESS, "format record failed: %d\n", r); - ok( !lstrcmp( buf, "1: C:\\I am a really long directory\\ " ), - "Expected '1: C:\\I am a really long directory\\ ', got %s\n", buf); + ok( !lstrcmp( buf, expected ), "Expected \"%s\", got \"%s\"\n", expected, buf); r = MsiSetComponentState( hpkg, "temporal", INSTALLSTATE_SOURCE ); ok( r == ERROR_SUCCESS, "failed to set install state: %d\n", r); @@ -2408,8 +2419,11 @@ static void test_formatrecord_tables(void) ok( r == ERROR_SUCCESS, "format record failed: %d\n", r); ok( !lstrcmp( buf, expected ), "Expected '%s', got %s\n", expected, buf); - DeleteFile( "C:\\I am a really long directory\\temporal.txt" ); - RemoveDirectory( "C:\\I am a really long directory" ); + sprintf( buf, "%sI am a really long directory\\temporal.txt", root ); + DeleteFile( buf ); + + sprintf( buf, "%sI am a really long directory", root ); + RemoveDirectory( buf ); MsiCloseHandle( hrec ); MsiCloseHandle( hpkg ); diff --git a/rostests/winetests/msi/install.c b/rostests/winetests/msi/install.c index b5892c0880e..5ac3852416b 100644 --- a/rostests/winetests/msi/install.c +++ b/rostests/winetests/msi/install.c @@ -34,6 +34,8 @@ static UINT (WINAPI *pMsiQueryComponentStateA) (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, LPCSTR, INSTALLSTATE*); +static UINT (WINAPI *pMsiSourceListEnumSourcesA) + (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPSTR, LPDWORD); static UINT (WINAPI *pMsiSourceListGetInfoA) (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, LPSTR, LPDWORD); @@ -144,7 +146,9 @@ static const CHAR property_dat[] = "Property\tValue\n" "Setup\tSetup\n" "UpgradeCode\t{4C0EAA15-0264-4E5A-8758-609EF142B92D}\n" "AdminProperties\tPOSTADMIN\n" - "ROOTDRIVE\tC:\\\n"; + "ROOTDRIVE\tC:\\\n" + "SERVNAME\tTestService\n" + "SERVDISP\tTestServiceDisp\n"; static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n" "s72\ti2\tl255\tL255\tL0\ts72\n" @@ -158,7 +162,7 @@ static const CHAR service_install_dat[] = "ServiceInstall\tName\tDisplayName\tSe "LoadOrderGroup\tDependencies\tStartName\tPassword\tArguments\tComponent_\tDescription\n" "s72\ts255\tL255\ti4\ti4\ti4\tS255\tS255\tS255\tS255\tS255\ts72\tL255\n" "ServiceInstall\tServiceInstall\n" - "TestService\tTestService\tTestService\t2\t3\t0\t\t\tTestService\t\t\tservice_comp\t\t"; + "TestService\t[SERVNAME]\t[SERVDISP]\t2\t3\t0\t\t\tTestService\t\t\tservice_comp\t\t"; static const CHAR service_control_dat[] = "ServiceControl\tName\tEvent\tArguments\tWait\tComponent_\n" "s72\tl255\ti2\tL255\tI2\ts72\n" @@ -173,6 +177,13 @@ static const CHAR cc_component_dat[] = "Component\tComponentId\tDirectory_\tAttr "augustus\t\tMSITESTDIR\t0\t1\taugustus\n" "caesar\t\tMSITESTDIR\t0\t1\tcaesar\n"; +static const CHAR cc2_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" + "s72\tS38\ts72\ti2\tS255\tS72\n" + "Component\tComponent\n" + "maximus\t\tMSITESTDIR\t0\t1\tmaximus\n" + "augustus\t\tMSITESTDIR\t0\t0\taugustus\n" + "caesar\t\tMSITESTDIR\t0\t1\tcaesar\n"; + static const CHAR cc_feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n" "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n" "Feature\tFeature\n" @@ -192,6 +203,14 @@ static const CHAR cc_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion "augustus\taugustus\taugustus\t50000\t\t\t16384\t2\n" "caesar\tcaesar\tcaesar\t500\t\t\t16384\t12"; +static const CHAR cc2_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n" + "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n" + "File\tFile\n" + "maximus\tmaximus\tmaximus\t500\t\t\t16384\t1\n" + "augustus\taugustus\taugustus\t50000\t\t\t16384\t2\n" + "tiberius\tmaximus\ttiberius\t500\t\t\t16384\t3\n" + "caesar\tcaesar\tcaesar\t500\t\t\t16384\t12"; + static const CHAR cc_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n" "i2\ti4\tL64\tS255\tS32\tS72\n" "Media\tDiskId\n" @@ -352,7 +371,7 @@ static const CHAR ci_install_exec_seq_dat[] = "Action\tCondition\tSequence\n" static const CHAR ci_custom_action_dat[] = "Action\tType\tSource\tTarget\tISComments\n" "s72\ti2\tS64\tS0\tS255\n" "CustomAction\tAction\n" - "RunInstall\t23\tmsitest\\concurrent.msi\tMYPROP=[UILevel]\t\n"; + "RunInstall\t87\tmsitest\\concurrent.msi\tMYPROP=[UILevel]\t\n"; static const CHAR ci_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" "s72\tS38\ts72\ti2\tS255\tS72\n" @@ -586,6 +605,31 @@ static const CHAR wrv_registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tCompon "Registry\tRegistry\n" "regdata\t2\tSOFTWARE\\Wine\\msitest\tValue\t[~]one[~]two[~]three\taugustus"; +static const CHAR ca51_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" + "s72\tS38\ts72\ti2\tS255\tS72\n" + "Component\tComponent\n" + "augustus\t\tMSITESTDIR\t0\tMYPROP=42\taugustus\n"; + +static const CHAR ca51_install_exec_seq_dat[] = "Action\tCondition\tSequence\n" + "s72\tS255\tI2\n" + "InstallExecuteSequence\tAction\n" + "ValidateProductID\t\t700\n" + "GoodSetProperty\t\t725\n" + "BadSetProperty\t\t750\n" + "CostInitialize\t\t800\n" + "FileCost\t\t900\n" + "CostFinalize\t\t1000\n" + "InstallValidate\t\t1400\n" + "InstallInitialize\t\t1500\n" + "InstallFiles\t\t4000\n" + "InstallFinalize\t\t6600"; + +static const CHAR ca51_custom_action_dat[] = "Action\tType\tSource\tTarget\n" + "s72\ti2\tS64\tS0\n" + "CustomAction\tAction\n" + "GoodSetProperty\t51\tMYPROP\t42\n" + "BadSetProperty\t51\t\tMYPROP\n"; + typedef struct _msi_table { const CHAR *filename; @@ -622,6 +666,18 @@ static const msi_table cc_tables[] = ADD_TABLE(property), }; +static const msi_table cc2_tables[] = +{ + ADD_TABLE(cc2_component), + ADD_TABLE(directory), + ADD_TABLE(cc_feature), + ADD_TABLE(cc_feature_comp), + ADD_TABLE(cc2_file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(cc_media), + ADD_TABLE(property), +}; + static const msi_table co_tables[] = { ADD_TABLE(cc_component), @@ -887,6 +943,31 @@ static const msi_table wrv_tables[] = ADD_TABLE(wrv_registry), }; +static const msi_table sf_tables[] = +{ + ADD_TABLE(wrv_component), + ADD_TABLE(directory), + ADD_TABLE(rof_feature), + ADD_TABLE(ci2_feature_comp), + ADD_TABLE(ci2_file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(rof_media), + ADD_TABLE(property), +}; + +static const msi_table ca51_tables[] = +{ + ADD_TABLE(ca51_component), + ADD_TABLE(directory), + ADD_TABLE(rof_feature), + ADD_TABLE(ci2_feature_comp), + ADD_TABLE(ci2_file), + ADD_TABLE(ca51_install_exec_seq), + ADD_TABLE(rof_media), + ADD_TABLE(property), + ADD_TABLE(ca51_custom_action), +}; + /* cabinet definitions */ /* make the max size large so there is only one cab file */ @@ -1007,6 +1088,7 @@ static void init_functionpointers(void) trace("GetProcAddress(%s) failed\n", #func); GET_PROC(MsiQueryComponentStateA); + GET_PROC(MsiSourceListEnumSourcesA); GET_PROC(MsiSourceListGetInfoA); #undef GET_PROC @@ -1331,6 +1413,15 @@ static void test_MsiInstallProduct(void) LONG res; HKEY hkey; DWORD num, size, type; + SC_HANDLE scm; + + scm = OpenSCManager(NULL, NULL, GENERIC_ALL); + if (!scm && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) + { + skip("Services are not implemented, we are most likely on win9x\n"); + return; + } + CloseServiceHandle(scm); create_test_files(); create_database(msifile, tables, sizeof(tables) / sizeof(msi_table)); @@ -1486,21 +1577,25 @@ static void create_cc_test_files(void) create_file("maximus", 500); create_file("augustus", 50000); + create_file("tiberius", 500); create_file("caesar", 500); - set_cab_parameters(&cabParams, "test1.cab", 200); + set_cab_parameters(&cabParams, "test1.cab", 40000); hfci = FCICreate(&erf, file_placed, mem_alloc, mem_free, fci_open, fci_read, fci_write, fci_close, fci_seek, fci_delete, get_temp_file, &cabParams, cab_context); ok(hfci != NULL, "Failed to create an FCI context\n"); - res = add_file(hfci, "maximus", tcompTYPE_MSZIP); + res = add_file(hfci, "maximus", tcompTYPE_NONE); ok(res, "Failed to add file maximus\n"); - res = add_file(hfci, "augustus", tcompTYPE_MSZIP); + res = add_file(hfci, "augustus", tcompTYPE_NONE); ok(res, "Failed to add file augustus\n"); + res = add_file(hfci, "tiberius", tcompTYPE_NONE); + ok(res, "Failed to add file tiberius\n"); + res = FCIFlushCabinet(hfci, FALSE, get_next_cabinet, progress); ok(res, "Failed to flush the cabinet\n"); @@ -1511,6 +1606,7 @@ static void create_cc_test_files(void) DeleteFile("maximus"); DeleteFile("augustus"); + DeleteFile("tiberius"); DeleteFile("caesar"); } @@ -1542,13 +1638,29 @@ static void test_continuouscabs(void) MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); r = MsiInstallProductA(msifile, NULL); - ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); - todo_wine + if (r == ERROR_SUCCESS) /* win9x has a problem with this */ { ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n"); ok(delete_pf("msitest\\caesar", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); } + + delete_cab_files(); + DeleteFile(msifile); + + create_cc_test_files(); + create_database(msifile, cc2_tables, sizeof(cc2_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\augustus", TRUE), "File installed\n"); + ok(delete_pf("msitest\\tiberius", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\caesar", TRUE), "File not installed\n"); ok(delete_pf("msitest", FALSE), "File not installed\n"); delete_cab_files(); @@ -1605,13 +1717,13 @@ static void test_caborder(void) create_database(msifile, co_tables, sizeof(co_tables) / sizeof(msi_table)); r = MsiInstallProductA(msifile, NULL); - ok(!delete_pf("msitest\\augustus", TRUE), "File is installed\n"); + ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r); ok(!delete_pf("msitest\\caesar", TRUE), "File is installed\n"); ok(!delete_pf("msitest", FALSE), "File is installed\n"); todo_wine { + ok(!delete_pf("msitest\\augustus", TRUE), "File is installed\n"); ok(!delete_pf("msitest\\maximus", TRUE), "File is installed\n"); - ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r); } delete_cab_files(); @@ -1621,11 +1733,11 @@ static void test_caborder(void) create_database(msifile, co2_tables, sizeof(co2_tables) / sizeof(msi_table)); r = MsiInstallProductA(msifile, NULL); - ok(!delete_pf("msitest\\augustus", TRUE), "File is installed\n"); ok(!delete_pf("msitest\\caesar", TRUE), "File is installed\n"); todo_wine { ok(r == ERROR_INSTALL_FAILURE, "Expected ERROR_INSTALL_FAILURE, got %u\n", r); + ok(!delete_pf("msitest\\augustus", TRUE), "File is installed\n"); ok(!delete_pf("msitest\\maximus", TRUE), "File is installed\n"); ok(!delete_pf("msitest", FALSE), "File is installed\n"); } @@ -1679,14 +1791,14 @@ static void test_samesequence(void) MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); r = MsiInstallProductA(msifile, NULL); - todo_wine + if (r == ERROR_SUCCESS) /* win9x has a problem with this */ { ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n"); ok(delete_pf("msitest\\caesar", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); } - ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); - ok(delete_pf("msitest", FALSE), "File not installed\n"); delete_cab_files(); DeleteFile(msifile); @@ -1702,14 +1814,14 @@ static void test_uiLevelFlags(void) MsiSetInternalUI(INSTALLUILEVEL_NONE | INSTALLUILEVEL_SOURCERESONLY, NULL); r = MsiInstallProductA(msifile, NULL); - ok(!delete_pf("msitest\\maximus", TRUE), "UI install occurred, but execute-only was requested.\n"); - todo_wine + if (r == ERROR_SUCCESS) /* win9x has a problem with this */ { ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(!delete_pf("msitest\\maximus", TRUE), "UI install occurred, but execute-only was requested.\n"); ok(delete_pf("msitest\\caesar", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); } - ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n"); - ok(delete_pf("msitest", FALSE), "File not installed\n"); delete_cab_files(); DeleteFile(msifile); @@ -1848,9 +1960,15 @@ static void test_concurrentinstall(void) ok(delete_pf("msitest\\augustus", TRUE), "File not installed\n"); ok(delete_pf("msitest", FALSE), "File not installed\n"); - /* Delete the files in the temp (current) folder */ - DeleteFile(msifile); DeleteFile(path); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\augustus", TRUE), "File installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + DeleteFile(msifile); DeleteFile("msitest\\msitest\\augustus"); DeleteFile("msitest\\maximus"); RemoveDirectory("msitest\\msitest"); @@ -1980,7 +2098,7 @@ static void get_date_str(LPSTR date) sprintf(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay); } -static void test_publish(void) +static void test_publish_registerproduct(void) { UINT r; LONG res; @@ -1992,6 +2110,12 @@ static void test_publish(void) static const CHAR subkey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; + if (!pMsiQueryComponentStateA) + { + skip("MsiQueryComponentStateA is not available\n"); + return; + } + get_date_str(date); GetTempPath(MAX_PATH, temp); @@ -2022,121 +2146,6 @@ static void test_publish(void) res = RegOpenKeyA(uninstall, prodcode, &prodkey); ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - /* nothing published */ - r = MsiInstallProductA(msifile, NULL); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); - ok(pf_exists("msitest\\maximus"), "File not installed\n"); - ok(pf_exists("msitest"), "File not installed\n"); - - state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); - ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - res = RegOpenKeyA(uninstall, prodcode, &prodkey); - ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - - /* install again */ - r = MsiInstallProductA(msifile, NULL); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(pf_exists("msitest\\maximus"), "File not installed\n"); - ok(pf_exists("msitest"), "File not installed\n"); - - state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); - ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - res = RegOpenKeyA(uninstall, prodcode, &prodkey); - ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - - /* try to uninstall */ - r = MsiInstallProductA(msifile, "REMOVE=ALL"); - todo_wine - { - ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - } - ok(pf_exists("msitest\\maximus"), "File deleted\n"); - ok(pf_exists("msitest"), "File deleted\n"); - - state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); - ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - res = RegOpenKeyA(uninstall, prodcode, &prodkey); - ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - - /* PublishProduct */ - r = MsiInstallProductA(msifile, "PUBLISH_PRODUCT=1"); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(pf_exists("msitest\\maximus"), "File not installed\n"); - ok(pf_exists("msitest"), "File not installed\n"); - - state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); - - state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); - ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - res = RegOpenKeyA(uninstall, prodcode, &prodkey); - ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - - /* try to uninstall after PublishProduct */ - r = MsiInstallProductA(msifile, "REMOVE=ALL"); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(pf_exists("msitest\\maximus"), "File deleted\n"); - ok(pf_exists("msitest"), "File deleted\n"); - - state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); - ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - res = RegOpenKeyA(uninstall, prodcode, &prodkey); - ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - /* RegisterProduct */ r = MsiInstallProductA(msifile, "REGISTER_PRODUCT=1"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); @@ -2149,6 +2158,9 @@ static void test_publish(void) state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); @@ -2186,8 +2198,8 @@ static void test_publish(void) RegCloseKey(prodkey); - /* complete uninstall */ - r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); + /* try to uninstall after RegisterProduct */ + r = MsiInstallProductA(msifile, "REMOVE=ALL"); todo_wine { ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); @@ -2216,7 +2228,10 @@ static void test_publish(void) ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); res = RegOpenKeyA(uninstall, prodcode, &prodkey); - ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + todo_wine + { + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + } todo_wine { @@ -2247,14 +2262,47 @@ static void test_publish(void) RegCloseKey(prodkey); - /* PublishProduct and RegisterProduct */ - r = MsiInstallProductA(msifile, "REGISTER_PRODUCT=1 PUBLISH_PRODUCT=1"); + /* full install to remove */ + r = MsiInstallProductA(msifile, "FULL=1"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(pf_exists("msitest\\maximus"), "File not installed\n"); - ok(pf_exists("msitest"), "File not installed\n"); + r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + RegCloseKey(uninstall); + DeleteFile(msifile); + DeleteFile("msitest\\maximus"); + RemoveDirectory("msitest"); + delete_pfmsitest_files(); +} + +static void test_publish_publishproduct(void) +{ + UINT r; + LONG res; + HKEY uninstall, prodkey; + INSTALLSTATE state; + CHAR prodcode[] = "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"; + + static const CHAR subkey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; + + if (!pMsiQueryComponentStateA) + { + skip("MsiQueryComponentStateA is not available\n"); + return; + } + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, subkey, &uninstall); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\maximus", 500); + + create_database(msifile, pp_tables, sizeof(pp_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL); state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - ok(state == INSTALLSTATE_DEFAULT, "Expected INSTALLSTATE_DEFAULT, got %d\n", state); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); @@ -2264,52 +2312,472 @@ static void test_publish(void) r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); - ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); res = RegOpenKeyA(uninstall, prodcode, &prodkey); - ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - CHECK_REG_STR(prodkey, "DisplayName", "MSITEST"); - CHECK_REG_STR(prodkey, "DisplayVersion", "1.1.1"); - CHECK_REG_STR(prodkey, "InstallDate", date); - CHECK_REG_STR(prodkey, "InstallSource", temp); - CHECK_REG_ISTR(prodkey, "ModifyPath", "MsiExec.exe /I{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - CHECK_REG_STR(prodkey, "Publisher", "Wine"); - CHECK_REG_STR(prodkey, "UninstallString", "MsiExec.exe /I{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - CHECK_REG_STR(prodkey, "AuthorizedCDFPrefix", NULL); - CHECK_REG_STR(prodkey, "Comments", NULL); - CHECK_REG_STR(prodkey, "Contact", NULL); - CHECK_REG_STR(prodkey, "HelpLink", NULL); - CHECK_REG_STR(prodkey, "HelpTelephone", NULL); - CHECK_REG_STR(prodkey, "InstallLocation", NULL); - CHECK_REG_STR(prodkey, "Readme", NULL); - CHECK_REG_STR(prodkey, "Size", NULL); - CHECK_REG_STR(prodkey, "URLInfoAbout", NULL); - CHECK_REG_STR(prodkey, "URLUpdateInfo", NULL); - CHECK_REG_DWORD(prodkey, "Language", 1033); - CHECK_REG_DWORD(prodkey, "Version", 0x1010001); - CHECK_REG_DWORD(prodkey, "VersionMajor", 1); - CHECK_REG_DWORD(prodkey, "VersionMinor", 1); - CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1); + /* PublishProduct */ + r = MsiInstallProductA(msifile, "PUBLISH_PRODUCT=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(pf_exists("msitest\\maximus"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + res = RegOpenKeyA(uninstall, prodcode, &prodkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + /* try to uninstall after PublishProduct */ + r = MsiInstallProductA(msifile, "REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(pf_exists("msitest\\maximus"), "File deleted\n"); + ok(pf_exists("msitest"), "File deleted\n"); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + res = RegOpenKeyA(uninstall, prodcode, &prodkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + /* full install to remove */ + r = MsiInstallProductA(msifile, "FULL=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + RegCloseKey(uninstall); + DeleteFile(msifile); + DeleteFile("msitest\\maximus"); + RemoveDirectory("msitest"); + delete_pfmsitest_files(); +} + +static void test_publish_publishfeatures(void) +{ + UINT r; + LONG res; + HKEY uninstall, prodkey; + INSTALLSTATE state; + CHAR prodcode[] = "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"; + + static const CHAR subkey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; + + if (!pMsiQueryComponentStateA) + { + skip("MsiQueryComponentStateA is not available\n"); + return; + } + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, subkey, &uninstall); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\maximus", 500); + + create_database(msifile, pp_tables, sizeof(pp_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + res = RegOpenKeyA(uninstall, prodcode, &prodkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + /* PublishFeatures */ + r = MsiInstallProductA(msifile, "PUBLISH_FEATURES=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(pf_exists("msitest\\maximus"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + /* try to uninstall after PublishFeatures */ + r = MsiInstallProductA(msifile, "REMOVE=ALL"); todo_wine { - CHECK_REG_DWORD(prodkey, "EstimatedSize", 12); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); } + ok(pf_exists("msitest\\maximus"), "File deleted\n"); + ok(pf_exists("msitest"), "File deleted\n"); - RegCloseKey(prodkey); + /* PublishFeatures and PublishProduct */ + r = MsiInstallProductA(msifile, "PUBLISH_PRODUCT=1 PUBLISH_FEATURES=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(pf_exists("msitest\\maximus"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + /* PublishFeatures and RegisterProduct */ + r = MsiInstallProductA(msifile, "REGISTER_PRODUCT=1 PUBLISH_FEATURES=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(pf_exists("msitest\\maximus"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_DEFAULT, "Expected INSTALLSTATE_DEFAULT, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + /* full install to remove */ + r = MsiInstallProductA(msifile, "FULL=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + RegCloseKey(uninstall); + DeleteFile(msifile); + DeleteFile("msitest\\maximus"); + RemoveDirectory("msitest"); + delete_pfmsitest_files(); +} + +static void test_publish_registeruser(void) +{ + UINT r; + LONG res; + HKEY uninstall, prodkey; + INSTALLSTATE state; + CHAR prodcode[] = "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"; + + static const CHAR subkey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; + + if (!pMsiQueryComponentStateA) + { + skip("MsiQueryComponentStateA is not available\n"); + return; + } + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, subkey, &uninstall); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\maximus", 500); + + create_database(msifile, pp_tables, sizeof(pp_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + res = RegOpenKeyA(uninstall, prodcode, &prodkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + /* RegisterUser */ + r = MsiInstallProductA(msifile, "REGISTER_USER=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(pf_exists("msitest\\maximus"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + res = RegOpenKeyA(uninstall, prodcode, &prodkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + /* try to uninstall after RegisterUser */ + r = MsiInstallProductA(msifile, "REMOVE=ALL"); + todo_wine + { + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + } + ok(pf_exists("msitest\\maximus"), "File deleted\n"); + ok(pf_exists("msitest"), "File deleted\n"); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + res = RegOpenKeyA(uninstall, prodcode, &prodkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + /* full install to remove */ + r = MsiInstallProductA(msifile, "FULL=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + RegCloseKey(uninstall); + DeleteFile(msifile); + DeleteFile("msitest\\maximus"); + RemoveDirectory("msitest"); + delete_pfmsitest_files(); +} + +static void get_user_sid(LPSTR *usersid) +{ + HANDLE token; + BYTE buf[1024]; + DWORD size; + PTOKEN_USER user; + HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll"); + static BOOL (WINAPI *pConvertSidToStringSidA)(PSID, LPSTR*); + + *usersid = NULL; + pConvertSidToStringSidA = (void *)GetProcAddress(hadvapi32, "ConvertSidToStringSidA"); + if (!pConvertSidToStringSidA) + return; + + OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token); + size = sizeof(buf); + GetTokenInformation(token, TokenUser, (void *)buf, size, &size); + user = (PTOKEN_USER)buf; + pConvertSidToStringSidA(user->User.Sid, usersid); +} + +static void test_publish_processcomponents(void) +{ + UINT r; + LONG res; + HKEY uninstall, prodkey, comp; + INSTALLSTATE state; + LPSTR usersid; + CHAR keypath[MAX_PATH]; + CHAR prodcode[] = "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"; + + static const CHAR subkey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; + + if (!pMsiQueryComponentStateA) + { + skip("MsiQueryComponentStateA is not available\n"); + return; + } + + get_user_sid(&usersid); + if (!usersid) + { + skip("ConvertSidToStringSidA is not available\n"); + return; + } + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, subkey, &uninstall); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\maximus", 500); + + create_database(msifile, pp_tables, sizeof(pp_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + res = RegOpenKeyA(uninstall, prodcode, &prodkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + /* ProcessComponent */ + r = MsiInstallProductA(msifile, "PROCESS_COMPONENTS=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(pf_exists("msitest\\maximus"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + res = RegOpenKeyA(uninstall, prodcode, &prodkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + /* try to uninstall after ProcessComponents */ + r = MsiInstallProductA(msifile, "REMOVE=ALL"); + todo_wine + { + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + } + ok(pf_exists("msitest\\maximus"), "File deleted\n"); + ok(pf_exists("msitest"), "File deleted\n"); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + res = RegOpenKeyA(uninstall, prodcode, &prodkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + /* ProcessComponent with PublishProduct */ + r = MsiInstallProductA(msifile, "PUBLISH_PRODUCT=1 PROCESS_COMPONENTS=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(pf_exists("msitest\\maximus"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + /* uninstall */ + r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* ProcessComponent with RegisterProduct */ + r = MsiInstallProductA(msifile, "REGISTER_PRODUCT=1 PROCESS_COMPONENTS=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(pf_exists("msitest\\maximus"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); + + state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + ok(state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); - /* try it again */ - r = MsiInstallProductA(msifile, "REGISTER_PRODUCT=1 PUBLISH_PRODUCT=1"); + /* ProcessComponent with RegisterProduct and PublishProduct */ + r = MsiInstallProductA(msifile, "REGISTER_PRODUCT=1 PUBLISH_PRODUCT=1 PROCESS_COMPONENTS=1"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); ok(pf_exists("msitest\\maximus"), "File not installed\n"); ok(pf_exists("msitest"), "File not installed\n"); state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - todo_wine - { - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - } + ok(state == INSTALLSTATE_DEFAULT, "Expected INSTALLSTATE_DEFAULT, got %d\n", state); state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); @@ -2319,52 +2787,65 @@ static void test_publish(void) r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); - todo_wine - { - ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - } - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - - res = RegOpenKeyA(uninstall, prodcode, &prodkey); - todo_wine - { - ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - } + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); - /* uninstall has a problem with this */ + /* uninstall */ r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); - todo_wine + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Components\\CBABC2FDCCB35E749A8944D8C1C098B5"); + + /* native has trouble removing the comp key unless it's a full install */ + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &comp); + if (res == ERROR_SUCCESS) { - ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + RegDeleteKeyA(comp, ""); + RegCloseKey(comp); } - ok(pf_exists("msitest\\maximus"), "File deleted\n"); - ok(pf_exists("msitest"), "File deleted\n"); - state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + RegCloseKey(uninstall); + DeleteFile(msifile); + DeleteFile("msitest\\maximus"); + RemoveDirectory("msitest"); + delete_pfmsitest_files(); +} - state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); +static void test_publish(void) +{ + UINT r; + LONG res; + HKEY uninstall, prodkey; + INSTALLSTATE state; + CHAR prodcode[] = "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"; + char date[MAX_PATH]; + char temp[MAX_PATH]; - r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); - ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + static const CHAR subkey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; - res = RegOpenKeyA(uninstall, prodcode, &prodkey); - todo_wine + if (!pMsiQueryComponentStateA) { - ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + skip("MsiQueryComponentStateA is not available\n"); + return; } - /* PublishProduct and RegisterProduct and ProcessComponents */ - r = MsiInstallProductA(msifile, "REGISTER_PRODUCT=1 PUBLISH_PRODUCT=1 PROCESS_COMPONENTS=1"); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(pf_exists("msitest\\maximus"), "File not installed\n"); - ok(pf_exists("msitest"), "File not installed\n"); + get_date_str(date); + GetTempPath(MAX_PATH, temp); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, subkey, &uninstall); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\maximus", 500); + + create_database(msifile, pp_tables, sizeof(pp_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL); state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - ok(state == INSTALLSTATE_DEFAULT, "Expected INSTALLSTATE_DEFAULT, got %d\n", state); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); @@ -2374,46 +2855,17 @@ static void test_publish(void) r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); res = RegOpenKeyA(uninstall, prodcode, &prodkey); - ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); - - CHECK_REG_STR(prodkey, "DisplayName", "MSITEST"); - CHECK_REG_STR(prodkey, "DisplayVersion", "1.1.1"); - CHECK_REG_STR(prodkey, "InstallDate", date); - CHECK_REG_STR(prodkey, "InstallSource", temp); - CHECK_REG_ISTR(prodkey, "ModifyPath", "MsiExec.exe /I{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - CHECK_REG_STR(prodkey, "Publisher", "Wine"); - CHECK_REG_STR(prodkey, "UninstallString", "MsiExec.exe /I{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - CHECK_REG_STR(prodkey, "AuthorizedCDFPrefix", NULL); - CHECK_REG_STR(prodkey, "Comments", NULL); - CHECK_REG_STR(prodkey, "Contact", NULL); - CHECK_REG_STR(prodkey, "HelpLink", NULL); - CHECK_REG_STR(prodkey, "HelpTelephone", NULL); - CHECK_REG_STR(prodkey, "InstallLocation", NULL); - CHECK_REG_STR(prodkey, "Readme", NULL); - CHECK_REG_STR(prodkey, "Size", NULL); - CHECK_REG_STR(prodkey, "URLInfoAbout", NULL); - CHECK_REG_STR(prodkey, "URLUpdateInfo", NULL); - CHECK_REG_DWORD(prodkey, "Language", 1033); - CHECK_REG_DWORD(prodkey, "Version", 0x1010001); - CHECK_REG_DWORD(prodkey, "VersionMajor", 1); - CHECK_REG_DWORD(prodkey, "VersionMinor", 1); - CHECK_REG_DWORD(prodkey, "WindowsInstaller", 1); - todo_wine - { - CHECK_REG_DWORD(prodkey, "EstimatedSize", 12); - } - - RegCloseKey(prodkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - /* complete uninstall */ - r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(pf_exists("msitest\\maximus"), "File deleted\n"); - ok(pf_exists("msitest"), "File deleted\n"); + /* nothing published */ + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(pf_exists("msitest\\maximus"), "File not installed\n"); + ok(pf_exists("msitest"), "File not installed\n"); state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); @@ -2430,13 +2882,10 @@ static void test_publish(void) ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); res = RegOpenKeyA(uninstall, prodcode, &prodkey); - todo_wine - { - ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - } + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - /* PublishProduct, RegisterProduct, ProcessComponents, PublishFeatures */ - r = MsiInstallProductA(msifile, "REGISTER_PRODUCT=1 PUBLISH_PRODUCT=1 PROCESS_COMPONENTS=1 PUBLISH_FEATURES=1"); + /* PublishProduct and RegisterProduct */ + r = MsiInstallProductA(msifile, "REGISTER_PRODUCT=1 PUBLISH_PRODUCT=1"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); ok(pf_exists("msitest\\maximus"), "File not installed\n"); ok(pf_exists("msitest"), "File not installed\n"); @@ -2445,15 +2894,15 @@ static void test_publish(void) ok(state == INSTALLSTATE_DEFAULT, "Expected INSTALLSTATE_DEFAULT, got %d\n", state); state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); - ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); - ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); r = pMsiQueryComponentStateA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, "{DF2CBABC-3BCC-47E5-A998-448D1C0C895B}", &state); - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + ok(r == ERROR_UNKNOWN_COMPONENT, "Expected ERROR_UNKNOWN_COMPONENT, got %d\n", r); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); res = RegOpenKeyA(uninstall, prodcode, &prodkey); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); @@ -2487,14 +2936,10 @@ static void test_publish(void) RegCloseKey(prodkey); - /* complete uninstall */ r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - todo_wine - { - ok(!pf_exists("msitest\\maximus"), "File deleted\n"); - ok(!pf_exists("msitest"), "File deleted\n"); - } + ok(pf_exists("msitest\\maximus"), "File deleted\n"); + ok(pf_exists("msitest"), "File deleted\n"); state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); @@ -2511,10 +2956,7 @@ static void test_publish(void) ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); res = RegOpenKeyA(uninstall, prodcode, &prodkey); - todo_wine - { - ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - } + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); /* complete install */ r = MsiInstallProductA(msifile, "FULL=1"); @@ -2852,10 +3294,7 @@ static void test_publish(void) ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); res = RegOpenKeyA(uninstall, prodcode, &prodkey); - todo_wine - { - ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); - } + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); /* make sure 'Program Files\msitest' is removed */ delete_pfmsitest_files(); @@ -2871,8 +3310,15 @@ static void test_publishsourcelist(void) UINT r; DWORD size; CHAR value[MAX_PATH]; + CHAR path[MAX_PATH]; CHAR prodcode[] = "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"; + if (!pMsiSourceListEnumSourcesA || !pMsiSourceListGetInfoA) + { + skip("MsiSourceListEnumSourcesA and/or MsiSourceListGetInfoA are not available\n"); + return; + } + CreateDirectoryA("msitest", NULL); create_file("msitest\\maximus", 500); @@ -2888,7 +3334,13 @@ static void test_publishsourcelist(void) /* nothing published */ size = 0xdeadbeef; r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + + size = 0xdeadbeef; + r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); @@ -2900,7 +3352,13 @@ static void test_publishsourcelist(void) /* after RegisterProduct */ size = 0xdeadbeef; r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + + size = 0xdeadbeef; + r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); @@ -2912,7 +3370,13 @@ static void test_publishsourcelist(void) /* after ProcessComponents */ size = 0xdeadbeef; r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + + size = 0xdeadbeef; + r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); @@ -2924,7 +3388,13 @@ static void test_publishsourcelist(void) /* after PublishFeatures */ size = 0xdeadbeef; r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + + size = 0xdeadbeef; + r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); @@ -2937,13 +3407,69 @@ static void test_publishsourcelist(void) size = MAX_PATH; lstrcpyA(value, "aaa"); r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size); - todo_wine - { - ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - ok(!lstrcmpA(value, "msitest.msi"), "Expected 'msitest.msi', got %s\n", value); - ok(size == 11, "Expected 11, got %d\n", size); - } + MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "msitest.msi"), "Expected 'msitest.msi', got %s\n", value); + ok(size == 11, "Expected 11, got %d\n", size); + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_MEDIAPACKAGEPATH, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value); + ok(size == 0, "Expected 0, got %d\n", size); + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_DISKPROMPT, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value); + ok(size == 0, "Expected 0, got %d\n", size); + + lstrcpyA(path, CURR_DIR); + lstrcatA(path, "\\"); + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, path), "Expected \"%s\", got \"%s\"\n", path, value); + ok(size == lstrlenA(path), "Expected %d, got %d\n", lstrlenA(path), size); + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "n"), "Expected \"n\", got \"%s\"\n", value); + ok(size == 1, "Expected 1, got %d\n", size); + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, path), "Expected \"%s\", got \"%s\"\n", path, value); + ok(size == lstrlenA(path), "Expected %d, got %d\n", lstrlenA(path), size); + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 1, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); /* complete uninstall */ r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); @@ -3530,12 +4056,18 @@ static void test_movefiles(void) ok(delete_pf("msitest\\kiribati", TRUE), "File not moved\n"); ok(!delete_pf("msitest\\lebanon", TRUE), "File moved\n"); ok(!delete_pf("msitest\\lebanon", FALSE), "Directory moved\n"); - ok(!delete_pf("msitest\\apple", TRUE), "File should not exist\n"); + /* either apple or application will be moved depending on directory order */ + if (!delete_pf("msitest\\apple", TRUE)) + ok(delete_pf("msitest\\application", TRUE), "File not moved\n"); + else + ok(!delete_pf("msitest\\application", TRUE), "File should not exist\n"); ok(delete_pf("msitest\\wildcard", TRUE), "File not moved\n"); - ok(delete_pf("msitest\\application", TRUE), "File not moved\n"); ok(!delete_pf("msitest\\ape", TRUE), "File moved\n"); - ok(delete_pf("msitest\\foo", TRUE), "File not moved\n"); - ok(!delete_pf("msitest\\fao", TRUE), "File should not exist\n"); + /* either fao or foo will be moved depending on directory order */ + if (delete_pf("msitest\\foo", TRUE)) + ok(!delete_pf("msitest\\fao", TRUE), "File should not exist\n"); + else + ok(delete_pf("msitest\\fao", TRUE), "File not moved\n"); ok(delete_pf("msitest\\single", TRUE), "File not moved\n"); ok(!delete_pf("msitest\\fbod", TRUE), "File moved\n"); ok(delete_pf("msitest\\budding", TRUE), "File not moved\n"); @@ -3685,6 +4217,62 @@ static void test_writeregistryvalues(void) RemoveDirectory("msitest"); } +static void test_sourcefolder(void) +{ + UINT r; + + CreateDirectoryA("msitest", NULL); + create_file("augustus", 500); + + create_database(msifile, sf_tables, sizeof(sf_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + r = MsiInstallProductA(msifile, NULL); + ok(!delete_pf("msitest\\augustus", TRUE), "File installed\n"); + todo_wine + { + ok(r == ERROR_INSTALL_FAILURE, + "Expected ERROR_INSTALL_FAILURE, got %u\n", r); + ok(!delete_pf("msitest", FALSE), "File installed\n"); + } + + RemoveDirectoryA("msitest"); + + r = MsiInstallProductA(msifile, NULL); + todo_wine + { + ok(r == ERROR_INSTALL_FAILURE, + "Expected ERROR_INSTALL_FAILURE, got %u\n", r); + ok(!delete_pf("msitest\\augustus", TRUE), "File installed\n"); + ok(!delete_pf("msitest", FALSE), "File installed\n"); + } + + DeleteFile(msifile); + DeleteFile("augustus"); +} + +static void test_customaction51(void) +{ + UINT r; + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\augustus", 500); + + create_database(msifile, ca51_tables, sizeof(ca51_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); + + r = MsiInstallProductA(msifile, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(delete_pf("msitest\\augustus", TRUE), "File installed\n"); + ok(delete_pf("msitest", FALSE), "File installed\n"); + + DeleteFile(msifile); + DeleteFile("msitest\\augustus"); + RemoveDirectory("msitest"); +} + START_TEST(install) { DWORD len; @@ -3717,6 +4305,11 @@ START_TEST(install) test_cabisextracted(); test_concurrentinstall(); test_setpropertyfolder(); + test_publish_registerproduct(); + test_publish_publishproduct(); + test_publish_publishfeatures(); + test_publish_registeruser(); + test_publish_processcomponents(); test_publish(); test_publishsourcelist(); test_transformprop(); @@ -3728,6 +4321,8 @@ START_TEST(install) test_missingcab(); test_duplicatefiles(); test_writeregistryvalues(); + test_sourcefolder(); + test_customaction51(); SetCurrentDirectoryA(prev_path); } diff --git a/rostests/winetests/msi/msi.c b/rostests/winetests/msi/msi.c index 520f0e77582..bb45d8da8fe 100644 --- a/rostests/winetests/msi/msi.c +++ b/rostests/winetests/msi/msi.c @@ -34,6 +34,8 @@ static INSTALLSTATE (WINAPI *pMsiGetComponentPathA) (LPCSTR, LPCSTR, LPSTR, DWORD*); static UINT (WINAPI *pMsiGetFileHashA) (LPCSTR, DWORD, PMSIFILEHASHINFO); +static UINT (WINAPI *pMsiGetProductInfoExA) + (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, LPCSTR, LPSTR, LPDWORD); static UINT (WINAPI *pMsiOpenPackageExA) (LPCSTR, DWORD, MSIHANDLE*); static UINT (WINAPI *pMsiOpenPackageExW) @@ -55,6 +57,7 @@ static void init_functionpointers(void) GET_PROC(hmsi, MsiGetComponentPathA) GET_PROC(hmsi, MsiGetFileHashA) + GET_PROC(hmsi, MsiGetProductInfoExA) GET_PROC(hmsi, MsiOpenPackageExA) GET_PROC(hmsi, MsiOpenPackageExW) GET_PROC(hmsi, MsiQueryComponentStateA) @@ -301,7 +304,8 @@ static void test_MsiGetFileHash(void) /* szFilePath is empty */ r = pMsiGetFileHashA("", 0, &hash); - ok(r == ERROR_PATH_NOT_FOUND, "Expected ERROR_PATH_NOT_FOUND, got %d\n", r); + ok(r == ERROR_PATH_NOT_FOUND || r == ERROR_BAD_PATHNAME, + "Expected ERROR_PATH_NOT_FOUND or ERROR_BAD_PATHNAME, got %d\n", r); /* szFilePath is nonexistent */ r = pMsiGetFileHashA(name, 0, &hash); @@ -643,7 +647,7 @@ static void test_MsiQueryFeatureState(void) state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); - res = RegSetValueExA(userkey, "feature", 0, REG_SZ, (const BYTE *)"", 8); + res = RegSetValueExA(userkey, "feature", 0, REG_SZ, (const BYTE *)"", 2); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); state = MsiQueryFeatureStateA(prodcode, "feature"); @@ -2042,6 +2046,4000 @@ static void test_MsiGetFileVersion(void) HeapFree(GetProcessHeap(), 0, langcheck); } +static void test_MsiGetProductInfo(void) +{ + UINT r; + LONG res; + HKEY propkey, source; + HKEY prodkey, localkey; + CHAR prodcode[MAX_PATH]; + CHAR prod_squashed[MAX_PATH]; + CHAR packcode[MAX_PATH]; + CHAR pack_squashed[MAX_PATH]; + CHAR buf[MAX_PATH]; + CHAR keypath[MAX_PATH]; + LPSTR usersid; + DWORD sz, val = 42; + + create_test_guid(prodcode, prod_squashed); + create_test_guid(packcode, pack_squashed); + get_user_sid(&usersid); + + /* NULL szProduct */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(NULL, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* empty szProduct */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA("", INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* garbage szProduct */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA("garbage", INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* guid without brackets */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA("6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D", + INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* guid with brackets */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA("{6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D}", + INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* same length as guid, but random */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA("A938G02JF-2NF3N93-VN3-2NNF-3KGKALDNF93", + INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* not installed, NULL szAttribute */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, NULL, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* not installed, NULL lpValueBuf */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, NULL, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* not installed, NULL pcchValueBuf */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, NULL); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* created guid cannot possibly be an installed product code */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* managed product code exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local user product code exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* both local and managed product code exist */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegCreateKeyA(localkey, "InstallProperties", &propkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(propkey, "HelpLink", 0, REG_SZ, (LPBYTE)"link", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpLink value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "link"), "Expected \"link\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + /* pcchBuf is NULL */ + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* lpValueBuf is NULL */ + sz = MAX_PATH; + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, NULL, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(sz == 4, "Expected 4, got %d\n", sz); + + /* lpValueBuf is NULL, pcchValueBuf is too small */ + sz = 2; + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, NULL, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(sz == 4, "Expected 4, got %d\n", sz); + + /* lpValueBuf is NULL, pcchValueBuf is too small */ + sz = 2; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(!lstrcmpA(buf, "apple"), "Expected buf to remain unchanged, got \"%s\"\n", buf); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(sz == 4, "Expected 4, got %d\n", sz); + + /* lpValueBuf is NULL, pcchValueBuf is exactly 4 */ + sz = 4; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), + "Expected buf to remain unchanged, got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "IMadeThis", 0, REG_SZ, (LPBYTE)"random", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* random property not supported by MSI, value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, "IMadeThis", buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected \"apple\", got \"%s\"\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + RegDeleteValueA(propkey, "IMadeThis"); + RegDeleteValueA(propkey, "HelpLink"); + RegDeleteKeyA(propkey, ""); + RegDeleteKeyA(localkey, ""); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(propkey); + RegCloseKey(localkey); + RegCloseKey(prodkey); + + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected \"apple\", got \"%s\"\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local user product key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected \"apple\", got \"%s\"\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegCreateKeyA(localkey, "InstallProperties", &propkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(propkey, "HelpLink", 0, REG_SZ, (LPBYTE)"link", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpLink value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "link"), "Expected \"link\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + RegDeleteValueA(propkey, "HelpLink"); + RegDeleteKeyA(propkey, ""); + RegDeleteKeyA(localkey, ""); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(propkey); + RegCloseKey(localkey); + RegCloseKey(prodkey); + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* classes product key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected \"apple\", got \"%s\"\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local user product key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected \"apple\", got \"%s\"\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegCreateKeyA(localkey, "InstallProperties", &propkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected \"apple\", got \"%s\"\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + RegDeleteKeyA(propkey, ""); + RegDeleteKeyA(localkey, ""); + RegCloseKey(propkey); + RegCloseKey(localkey); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, "S-1-5-18\\\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Local System product key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected \"apple\", got \"%s\"\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegCreateKeyA(localkey, "InstallProperties", &propkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(propkey, "HelpLink", 0, REG_SZ, (LPBYTE)"link", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpLink value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "link"), "Expected \"link\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "HelpLink", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpLink type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "DisplayName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_INSTALLEDPRODUCTNAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "name"), "Expected \"name\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "DisplayName", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayName type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_INSTALLEDPRODUCTNAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "DisplayVersion", 0, REG_SZ, (LPBYTE)"1.1.1", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayVersion value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_VERSIONSTRING, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "1.1.1"), "Expected \"1.1.1\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "DisplayVersion", 0, + REG_DWORD, (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayVersion type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_VERSIONSTRING, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "HelpTelephone", 0, REG_SZ, (LPBYTE)"tele", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpTelephone value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPTELEPHONE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "tele"), "Expected \"tele\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "HelpTelephone", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpTelephone type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_HELPTELEPHONE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallLocation", 0, REG_SZ, (LPBYTE)"loc", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallLocation value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_INSTALLLOCATION, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "loc"), "Expected \"loc\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallLocation", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallLocation type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_INSTALLLOCATION, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallSource", 0, REG_SZ, (LPBYTE)"source", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallSource value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_INSTALLSOURCE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "source"), "Expected \"source\", got \"%s\"\n", buf); + ok(sz == 6, "Expected 6, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallSource", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallSource type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_INSTALLSOURCE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallDate", 0, REG_SZ, (LPBYTE)"date", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallDate value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_INSTALLDATE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "date"), "Expected \"date\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallDate", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallDate type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_INSTALLDATE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "Publisher", 0, REG_SZ, (LPBYTE)"pub", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Publisher value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PUBLISHER, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "pub"), "Expected \"pub\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(propkey, "Publisher", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Publisher type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PUBLISHER, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "LocalPackage", 0, REG_SZ, (LPBYTE)"pack", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_LOCALPACKAGE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "pack"), "Expected \"pack\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "LocalPackage", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_LOCALPACKAGE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "UrlInfoAbout", 0, REG_SZ, (LPBYTE)"about", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* UrlInfoAbout value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_URLINFOABOUT, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "about"), "Expected \"about\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "UrlInfoAbout", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* UrlInfoAbout type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_URLINFOABOUT, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "UrlUpdateInfo", 0, REG_SZ, (LPBYTE)"info", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* UrlUpdateInfo value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_URLUPDATEINFO, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "info"), "Expected \"info\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "UrlUpdateInfo", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* UrlUpdateInfo type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_URLUPDATEINFO, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "VersionMinor", 0, REG_SZ, (LPBYTE)"1", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMinor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_VERSIONMINOR, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "1"), "Expected \"1\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + res = RegSetValueExA(propkey, "VersionMinor", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMinor type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_VERSIONMINOR, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "VersionMajor", 0, REG_SZ, (LPBYTE)"1", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMajor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_VERSIONMAJOR, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "1"), "Expected \"1\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + res = RegSetValueExA(propkey, "VersionMajor", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMajor type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_VERSIONMAJOR, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductID", 0, REG_SZ, (LPBYTE)"id", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductID value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PRODUCTID, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "id"), "Expected \"id\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductID", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductID type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PRODUCTID, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "RegCompany", 0, REG_SZ, (LPBYTE)"comp", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegCompany value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_REGCOMPANY, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "comp"), "Expected \"comp\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "RegCompany", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegCompany type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_REGCOMPANY, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "RegOwner", 0, REG_SZ, (LPBYTE)"own", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegOwner value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_REGOWNER, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "own"), "Expected \"own\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(propkey, "RegOwner", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegOwner type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_REGOWNER, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstanceType", 0, REG_SZ, (LPBYTE)"type", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstanceType value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_INSTANCETYPE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstanceType", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstanceType type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_INSTANCETYPE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(prodkey, "InstanceType", 0, REG_SZ, (LPBYTE)"type", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstanceType value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_INSTANCETYPE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "type"), "Expected \"type\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(prodkey, "InstanceType", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstanceType type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_INSTANCETYPE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "Transforms", 0, REG_SZ, (LPBYTE)"tforms", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Transforms value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_TRANSFORMS, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(propkey, "Transforms", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Transforms type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_TRANSFORMS, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Transforms", 0, REG_SZ, (LPBYTE)"tforms", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Transforms value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_TRANSFORMS, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "tforms"), "Expected \"tforms\", got \"%s\"\n", buf); + ok(sz == 6, "Expected 6, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Transforms", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Transforms type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_TRANSFORMS, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "Language", 0, REG_SZ, (LPBYTE)"lang", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Language value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_LANGUAGE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(propkey, "Language", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Language type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_LANGUAGE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Language", 0, REG_SZ, (LPBYTE)"lang", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Language value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_LANGUAGE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "lang"), "Expected \"lang\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Language", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Language type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_LANGUAGE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PRODUCTNAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductName", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductName type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PRODUCTNAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(prodkey, "ProductName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PRODUCTNAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "name"), "Expected \"name\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(prodkey, "ProductName", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductName type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PRODUCTNAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "Assignment", 0, REG_SZ, (LPBYTE)"at", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Assignment value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_ASSIGNMENTTYPE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(propkey, "Assignment", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Assignment type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_ASSIGNMENTTYPE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Assignment", 0, REG_SZ, (LPBYTE)"at", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Assignment value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_ASSIGNMENTTYPE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "at"), "Expected \"at\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Assignment", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Assignment type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_ASSIGNMENTTYPE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "PackageCode", 0, REG_SZ, (LPBYTE)"code", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageCode value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PACKAGECODE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(propkey, "PackageCode", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageCode type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PACKAGECODE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(prodkey, "PackageCode", 0, REG_SZ, (LPBYTE)"code", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageCode value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PACKAGECODE, buf, &sz); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(buf, "code"), "Expected \"code\", got \"%s\"\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "PackageCode", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageCode type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PACKAGECODE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(prodkey, "PackageCode", 0, REG_SZ, (LPBYTE)pack_squashed, 33); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageCode value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PACKAGECODE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, packcode), "Expected \"%s\", got \"%s\"\n", packcode, buf); + ok(sz == 38, "Expected 38, got %d\n", sz); + + res = RegSetValueExA(propkey, "Version", 0, REG_SZ, (LPBYTE)"ver", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Version value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_VERSION, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(propkey, "Version", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Version type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_VERSION, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Version", 0, REG_SZ, (LPBYTE)"ver", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Version value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_VERSION, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "ver"), "Expected \"ver\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Version", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Version type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_VERSION, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductIcon", 0, REG_SZ, (LPBYTE)"ico", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductIcon value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PRODUCTICON, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductIcon", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductIcon type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PRODUCTICON, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(prodkey, "ProductIcon", 0, REG_SZ, (LPBYTE)"ico", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductIcon value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PRODUCTICON, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "ico"), "Expected \"ico\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(prodkey, "ProductIcon", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductIcon type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PRODUCTICON, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegCreateKeyA(prodkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(source, "PackageName", 0, REG_SZ, (LPBYTE)"packname", 9); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PACKAGENAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "packname"), "Expected \"packname\", got \"%s\"\n", buf); + ok(sz == 8, "Expected 8, got %d\n", sz); + + res = RegSetValueExA(source, "PackageName", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageName type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_PACKAGENAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "AuthorizedLUAApp", 0, REG_SZ, (LPBYTE)"auth", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Authorized value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_AUTHORIZED_LUA_APP, buf, &sz); + if (r != ERROR_UNKNOWN_PROPERTY) + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + } + + res = RegSetValueExA(propkey, "AuthorizedLUAApp", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* AuthorizedLUAApp type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_AUTHORIZED_LUA_APP, buf, &sz); + if (r != ERROR_UNKNOWN_PROPERTY) + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + } + + res = RegSetValueExA(prodkey, "AuthorizedLUAApp", 0, REG_SZ, (LPBYTE)"auth", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Authorized value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_AUTHORIZED_LUA_APP, buf, &sz); + if (r != ERROR_UNKNOWN_PROPERTY) + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "auth"), "Expected \"auth\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + } + + res = RegSetValueExA(prodkey, "AuthorizedLUAApp", 0, REG_DWORD, + (const BYTE *)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* AuthorizedLUAApp type is REG_DWORD */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiGetProductInfoA(prodcode, INSTALLPROPERTY_AUTHORIZED_LUA_APP, buf, &sz); + if (r != ERROR_UNKNOWN_PROPERTY) + { + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "42"), "Expected \"42\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + } + + RegDeleteValueA(propkey, "HelpLink"); + RegDeleteValueA(propkey, "DisplayName"); + RegDeleteValueA(propkey, "DisplayVersion"); + RegDeleteValueA(propkey, "HelpTelephone"); + RegDeleteValueA(propkey, "InstallLocation"); + RegDeleteValueA(propkey, "InstallSource"); + RegDeleteValueA(propkey, "InstallDate"); + RegDeleteValueA(propkey, "Publisher"); + RegDeleteValueA(propkey, "LocalPackage"); + RegDeleteValueA(propkey, "UrlInfoAbout"); + RegDeleteValueA(propkey, "UrlUpdateInfo"); + RegDeleteValueA(propkey, "VersionMinor"); + RegDeleteValueA(propkey, "VersionMajor"); + RegDeleteValueA(propkey, "ProductID"); + RegDeleteValueA(propkey, "RegCompany"); + RegDeleteValueA(propkey, "RegOwner"); + RegDeleteValueA(propkey, "InstanceType"); + RegDeleteValueA(propkey, "Transforms"); + RegDeleteValueA(propkey, "Language"); + RegDeleteValueA(propkey, "ProductName"); + RegDeleteValueA(propkey, "Assignment"); + RegDeleteValueA(propkey, "PackageCode"); + RegDeleteValueA(propkey, "Version"); + RegDeleteValueA(propkey, "ProductIcon"); + RegDeleteValueA(propkey, "AuthorizedLUAApp"); + RegDeleteKeyA(propkey, ""); + RegDeleteKeyA(localkey, ""); + RegDeleteValueA(prodkey, "InstanceType"); + RegDeleteValueA(prodkey, "Transforms"); + RegDeleteValueA(prodkey, "Language"); + RegDeleteValueA(prodkey, "ProductName"); + RegDeleteValueA(prodkey, "Assignment"); + RegDeleteValueA(prodkey, "PackageCode"); + RegDeleteValueA(prodkey, "Version"); + RegDeleteValueA(prodkey, "ProductIcon"); + RegDeleteValueA(prodkey, "AuthorizedLUAApp"); + RegDeleteValueA(source, "PackageName"); + RegDeleteKeyA(source, ""); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(propkey); + RegCloseKey(localkey); + RegCloseKey(source); + RegCloseKey(prodkey); +} + +static void test_MsiGetProductInfoEx(void) +{ + UINT r; + LONG res; + HKEY propkey, userkey; + HKEY prodkey, localkey; + CHAR prodcode[MAX_PATH]; + CHAR prod_squashed[MAX_PATH]; + CHAR packcode[MAX_PATH]; + CHAR pack_squashed[MAX_PATH]; + CHAR buf[MAX_PATH]; + CHAR keypath[MAX_PATH]; + LPSTR usersid; + DWORD sz; + + if (!pMsiGetProductInfoExA) + { + skip("MsiGetProductInfoExA is not available\n"); + return; + } + + create_test_guid(prodcode, prod_squashed); + create_test_guid(packcode, pack_squashed); + get_user_sid(&usersid); + + /* NULL szProductCode */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* empty szProductCode */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* garbage szProductCode */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* guid without brackets */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA("6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D", usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* guid with brackets */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA("{6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D}", usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* szValue is non-NULL while pcchValue is NULL */ + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, NULL); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + + /* dwContext is out of range */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, 42, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* szProperty is NULL */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + NULL, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* szProperty is empty */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + "", buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* szProperty is not a valid property */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + "notvalid", buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* same length as guid, but random */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA("A938G02JF-2NF3N93-VN3-2NNF-3KGKALDNF93", usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + /* MSIINSTALLCONTEXT_USERUNMANAGED */ + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local user product key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegCreateKeyA(localkey, "InstallProperties", &propkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "LocalPackage", 0, REG_SZ, (LPBYTE)"local", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "5"), "Expected \"5\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + RegDeleteValueA(propkey, "LocalPackage"); + + /* LocalPackage value must exist */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "LocalPackage", 0, REG_SZ, (LPBYTE)"local", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage exists, but HelpLink does not exist */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(propkey, "HelpLink", 0, REG_SZ, (LPBYTE)"link", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpLink value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "link"), "Expected \"link\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "HelpTelephone", 0, REG_SZ, (LPBYTE)"phone", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpTelephone value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_HELPTELEPHONE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "phone"), "Expected \"phone\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + /* szValue and pcchValue are NULL */ + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_HELPTELEPHONE, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* pcchValue is exactly 5 */ + sz = 5; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_HELPTELEPHONE, buf, &sz); + ok(r == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 10, "Expected 10, got %d\n", sz); + + /* szValue is NULL, pcchValue is exactly 5 */ + sz = 5; + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_HELPTELEPHONE, NULL, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(sz == 10, "Expected 10, got %d\n", sz); + + /* szValue is NULL, pcchValue is MAX_PATH */ + sz = MAX_PATH; + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_HELPTELEPHONE, NULL, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(sz == 10, "Expected 10, got %d\n", sz); + + /* pcchValue is exactly 0 */ + sz = 0; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_HELPTELEPHONE, buf, &sz); + ok(r == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected \"apple\", got \"%s\"\n", buf); + ok(sz == 10, "Expected 10, got %d\n", sz); + + res = RegSetValueExA(propkey, "notvalid", 0, REG_SZ, (LPBYTE)"invalid", 8); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* szProperty is not a valid property */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + "notvalid", buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallDate", 0, REG_SZ, (LPBYTE)"date", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallDate value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_INSTALLDATE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "date"), "Expected \"date\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "DisplayName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_INSTALLEDPRODUCTNAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "name"), "Expected \"name\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallLocation", 0, REG_SZ, (LPBYTE)"loc", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallLocation value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_INSTALLLOCATION, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "loc"), "Expected \"loc\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallSource", 0, REG_SZ, (LPBYTE)"source", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallSource value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_INSTALLSOURCE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "source"), "Expected \"source\", got \"%s\"\n", buf); + ok(sz == 6, "Expected 6, got %d\n", sz); + + res = RegSetValueExA(propkey, "LocalPackage", 0, REG_SZ, (LPBYTE)"local", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "local"), "Expected \"local\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "Publisher", 0, REG_SZ, (LPBYTE)"pub", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Publisher value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PUBLISHER, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "pub"), "Expected \"pub\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(propkey, "URLInfoAbout", 0, REG_SZ, (LPBYTE)"about", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URLInfoAbout value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_URLINFOABOUT, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "about"), "Expected \"about\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "URLUpdateInfo", 0, REG_SZ, (LPBYTE)"update", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URLUpdateInfo value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_URLUPDATEINFO, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "update"), "Expected \"update\", got \"%s\"\n", buf); + ok(sz == 6, "Expected 6, got %d\n", sz); + + res = RegSetValueExA(propkey, "VersionMinor", 0, REG_SZ, (LPBYTE)"2", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMinor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_VERSIONMINOR, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "2"), "Expected \"2\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + res = RegSetValueExA(propkey, "VersionMajor", 0, REG_SZ, (LPBYTE)"3", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMajor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_VERSIONMAJOR, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "3"), "Expected \"3\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + res = RegSetValueExA(propkey, "DisplayVersion", 0, REG_SZ, (LPBYTE)"3.2.1", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayVersion value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_VERSIONSTRING, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "3.2.1"), "Expected \"3.2.1\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductID", 0, REG_SZ, (LPBYTE)"id", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductID value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTID, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "id"), "Expected \"id\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "RegCompany", 0, REG_SZ, (LPBYTE)"comp", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegCompany value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_REGCOMPANY, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "comp"), "Expected \"comp\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "RegOwner", 0, REG_SZ, (LPBYTE)"owner", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegOwner value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_REGOWNER, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "owner"), "Expected \"owner\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "Transforms", 0, REG_SZ, (LPBYTE)"trans", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Transforms value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_TRANSFORMS, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "Language", 0, REG_SZ, (LPBYTE)"lang", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Language value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LANGUAGE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTNAME, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "AssignmentType", 0, REG_SZ, (LPBYTE)"type", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* FIXME */ + + /* AssignmentType value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_ASSIGNMENTTYPE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "PackageCode", 0, REG_SZ, (LPBYTE)"code", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageCode value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PACKAGECODE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "Version", 0, REG_SZ, (LPBYTE)"ver", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Version value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_VERSION, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductIcon", 0, REG_SZ, (LPBYTE)"icon", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductIcon value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTICON, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "PackageName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PACKAGENAME, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "AuthorizedLUAApp", 0, REG_SZ, (LPBYTE)"auth", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* AuthorizedLUAApp value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_AUTHORIZED_LUA_APP, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + RegDeleteValueA(propkey, "AuthorizedLUAApp"); + RegDeleteValueA(propkey, "PackageName"); + RegDeleteValueA(propkey, "ProductIcon"); + RegDeleteValueA(propkey, "Version"); + RegDeleteValueA(propkey, "PackageCode"); + RegDeleteValueA(propkey, "AssignmentType"); + RegDeleteValueA(propkey, "ProductName"); + RegDeleteValueA(propkey, "Language"); + RegDeleteValueA(propkey, "Transforms"); + RegDeleteValueA(propkey, "RegOwner"); + RegDeleteValueA(propkey, "RegCompany"); + RegDeleteValueA(propkey, "ProductID"); + RegDeleteValueA(propkey, "DisplayVersion"); + RegDeleteValueA(propkey, "VersionMajor"); + RegDeleteValueA(propkey, "VersionMinor"); + RegDeleteValueA(propkey, "URLUpdateInfo"); + RegDeleteValueA(propkey, "URLInfoAbout"); + RegDeleteValueA(propkey, "Publisher"); + RegDeleteValueA(propkey, "LocalPackage"); + RegDeleteValueA(propkey, "InstallSource"); + RegDeleteValueA(propkey, "InstallLocation"); + RegDeleteValueA(propkey, "DisplayName"); + RegDeleteValueA(propkey, "InstallDate"); + RegDeleteValueA(propkey, "HelpTelephone"); + RegDeleteValueA(propkey, "HelpLink"); + RegDeleteValueA(propkey, "LocalPackage"); + RegDeleteKeyA(propkey, ""); + RegCloseKey(propkey); + RegDeleteKeyA(localkey, ""); + RegCloseKey(localkey); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "1"), "Expected \"1\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + res = RegSetValueExA(prodkey, "HelpLink", 0, REG_SZ, (LPBYTE)"link", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpLink value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "HelpTelephone", 0, REG_SZ, (LPBYTE)"phone", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpTelephone value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_HELPTELEPHONE, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "InstallDate", 0, REG_SZ, (LPBYTE)"date", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallDate value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_INSTALLDATE, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "DisplayName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_INSTALLEDPRODUCTNAME, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "InstallLocation", 0, REG_SZ, (LPBYTE)"loc", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallLocation value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_INSTALLLOCATION, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "InstallSource", 0, REG_SZ, (LPBYTE)"source", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallSource value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_INSTALLSOURCE, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "LocalPackage", 0, REG_SZ, (LPBYTE)"local", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Publisher", 0, REG_SZ, (LPBYTE)"pub", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Publisher value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PUBLISHER, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "URLInfoAbout", 0, REG_SZ, (LPBYTE)"about", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URLInfoAbout value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_URLINFOABOUT, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "URLUpdateInfo", 0, REG_SZ, (LPBYTE)"update", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URLUpdateInfo value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_URLUPDATEINFO, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "VersionMinor", 0, REG_SZ, (LPBYTE)"2", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMinor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_VERSIONMINOR, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "VersionMajor", 0, REG_SZ, (LPBYTE)"3", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMajor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_VERSIONMAJOR, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "DisplayVersion", 0, REG_SZ, (LPBYTE)"3.2.1", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayVersion value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_VERSIONSTRING, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "ProductID", 0, REG_SZ, (LPBYTE)"id", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductID value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTID, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "RegCompany", 0, REG_SZ, (LPBYTE)"comp", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegCompany value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_REGCOMPANY, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "RegOwner", 0, REG_SZ, (LPBYTE)"owner", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegOwner value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_REGOWNER, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Transforms", 0, REG_SZ, (LPBYTE)"trans", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Transforms value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_TRANSFORMS, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "trans"), "Expected \"trans\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Language", 0, REG_SZ, (LPBYTE)"lang", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Language value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_LANGUAGE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "lang"), "Expected \"lang\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(prodkey, "ProductName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTNAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "name"), "Expected \"name\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(prodkey, "AssignmentType", 0, REG_SZ, (LPBYTE)"type", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* FIXME */ + + /* AssignmentType value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_ASSIGNMENTTYPE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(prodkey, "PackageCode", 0, REG_SZ, (LPBYTE)"code", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* FIXME */ + + /* PackageCode value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PACKAGECODE, buf, &sz); + todo_wine + { + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + } + + res = RegSetValueExA(prodkey, "Version", 0, REG_SZ, (LPBYTE)"ver", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Version value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_VERSION, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "ver"), "Expected \"ver\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(prodkey, "ProductIcon", 0, REG_SZ, (LPBYTE)"icon", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductIcon value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PRODUCTICON, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "icon"), "Expected \"icon\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(prodkey, "PackageName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_PACKAGENAME, buf, &sz); + todo_wine + { + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + } + + res = RegSetValueExA(prodkey, "AuthorizedLUAApp", 0, REG_SZ, (LPBYTE)"auth", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* AuthorizedLUAApp value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + INSTALLPROPERTY_AUTHORIZED_LUA_APP, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "auth"), "Expected \"auth\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + RegDeleteValueA(prodkey, "AuthorizedLUAApp"); + RegDeleteValueA(prodkey, "PackageName"); + RegDeleteValueA(prodkey, "ProductIcon"); + RegDeleteValueA(prodkey, "Version"); + RegDeleteValueA(prodkey, "PackageCode"); + RegDeleteValueA(prodkey, "AssignmentType"); + RegDeleteValueA(prodkey, "ProductName"); + RegDeleteValueA(prodkey, "Language"); + RegDeleteValueA(prodkey, "Transforms"); + RegDeleteValueA(prodkey, "RegOwner"); + RegDeleteValueA(prodkey, "RegCompany"); + RegDeleteValueA(prodkey, "ProductID"); + RegDeleteValueA(prodkey, "DisplayVersion"); + RegDeleteValueA(prodkey, "VersionMajor"); + RegDeleteValueA(prodkey, "VersionMinor"); + RegDeleteValueA(prodkey, "URLUpdateInfo"); + RegDeleteValueA(prodkey, "URLInfoAbout"); + RegDeleteValueA(prodkey, "Publisher"); + RegDeleteValueA(prodkey, "LocalPackage"); + RegDeleteValueA(prodkey, "InstallSource"); + RegDeleteValueA(prodkey, "InstallLocation"); + RegDeleteValueA(prodkey, "DisplayName"); + RegDeleteValueA(prodkey, "InstallDate"); + RegDeleteValueA(prodkey, "HelpTelephone"); + RegDeleteValueA(prodkey, "HelpLink"); + RegDeleteValueA(prodkey, "LocalPackage"); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + /* MSIINSTALLCONTEXT_USERMANAGED */ + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local user product key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegCreateKeyA(localkey, "InstallProperties", &propkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "ManagedLocalPackage", 0, REG_SZ, (LPBYTE)"local", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ManagedLocalPackage value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "5"), "Expected \"5\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + res = RegSetValueExA(propkey, "HelpLink", 0, REG_SZ, (LPBYTE)"link", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpLink value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "link"), "Expected \"link\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "HelpTelephone", 0, REG_SZ, (LPBYTE)"phone", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpTelephone value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_HELPTELEPHONE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "phone"), "Expected \"phone\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallDate", 0, REG_SZ, (LPBYTE)"date", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallDate value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_INSTALLDATE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "date"), "Expected \"date\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "DisplayName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_INSTALLEDPRODUCTNAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "name"), "Expected \"name\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallLocation", 0, REG_SZ, (LPBYTE)"loc", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallLocation value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_INSTALLLOCATION, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "loc"), "Expected \"loc\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallSource", 0, REG_SZ, (LPBYTE)"source", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallSource value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_INSTALLSOURCE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "source"), "Expected \"source\", got \"%s\"\n", buf); + ok(sz == 6, "Expected 6, got %d\n", sz); + + res = RegSetValueExA(propkey, "LocalPackage", 0, REG_SZ, (LPBYTE)"local", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "local"), "Expected \"local\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "Publisher", 0, REG_SZ, (LPBYTE)"pub", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Publisher value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PUBLISHER, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "pub"), "Expected \"pub\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(propkey, "URLInfoAbout", 0, REG_SZ, (LPBYTE)"about", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URLInfoAbout value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_URLINFOABOUT, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "about"), "Expected \"about\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "URLUpdateInfo", 0, REG_SZ, (LPBYTE)"update", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URLUpdateInfo value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_URLUPDATEINFO, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "update"), "Expected \"update\", got \"%s\"\n", buf); + ok(sz == 6, "Expected 6, got %d\n", sz); + + res = RegSetValueExA(propkey, "VersionMinor", 0, REG_SZ, (LPBYTE)"2", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMinor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_VERSIONMINOR, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "2"), "Expected \"2\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + res = RegSetValueExA(propkey, "VersionMajor", 0, REG_SZ, (LPBYTE)"3", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMajor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_VERSIONMAJOR, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "3"), "Expected \"3\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + res = RegSetValueExA(propkey, "DisplayVersion", 0, REG_SZ, (LPBYTE)"3.2.1", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayVersion value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_VERSIONSTRING, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "3.2.1"), "Expected \"3.2.1\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductID", 0, REG_SZ, (LPBYTE)"id", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductID value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PRODUCTID, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "id"), "Expected \"id\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "RegCompany", 0, REG_SZ, (LPBYTE)"comp", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegCompany value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_REGCOMPANY, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "comp"), "Expected \"comp\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "RegOwner", 0, REG_SZ, (LPBYTE)"owner", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegOwner value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_REGOWNER, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "owner"), "Expected \"owner\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "Transforms", 0, REG_SZ, (LPBYTE)"trans", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Transforms value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_TRANSFORMS, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "Language", 0, REG_SZ, (LPBYTE)"lang", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Language value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LANGUAGE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PRODUCTNAME, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "AssignmentType", 0, REG_SZ, (LPBYTE)"type", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* FIXME */ + + /* AssignmentType value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_ASSIGNMENTTYPE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "PackageCode", 0, REG_SZ, (LPBYTE)"code", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageCode value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PACKAGECODE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "Version", 0, REG_SZ, (LPBYTE)"ver", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Version value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_VERSION, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductIcon", 0, REG_SZ, (LPBYTE)"icon", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductIcon value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PRODUCTICON, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "PackageName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PACKAGENAME, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "AuthorizedLUAApp", 0, REG_SZ, (LPBYTE)"auth", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* AuthorizedLUAApp value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_AUTHORIZED_LUA_APP, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + RegDeleteValueA(propkey, "AuthorizedLUAApp"); + RegDeleteValueA(propkey, "PackageName"); + RegDeleteValueA(propkey, "ProductIcon"); + RegDeleteValueA(propkey, "Version"); + RegDeleteValueA(propkey, "PackageCode"); + RegDeleteValueA(propkey, "AssignmentType"); + RegDeleteValueA(propkey, "ProductName"); + RegDeleteValueA(propkey, "Language"); + RegDeleteValueA(propkey, "Transforms"); + RegDeleteValueA(propkey, "RegOwner"); + RegDeleteValueA(propkey, "RegCompany"); + RegDeleteValueA(propkey, "ProductID"); + RegDeleteValueA(propkey, "DisplayVersion"); + RegDeleteValueA(propkey, "VersionMajor"); + RegDeleteValueA(propkey, "VersionMinor"); + RegDeleteValueA(propkey, "URLUpdateInfo"); + RegDeleteValueA(propkey, "URLInfoAbout"); + RegDeleteValueA(propkey, "Publisher"); + RegDeleteValueA(propkey, "LocalPackage"); + RegDeleteValueA(propkey, "InstallSource"); + RegDeleteValueA(propkey, "InstallLocation"); + RegDeleteValueA(propkey, "DisplayName"); + RegDeleteValueA(propkey, "InstallDate"); + RegDeleteValueA(propkey, "HelpTelephone"); + RegDeleteValueA(propkey, "HelpLink"); + RegDeleteValueA(propkey, "ManagedLocalPackage"); + RegDeleteKeyA(propkey, ""); + RegCloseKey(propkey); + RegDeleteKeyA(localkey, ""); + RegCloseKey(localkey); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "1"), "Expected \"1\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* current user product key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "HelpLink", 0, REG_SZ, (LPBYTE)"link", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpLink value exists, user product key does not exist */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(userkey, "HelpLink", 0, REG_SZ, (LPBYTE)"link", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpLink value exists, user product key does exist */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "HelpTelephone", 0, REG_SZ, (LPBYTE)"phone", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpTelephone value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_HELPTELEPHONE, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "InstallDate", 0, REG_SZ, (LPBYTE)"date", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallDate value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_INSTALLDATE, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "DisplayName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_INSTALLEDPRODUCTNAME, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "InstallLocation", 0, REG_SZ, (LPBYTE)"loc", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallLocation value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_INSTALLLOCATION, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "InstallSource", 0, REG_SZ, (LPBYTE)"source", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallSource value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_INSTALLSOURCE, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "LocalPackage", 0, REG_SZ, (LPBYTE)"local", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LOCALPACKAGE, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "Publisher", 0, REG_SZ, (LPBYTE)"pub", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Publisher value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PUBLISHER, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "URLInfoAbout", 0, REG_SZ, (LPBYTE)"about", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URLInfoAbout value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_URLINFOABOUT, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "URLUpdateInfo", 0, REG_SZ, (LPBYTE)"update", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URLUpdateInfo value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_URLUPDATEINFO, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "VersionMinor", 0, REG_SZ, (LPBYTE)"2", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMinor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_VERSIONMINOR, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "VersionMajor", 0, REG_SZ, (LPBYTE)"3", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMajor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_VERSIONMAJOR, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "DisplayVersion", 0, REG_SZ, (LPBYTE)"3.2.1", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayVersion value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_VERSIONSTRING, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "ProductID", 0, REG_SZ, (LPBYTE)"id", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductID value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PRODUCTID, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "RegCompany", 0, REG_SZ, (LPBYTE)"comp", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegCompany value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_REGCOMPANY, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "RegOwner", 0, REG_SZ, (LPBYTE)"owner", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegOwner value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_REGOWNER, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(userkey, "Transforms", 0, REG_SZ, (LPBYTE)"trans", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Transforms value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_TRANSFORMS, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "trans"), "Expected \"trans\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(userkey, "Language", 0, REG_SZ, (LPBYTE)"lang", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Language value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_LANGUAGE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "lang"), "Expected \"lang\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(userkey, "ProductName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PRODUCTNAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "name"), "Expected \"name\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(userkey, "AssignmentType", 0, REG_SZ, (LPBYTE)"type", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* FIXME */ + + /* AssignmentType value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_ASSIGNMENTTYPE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(userkey, "PackageCode", 0, REG_SZ, (LPBYTE)"code", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* FIXME */ + + /* PackageCode value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PACKAGECODE, buf, &sz); + todo_wine + { + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + } + + res = RegSetValueExA(userkey, "Version", 0, REG_SZ, (LPBYTE)"ver", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Version value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_VERSION, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "ver"), "Expected \"ver\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(userkey, "ProductIcon", 0, REG_SZ, (LPBYTE)"icon", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductIcon value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PRODUCTICON, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "icon"), "Expected \"icon\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(userkey, "PackageName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_PACKAGENAME, buf, &sz); + todo_wine + { + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + } + + res = RegSetValueExA(userkey, "AuthorizedLUAApp", 0, REG_SZ, (LPBYTE)"auth", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* AuthorizedLUAApp value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + INSTALLPROPERTY_AUTHORIZED_LUA_APP, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "auth"), "Expected \"auth\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + RegDeleteValueA(userkey, "AuthorizedLUAApp"); + RegDeleteValueA(userkey, "PackageName"); + RegDeleteValueA(userkey, "ProductIcon"); + RegDeleteValueA(userkey, "Version"); + RegDeleteValueA(userkey, "PackageCode"); + RegDeleteValueA(userkey, "AssignmentType"); + RegDeleteValueA(userkey, "ProductName"); + RegDeleteValueA(userkey, "Language"); + RegDeleteValueA(userkey, "Transforms"); + RegDeleteValueA(userkey, "RegOwner"); + RegDeleteValueA(userkey, "RegCompany"); + RegDeleteValueA(userkey, "ProductID"); + RegDeleteValueA(userkey, "DisplayVersion"); + RegDeleteValueA(userkey, "VersionMajor"); + RegDeleteValueA(userkey, "VersionMinor"); + RegDeleteValueA(userkey, "URLUpdateInfo"); + RegDeleteValueA(userkey, "URLInfoAbout"); + RegDeleteValueA(userkey, "Publisher"); + RegDeleteValueA(userkey, "LocalPackage"); + RegDeleteValueA(userkey, "InstallSource"); + RegDeleteValueA(userkey, "InstallLocation"); + RegDeleteValueA(userkey, "DisplayName"); + RegDeleteValueA(userkey, "InstallDate"); + RegDeleteValueA(userkey, "HelpTelephone"); + RegDeleteValueA(userkey, "HelpLink"); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + /* MSIINSTALLCONTEXT_MACHINE */ + + /* szUserSid is non-NULL */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, usersid, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\S-1-5-18\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local system product key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegCreateKeyA(localkey, "InstallProperties", &propkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "LocalPackage", 0, REG_SZ, (LPBYTE)"local", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "5"), "Expected \"5\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + res = RegSetValueExA(propkey, "HelpLink", 0, REG_SZ, (LPBYTE)"link", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpLink value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "link"), "Expected \"link\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "HelpTelephone", 0, REG_SZ, (LPBYTE)"phone", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpTelephone value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_HELPTELEPHONE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "phone"), "Expected \"phone\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallDate", 0, REG_SZ, (LPBYTE)"date", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallDate value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_INSTALLDATE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "date"), "Expected \"date\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "DisplayName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_INSTALLEDPRODUCTNAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "name"), "Expected \"name\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallLocation", 0, REG_SZ, (LPBYTE)"loc", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallLocation value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_INSTALLLOCATION, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "loc"), "Expected \"loc\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(propkey, "InstallSource", 0, REG_SZ, (LPBYTE)"source", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallSource value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_INSTALLSOURCE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "source"), "Expected \"source\", got \"%s\"\n", buf); + ok(sz == 6, "Expected 6, got %d\n", sz); + + res = RegSetValueExA(propkey, "LocalPackage", 0, REG_SZ, (LPBYTE)"local", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "local"), "Expected \"local\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "Publisher", 0, REG_SZ, (LPBYTE)"pub", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Publisher value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PUBLISHER, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "pub"), "Expected \"pub\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(propkey, "URLInfoAbout", 0, REG_SZ, (LPBYTE)"about", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URLInfoAbout value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_URLINFOABOUT, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "about"), "Expected \"about\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "URLUpdateInfo", 0, REG_SZ, (LPBYTE)"update", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URLUpdateInfo value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_URLUPDATEINFO, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "update"), "Expected \"update\", got \"%s\"\n", buf); + ok(sz == 6, "Expected 6, got %d\n", sz); + + res = RegSetValueExA(propkey, "VersionMinor", 0, REG_SZ, (LPBYTE)"2", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMinor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_VERSIONMINOR, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "2"), "Expected \"2\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + res = RegSetValueExA(propkey, "VersionMajor", 0, REG_SZ, (LPBYTE)"3", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMajor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_VERSIONMAJOR, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "3"), "Expected \"3\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + res = RegSetValueExA(propkey, "DisplayVersion", 0, REG_SZ, (LPBYTE)"3.2.1", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayVersion value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_VERSIONSTRING, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "3.2.1"), "Expected \"3.2.1\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductID", 0, REG_SZ, (LPBYTE)"id", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductID value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PRODUCTID, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "id"), "Expected \"id\", got \"%s\"\n", buf); + ok(sz == 2, "Expected 2, got %d\n", sz); + + res = RegSetValueExA(propkey, "RegCompany", 0, REG_SZ, (LPBYTE)"comp", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegCompany value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_REGCOMPANY, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "comp"), "Expected \"comp\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(propkey, "RegOwner", 0, REG_SZ, (LPBYTE)"owner", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegOwner value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_REGOWNER, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "owner"), "Expected \"owner\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(propkey, "Transforms", 0, REG_SZ, (LPBYTE)"trans", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Transforms value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_TRANSFORMS, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "Language", 0, REG_SZ, (LPBYTE)"lang", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Language value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LANGUAGE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PRODUCTNAME, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "AssignmentType", 0, REG_SZ, (LPBYTE)"type", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* FIXME */ + + /* AssignmentType value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_ASSIGNMENTTYPE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "PackageCode", 0, REG_SZ, (LPBYTE)"code", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageCode value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PACKAGECODE, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "Version", 0, REG_SZ, (LPBYTE)"ver", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Version value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_VERSION, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "ProductIcon", 0, REG_SZ, (LPBYTE)"icon", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductIcon value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PRODUCTICON, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "PackageName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PACKAGENAME, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(propkey, "AuthorizedLUAApp", 0, REG_SZ, (LPBYTE)"auth", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* AuthorizedLUAApp value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_AUTHORIZED_LUA_APP, buf, &sz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + RegDeleteValueA(propkey, "AuthorizedLUAApp"); + RegDeleteValueA(propkey, "PackageName"); + RegDeleteValueA(propkey, "ProductIcon"); + RegDeleteValueA(propkey, "Version"); + RegDeleteValueA(propkey, "PackageCode"); + RegDeleteValueA(propkey, "AssignmentType"); + RegDeleteValueA(propkey, "ProductName"); + RegDeleteValueA(propkey, "Language"); + RegDeleteValueA(propkey, "Transforms"); + RegDeleteValueA(propkey, "RegOwner"); + RegDeleteValueA(propkey, "RegCompany"); + RegDeleteValueA(propkey, "ProductID"); + RegDeleteValueA(propkey, "DisplayVersion"); + RegDeleteValueA(propkey, "VersionMajor"); + RegDeleteValueA(propkey, "VersionMinor"); + RegDeleteValueA(propkey, "URLUpdateInfo"); + RegDeleteValueA(propkey, "URLInfoAbout"); + RegDeleteValueA(propkey, "Publisher"); + RegDeleteValueA(propkey, "LocalPackage"); + RegDeleteValueA(propkey, "InstallSource"); + RegDeleteValueA(propkey, "InstallLocation"); + RegDeleteValueA(propkey, "DisplayName"); + RegDeleteValueA(propkey, "InstallDate"); + RegDeleteValueA(propkey, "HelpTelephone"); + RegDeleteValueA(propkey, "HelpLink"); + RegDeleteValueA(propkey, "LocalPackage"); + RegDeleteKeyA(propkey, ""); + RegCloseKey(propkey); + RegDeleteKeyA(localkey, ""); + RegCloseKey(localkey); + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* local classes product key exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PRODUCTSTATE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "1"), "Expected \"1\", got \"%s\"\n", buf); + ok(sz == 1, "Expected 1, got %d\n", sz); + + res = RegSetValueExA(prodkey, "HelpLink", 0, REG_SZ, (LPBYTE)"link", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpLink value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_HELPLINK, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "HelpTelephone", 0, REG_SZ, (LPBYTE)"phone", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* HelpTelephone value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_HELPTELEPHONE, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "InstallDate", 0, REG_SZ, (LPBYTE)"date", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallDate value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_INSTALLDATE, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "DisplayName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_INSTALLEDPRODUCTNAME, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "InstallLocation", 0, REG_SZ, (LPBYTE)"loc", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallLocation value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_INSTALLLOCATION, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "InstallSource", 0, REG_SZ, (LPBYTE)"source", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallSource value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_INSTALLSOURCE, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "LocalPackage", 0, REG_SZ, (LPBYTE)"local", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LocalPackage value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LOCALPACKAGE, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Publisher", 0, REG_SZ, (LPBYTE)"pub", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Publisher value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PUBLISHER, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "URLInfoAbout", 0, REG_SZ, (LPBYTE)"about", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URLInfoAbout value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_URLINFOABOUT, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "URLUpdateInfo", 0, REG_SZ, (LPBYTE)"update", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URLUpdateInfo value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_URLUPDATEINFO, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "VersionMinor", 0, REG_SZ, (LPBYTE)"2", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMinor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_VERSIONMINOR, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "VersionMajor", 0, REG_SZ, (LPBYTE)"3", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* VersionMajor value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_VERSIONMAJOR, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "DisplayVersion", 0, REG_SZ, (LPBYTE)"3.2.1", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* DisplayVersion value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_VERSIONSTRING, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "ProductID", 0, REG_SZ, (LPBYTE)"id", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductID value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PRODUCTID, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "RegCompany", 0, REG_SZ, (LPBYTE)"comp", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegCompany value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_REGCOMPANY, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "RegOwner", 0, REG_SZ, (LPBYTE)"owner", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegOwner value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_REGOWNER, buf, &sz); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Transforms", 0, REG_SZ, (LPBYTE)"trans", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Transforms value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_TRANSFORMS, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "trans"), "Expected \"trans\", got \"%s\"\n", buf); + ok(sz == 5, "Expected 5, got %d\n", sz); + + res = RegSetValueExA(prodkey, "Language", 0, REG_SZ, (LPBYTE)"lang", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Language value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_LANGUAGE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "lang"), "Expected \"lang\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(prodkey, "ProductName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PRODUCTNAME, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "name"), "Expected \"name\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(prodkey, "AssignmentType", 0, REG_SZ, (LPBYTE)"type", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* FIXME */ + + /* AssignmentType value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_ASSIGNMENTTYPE, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + res = RegSetValueExA(prodkey, "PackageCode", 0, REG_SZ, (LPBYTE)"code", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* FIXME */ + + /* PackageCode value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PACKAGECODE, buf, &sz); + todo_wine + { + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + } + + res = RegSetValueExA(prodkey, "Version", 0, REG_SZ, (LPBYTE)"ver", 4); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Version value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_VERSION, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "ver"), "Expected \"ver\", got \"%s\"\n", buf); + ok(sz == 3, "Expected 3, got %d\n", sz); + + res = RegSetValueExA(prodkey, "ProductIcon", 0, REG_SZ, (LPBYTE)"icon", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductIcon value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PRODUCTICON, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "icon"), "Expected \"icon\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + res = RegSetValueExA(prodkey, "PackageName", 0, REG_SZ, (LPBYTE)"name", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* PackageName value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_PACKAGENAME, buf, &sz); + todo_wine + { + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + ok(sz == MAX_PATH, "Expected MAX_PATH, got %d\n", sz); + } + + res = RegSetValueExA(prodkey, "AuthorizedLUAApp", 0, REG_SZ, (LPBYTE)"auth", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* AuthorizedLUAApp value exists */ + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = pMsiGetProductInfoExA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + INSTALLPROPERTY_AUTHORIZED_LUA_APP, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, "auth"), "Expected \"auth\", got \"%s\"\n", buf); + ok(sz == 4, "Expected 4, got %d\n", sz); + + RegDeleteValueA(prodkey, "AuthorizedLUAApp"); + RegDeleteValueA(prodkey, "PackageName"); + RegDeleteValueA(prodkey, "ProductIcon"); + RegDeleteValueA(prodkey, "Version"); + RegDeleteValueA(prodkey, "PackageCode"); + RegDeleteValueA(prodkey, "AssignmentType"); + RegDeleteValueA(prodkey, "ProductName"); + RegDeleteValueA(prodkey, "Language"); + RegDeleteValueA(prodkey, "Transforms"); + RegDeleteValueA(prodkey, "RegOwner"); + RegDeleteValueA(prodkey, "RegCompany"); + RegDeleteValueA(prodkey, "ProductID"); + RegDeleteValueA(prodkey, "DisplayVersion"); + RegDeleteValueA(prodkey, "VersionMajor"); + RegDeleteValueA(prodkey, "VersionMinor"); + RegDeleteValueA(prodkey, "URLUpdateInfo"); + RegDeleteValueA(prodkey, "URLInfoAbout"); + RegDeleteValueA(prodkey, "Publisher"); + RegDeleteValueA(prodkey, "LocalPackage"); + RegDeleteValueA(prodkey, "InstallSource"); + RegDeleteValueA(prodkey, "InstallLocation"); + RegDeleteValueA(prodkey, "DisplayName"); + RegDeleteValueA(prodkey, "InstallDate"); + RegDeleteValueA(prodkey, "HelpTelephone"); + RegDeleteValueA(prodkey, "HelpLink"); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); +} + START_TEST(msi) { init_functionpointers(); @@ -2062,6 +6060,8 @@ START_TEST(msi) test_MsiGetComponentPath(); test_MsiGetProductCode(); test_MsiEnumClients(); + test_MsiGetProductInfo(); + test_MsiGetProductInfoEx(); } test_MsiGetFileVersion(); diff --git a/rostests/winetests/msi/msi.rbuild b/rostests/winetests/msi/msi.rbuild index 545c8e3e842..677dfa0055b 100644 --- a/rostests/winetests/msi/msi.rbuild +++ b/rostests/winetests/msi/msi.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/msi/package.c b/rostests/winetests/msi/package.c index dc0e31ec41c..232b75e9cfb 100644 --- a/rostests/winetests/msi/package.c +++ b/rostests/winetests/msi/package.c @@ -922,10 +922,12 @@ static void test_settargetpath(void) sprintf( tempdir, "%s\\subdir", buffer ); r = MsiSetTargetPath( hpkg, "TARGETDIR", buffer ); - ok( r == ERROR_SUCCESS, "MsiSetTargetPath on file returned %d\n", r ); + ok( r == ERROR_SUCCESS || r == ERROR_DIRECTORY, + "MsiSetTargetPath on file returned %d\n", r ); r = MsiSetTargetPath( hpkg, "TARGETDIR", tempdir ); - ok( r == ERROR_SUCCESS, "MsiSetTargetPath on 'subdir' of file returned %d\n", r ); + ok( r == ERROR_SUCCESS || r == ERROR_DIRECTORY, + "MsiSetTargetPath on 'subdir' of file returned %d\n", r ); DeleteFile( buffer ); @@ -986,6 +988,9 @@ static void test_condition(void) r = MsiEvaluateCondition(hpkg, "0"); ok( r == MSICONDITION_FALSE, "wrong return val\n"); + r = MsiEvaluateCondition(hpkg, "-1"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + r = MsiEvaluateCondition(hpkg, "0 = 0"); ok( r == MSICONDITION_TRUE, "wrong return val\n"); @@ -1622,6 +1627,10 @@ static void test_condition(void) r = MsiEvaluateCondition(hpkg, "X !=\"\" and (X =\"5.0\" or X =\"5.1\" or X =\"6.0\")"); ok( r == MSICONDITION_ERROR, "wrong return val (%d)\n", r); + /* feature doesn't exist */ + r = MsiEvaluateCondition(hpkg, "&nofeature"); + ok( r == MSICONDITION_FALSE, "wrong return val (%d)\n", r); + MsiCloseHandle( hpkg ); DeleteFile(msifile); } @@ -4697,7 +4706,8 @@ static void test_installprops(void) CHAR path[MAX_PATH]; CHAR buf[MAX_PATH]; DWORD size, type; - HKEY hkey; + LANGID langid; + HKEY hkey1, hkey2; UINT r; GetCurrentDirectory(MAX_PATH, path); @@ -4717,25 +4727,46 @@ static void test_installprops(void) ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); ok( !lstrcmp(buf, path), "Expected %s, got %s\n", path, buf); - RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hkey); + RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\MS Setup (ACME)\\User Info", &hkey1); + + RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hkey2); size = MAX_PATH; type = REG_SZ; - RegQueryValueEx(hkey, "RegisteredOwner", NULL, &type, (LPBYTE)path, &size); + *path = '\0'; + if (RegQueryValueEx(hkey1, "DefName", NULL, &type, (LPBYTE)path, &size) != ERROR_SUCCESS) + { + size = MAX_PATH; + type = REG_SZ; + RegQueryValueEx(hkey2, "RegisteredOwner", NULL, &type, (LPBYTE)path, &size); + } - size = MAX_PATH; - r = MsiGetProperty(hpkg, "USERNAME", buf, &size); - ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); - ok( !lstrcmp(buf, path), "Expected %s, got %s\n", path, buf); + /* win9x doesn't set this */ + if (*path) + { + size = MAX_PATH; + r = MsiGetProperty(hpkg, "USERNAME", buf, &size); + ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); + ok( !lstrcmp(buf, path), "Expected %s, got %s\n", path, buf); + } size = MAX_PATH; type = REG_SZ; - RegQueryValueEx(hkey, "RegisteredOrganization", NULL, &type, (LPBYTE)path, &size); + *path = '\0'; + if (RegQueryValueEx(hkey1, "DefCompany", NULL, &type, (LPBYTE)path, &size) != ERROR_SUCCESS) + { + size = MAX_PATH; + type = REG_SZ; + RegQueryValueEx(hkey2, "RegisteredOrganization", NULL, &type, (LPBYTE)path, &size); + } - size = MAX_PATH; - r = MsiGetProperty(hpkg, "COMPANYNAME", buf, &size); - ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); - ok( !lstrcmp(buf, path), "Expected %s, got %s\n", path, buf); + if (*path) + { + size = MAX_PATH; + r = MsiGetProperty(hpkg, "COMPANYNAME", buf, &size); + ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); + ok( !lstrcmp(buf, path), "Expected %s, got %s\n", path, buf); + } size = MAX_PATH; r = MsiGetProperty(hpkg, "VersionDatabase", buf, &size); @@ -4762,7 +4793,16 @@ static void test_installprops(void) ok( r == ERROR_SUCCESS, "failed to get property: %d\n", r); trace("PackageCode = %s\n", buf); - CloseHandle(hkey); + langid = GetUserDefaultLangID(); + sprintf(path, "%d", langid); + + size = MAX_PATH; + r = MsiGetProperty(hpkg, "UserLanguageID", buf, &size); + ok( r == ERROR_SUCCESS, "Expected ERROR_SUCCESS< got %d\n", r); + ok( !lstrcmpA(buf, path), "Expected \"%s\", got \"%s\"\n", path, buf); + + CloseHandle(hkey1); + CloseHandle(hkey2); MsiCloseHandle(hpkg); DeleteFile(msifile); } @@ -5294,7 +5334,8 @@ static void test_complocator(void) lstrcpyA(expected, CURR_DIR); lstrcatA(expected, "\\abelisaurus"); - ok(!lstrcmpA(prop, expected), "Expected %s, got %s\n", expected, prop); + ok(!lstrcmpA(prop, expected) || !lstrcmpA(prop, ""), + "Expected %s or empty string, got %s\n", expected, prop); size = MAX_PATH; r = MsiGetPropertyA(hpkg, "BACTROSAURUS", prop, &size); @@ -5317,7 +5358,8 @@ static void test_complocator(void) lstrcpyA(expected, CURR_DIR); lstrcatA(expected, "\\"); - ok(!lstrcmpA(prop, expected), "Expected %s, got %s\n", expected, prop); + ok(!lstrcmpA(prop, expected) || !lstrcmpA(prop, ""), + "Expected %s or empty string, got %s\n", expected, prop); size = MAX_PATH; r = MsiGetPropertyA(hpkg, "FALCARIUS", prop, &size); @@ -5360,7 +5402,8 @@ static void test_complocator(void) lstrcpyA(expected, CURR_DIR); lstrcatA(expected, "\\"); - ok(!lstrcmpA(prop, expected), "Expected %s, got %s\n", expected, prop); + ok(!lstrcmpA(prop, expected) || !lstrcmpA(prop, ""), + "Expected %s or empty string, got %s\n", expected, prop); size = MAX_PATH; r = MsiGetPropertyA(hpkg, "NEOSODON", prop, &size); @@ -5368,7 +5411,8 @@ static void test_complocator(void) lstrcpyA(expected, CURR_DIR); lstrcatA(expected, "\\neosodon\\"); - ok(!lstrcmpA(prop, expected), "Expected %s, got %s\n", expected, prop); + ok(!lstrcmpA(prop, expected) || !lstrcmpA(prop, ""), + "Expected %s or empty string, got %s\n", expected, prop); size = MAX_PATH; r = MsiGetPropertyA(hpkg, "OLOROTITAN", prop, &size); diff --git a/rostests/winetests/msi/record.c b/rostests/winetests/msi/record.c index 1f72d128617..471fc9ce372 100644 --- a/rostests/winetests/msi/record.c +++ b/rostests/winetests/msi/record.c @@ -351,7 +351,35 @@ static void test_msirecord(void) DeleteFile(filename); /* Delete it for sure, when everything else is closed. */ } +static void test_MsiRecordGetString(void) +{ + MSIHANDLE rec; + CHAR buf[MAX_PATH]; + DWORD sz; + UINT r; + + rec = MsiCreateRecord(2); + ok(rec != 0, "Expected a valid handle\n"); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 1, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + sz = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordGetString(rec, 10, buf, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(sz == 0, "Expected 0, got %d\n", sz); + + MsiCloseHandle(rec); +} + START_TEST(record) { test_msirecord(); + test_MsiRecordGetString(); } diff --git a/rostests/winetests/msi/source.c b/rostests/winetests/msi/source.c index 7407f5b8748..aef15ba782f 100644 --- a/rostests/winetests/msi/source.c +++ b/rostests/winetests/msi/source.c @@ -31,10 +31,21 @@ #include "wine/test.h" static BOOL (WINAPI *pConvertSidToStringSidA)(PSID, LPSTR*); -static UINT (WINAPI *pMsiSourceListGetInfoA) - (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, LPSTR, LPDWORD); +static UINT (WINAPI *pMsiSourceListAddMediaDiskA) + (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPCSTR, LPCSTR); static UINT (WINAPI *pMsiSourceListAddSourceExA) (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, DWORD); +static UINT (WINAPI *pMsiSourceListEnumMediaDisksA) + (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPDWORD, LPSTR, + LPDWORD, LPSTR, LPDWORD); +static UINT (WINAPI *pMsiSourceListEnumSourcesA) + (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPSTR, LPDWORD); +static UINT (WINAPI *pMsiSourceListGetInfoA) + (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR, LPSTR, LPDWORD); +static UINT (WINAPI *pMsiSourceListSetInfoA) + (LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD,LPCSTR, LPCSTR); +static UINT (WINAPI *pMsiSourceListAddSourceA) + (LPCSTR, LPCSTR, DWORD, LPCSTR); static void init_functionpointers(void) { @@ -46,8 +57,13 @@ static void init_functionpointers(void) if(!p ## func) \ trace("GetProcAddress(%s) failed\n", #func); + GET_PROC(hmsi, MsiSourceListAddMediaDiskA) GET_PROC(hmsi, MsiSourceListAddSourceExA) + GET_PROC(hmsi, MsiSourceListEnumMediaDisksA) + GET_PROC(hmsi, MsiSourceListEnumSourcesA) GET_PROC(hmsi, MsiSourceListGetInfoA) + GET_PROC(hmsi, MsiSourceListSetInfoA) + GET_PROC(hmsi, MsiSourceListAddSourceA) GET_PROC(hadvapi32, ConvertSidToStringSidA) @@ -106,20 +122,54 @@ static void create_test_guid(LPSTR prodcode, LPSTR squashed) WideCharToMultiByte(CP_ACP, 0, squashedW, -1, squashed, MAX_PATH, NULL, NULL); } -static void get_user_sid(LPSTR *usersid) +static int get_user_sid(LPSTR *usersid) { HANDLE token; BYTE buf[1024]; DWORD size; PTOKEN_USER user; + BOOL rc; - OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token); + rc=OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token); + if (!rc && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + return 0; size = sizeof(buf); GetTokenInformation(token, TokenUser, (void *)buf, size, &size); user = (PTOKEN_USER)buf; pConvertSidToStringSidA(user->User.Sid, usersid); + return 1; +} + +static void check_reg_str(HKEY prodkey, LPCSTR name, LPCSTR expected, BOOL bcase, DWORD line) +{ + char val[MAX_PATH]; + DWORD size, type; + LONG res; + + size = MAX_PATH; + val[0] = '\0'; + res = RegQueryValueExA(prodkey, name, NULL, &type, (LPBYTE)val, &size); + + if (res != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) + { + ok_(__FILE__, line)(FALSE, "Key doesn't exist or wrong type\n"); + return; + } + + if (!expected) + ok_(__FILE__, line)(lstrlenA(val) == 0, "Expected empty string, got %s\n", val); + else + { + if (bcase) + ok_(__FILE__, line)(!lstrcmpA(val, expected), "Expected %s, got %s\n", expected, val); + else + ok_(__FILE__, line)(!lstrcmpiA(val, expected), "Expected %s, got %s\n", expected, val); + } } +#define CHECK_REG_STR(prodkey, name, expected) \ + check_reg_str(prodkey, name, expected, TRUE, __LINE__); + static void test_MsiSourceListGetInfo(void) { CHAR prodcode[MAX_PATH]; @@ -130,7 +180,7 @@ static void test_MsiSourceListGetInfo(void) LPCSTR data; LONG res; UINT r; - HKEY userkey, hkey; + HKEY userkey, hkey, media; DWORD size; if (!pMsiSourceListGetInfoA) @@ -140,7 +190,11 @@ static void test_MsiSourceListGetInfo(void) } create_test_guid(prodcode, prod_squashed); - get_user_sid(&usersid); + if (!get_user_sid(&usersid)) + { + skip("User SID not available -> skipping MsiSourceListGetInfoA tests\n"); + return; + } /* NULL szProductCodeOrPatchCode */ r = pMsiSourceListGetInfoA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, @@ -218,6 +272,7 @@ static void test_MsiSourceListGetInfo(void) ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); /* size is non-NULL while value is NULL */ + size = MAX_PATH; r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); @@ -229,6 +284,7 @@ static void test_MsiSourceListGetInfo(void) ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); /* user product key exists */ + size = MAX_PATH; r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAME, NULL, &size); ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); @@ -302,6 +358,206 @@ static void test_MsiSourceListGetInfo(void) ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); ok(size == 11, "Expected 11, got %d\n", size); + /* INSTALLPROPERTY_MEDIAPACKAGEPATH, media key does not exist */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_MEDIAPACKAGEPATH, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value); + ok(size == 0, "Expected 0, got %d\n", size); + + res = RegCreateKeyA(hkey, "Media", &media); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + data = "path"; + res = RegSetValueExA(media, "MediaPackage", 0, REG_SZ, + (const BYTE *)data, lstrlenA(data) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLPROPERTY_MEDIAPACKAGEPATH */ + size = MAX_PATH; + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_MEDIAPACKAGEPATH, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "path"), "Expected \"path\", got \"%s\"\n", value); + ok(size == 4, "Expected 4, got %d\n", size); + + /* INSTALLPROPERTY_DISKPROMPT */ + data = "prompt"; + res = RegSetValueExA(media, "DiskPrompt", 0, REG_SZ, + (const BYTE *)data, lstrlenA(data) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + size = MAX_PATH; + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_DISKPROMPT, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "prompt"), "Expected \"prompt\", got \"%s\"\n", value); + ok(size == 6, "Expected 6, got %d\n", size); + + data = ""; + res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ, + (const BYTE *)data, lstrlenA(data) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLPROPERTY_LASTUSEDSOURCE, source is empty */ + size = MAX_PATH; + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value); + ok(size == 0, "Expected 0, got %d\n", size); + + data = "source"; + res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ, + (const BYTE *)data, lstrlenA(data) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLPROPERTY_LASTUSEDSOURCE */ + size = MAX_PATH; + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "source"), "Expected \"source\", got \"%s\"\n", value); + ok(size == 6, "Expected 6, got %d\n", size); + + /* INSTALLPROPERTY_LASTUSEDSOURCE, size is too short */ + size = 4; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, + value, &size); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got \"%s\"\n", value); + ok(size == 6, "Expected 6, got %d\n", size); + + /* INSTALLPROPERTY_LASTUSEDSOURCE, size is exactly 6 */ + size = 6; + lstrcpyA(value, "aaa"); + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, + value, &size); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got \"%s\"\n", value); + ok(size == 6, "Expected 6, got %d\n", size); + + data = "a;source"; + res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ, + (const BYTE *)data, lstrlenA(data) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLPROPERTY_LASTUSEDSOURCE, one semi-colon */ + size = MAX_PATH; + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "source"), "Expected \"source\", got \"%s\"\n", value); + ok(size == 6, "Expected 6, got %d\n", size); + + data = "a:source"; + res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ, + (const BYTE *)data, lstrlenA(data) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLPROPERTY_LASTUSEDSOURCE, one colon */ + size = MAX_PATH; + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCE, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "a:source"), "Expected \"a:source\", got \"%s\"\n", value); + ok(size == 8, "Expected 8, got %d\n", size); + + /* INSTALLPROPERTY_LASTUSEDTYPE, invalid source format */ + size = MAX_PATH; + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value); + ok(size == 0, "Expected 0, got %d\n", size); + + data = "x;y;z"; + res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ, + (const BYTE *)data, lstrlenA(data) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLPROPERTY_LASTUSEDTYPE, invalid source format */ + size = MAX_PATH; + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, ""), "Expected \"\", got \"%s\"\n", value); + ok(size == 0, "Expected 0, got %d\n", size); + + data = "n;y;z"; + res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ, + (const BYTE *)data, lstrlenA(data) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLPROPERTY_LASTUSEDTYPE */ + size = MAX_PATH; + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "n"), "Expected \"n\", got \"%s\"\n", value); + ok(size == 1, "Expected 1, got %d\n", size); + + data = "negatory"; + res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ, + (const BYTE *)data, lstrlenA(data) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLPROPERTY_LASTUSEDTYPE */ + size = MAX_PATH; + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "n"), "Expected \"n\", got \"%s\"\n", value); + ok(size == 1, "Expected 1, got %d\n", size); + + data = "megatron"; + res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ, + (const BYTE *)data, lstrlenA(data) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLPROPERTY_LASTUSEDTYPE */ + size = MAX_PATH; + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "m"), "Expected \"m\", got \"%s\"\n", value); + ok(size == 1, "Expected 1, got %d\n", size); + + data = "useless"; + res = RegSetValueExA(hkey, "LastUsedSource", 0, REG_SZ, + (const BYTE *)data, lstrlenA(data) + 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* INSTALLPROPERTY_LASTUSEDTYPE */ + size = MAX_PATH; + r = pMsiSourceListGetInfoA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDTYPE, + value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "u"), "Expected \"u\", got \"%s\"\n", value); + ok(size == 1, "Expected 1, got %d\n", size); + + RegDeleteValueA(media, "MediaPackage"); + RegDeleteValueA(media, "DiskPrompt"); + RegDeleteKeyA(media, ""); + RegDeleteValueA(hkey, "LastUsedSource"); RegDeleteValueA(hkey, "nonexistent"); RegDeleteValueA(hkey, "PackageName"); RegDeleteKeyA(hkey, ""); @@ -367,7 +623,11 @@ static void test_MsiSourceListAddSourceEx(void) } create_test_guid(prodcode, prod_squashed); - get_user_sid(&usersid); + if (!get_user_sid(&usersid)) + { + skip("User SID not available -> skipping MsiSourceListAddSourceExA tests\n"); + return; + } /* GetLastError is not set by the function */ @@ -716,10 +976,2336 @@ static void test_MsiSourceListAddSourceEx(void) HeapFree(GetProcessHeap(), 0, usersid); } +static void test_MsiSourceListEnumSources(void) +{ + CHAR prodcode[MAX_PATH]; + CHAR prod_squashed[MAX_PATH]; + CHAR keypath[MAX_PATH*2]; + CHAR value[MAX_PATH]; + LPSTR usersid; + LONG res; + UINT r; + HKEY prodkey, userkey; + HKEY url, net, source; + DWORD size; + + if (!pMsiSourceListEnumSourcesA) + { + skip("MsiSourceListEnumSourcesA is not available\n"); + return; + } + + create_test_guid(prodcode, prod_squashed); + if (!get_user_sid(&usersid)) + { + skip("User SID not available -> skipping MsiSourceListEnumSourcesA tests\n"); + return; + } + + /* GetLastError is not set by the function */ + + /* NULL szProductCodeOrPatchCode */ + size = 0xdeadbeef; + r = pMsiSourceListEnumSourcesA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + + /* empty szProductCodeOrPatchCode */ + size = 0xdeadbeef; + r = pMsiSourceListEnumSourcesA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + + /* garbage szProductCodeOrPatchCode */ + size = 0xdeadbeef; + r = pMsiSourceListEnumSourcesA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + + /* guid without brackets */ + size = 0xdeadbeef; + r = pMsiSourceListEnumSourcesA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA", + usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + + /* guid with brackets */ + size = 0xdeadbeef; + r = pMsiSourceListEnumSourcesA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", + usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(size == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", size); + + /* MSIINSTALLCONTEXT_USERUNMANAGED */ + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegCreateKeyA(userkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegCreateKeyA(source, "URL", &url); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URL key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegSetValueExA(url, "1", 0, REG_SZ, (LPBYTE)"first", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(url, "2", 0, REG_SZ, (LPBYTE)"second", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegSetValueExA(url, "4", 0, REG_SZ, (LPBYTE)"fourth", 7); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* sources exist */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value); + ok(size == 5, "Expected 5, got %d\n", size); + + /* try index 0 again */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value); + ok(size == 5, "Expected 5, got %d\n", size); + + /* both szSource and pcchSource are NULL, index 0 */ + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* both szSource and pcchSource are NULL, index 1 */ + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 1, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* size is exactly 5 */ + size = 5; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got %s\n", value); + ok(size == 5, "Expected 5, got %d\n", size); + + /* szSource is non-NULL while pcchSource is NULL */ + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, NULL); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got %s\n", value); + + /* try index 1 after failure */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 1, value, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected \"aaa\", got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + /* reset the enumeration */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value); + ok(size == 5, "Expected 5, got %d\n", size); + + /* try index 1 */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 1, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "second"), "Expected \"second\", got %s\n", value); + ok(size == 6, "Expected 6, got %d\n", size); + + /* try index 1 again */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 1, value, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + /* try index 2 */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 2, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + /* try index < 0 */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, -1, value, &size); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + /* NULL szUserSid */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value); + ok(size == 5, "Expected 5, got %d\n", size); + + /* invalid dwOptions, must be one of MSICODE_ and MSISOURCETYPE_ */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, value, &size); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + /* invalid dwOptions, must be one of MSICODE_ and MSISOURCETYPE_ */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PATCH, 0, value, &size); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + /* invalid dwOptions, must be one of MSICODE_ and MSISOURCETYPE_ */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSICODE_PATCH | MSISOURCETYPE_URL, + 0, value, &size); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + /* invalid dwOptions, must be one of MSICODE_ and MSISOURCETYPE_ */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL, + 0, value, &size); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + RegDeleteValueA(url, "1"); + RegDeleteValueA(url, "2"); + RegDeleteValueA(url, "4"); + RegDeleteKeyA(url, ""); + RegCloseKey(url); + + /* SourceList key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegCreateKeyA(source, "Net", &net); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Net key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegSetValueExA(net, "1", 0, REG_SZ, (LPBYTE)"first", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* sources exist */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value); + ok(size == 5, "Expected 5, got %d\n", size); + + RegDeleteValueA(net, "1"); + RegDeleteKeyA(net, ""); + RegCloseKey(net); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + + /* MSIINSTALLCONTEXT_USERMANAGED */ + + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegCreateKeyA(userkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegCreateKeyA(source, "URL", &url); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URL key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegSetValueExA(url, "1", 0, REG_SZ, (LPBYTE)"first", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* sources exist */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value); + ok(size == 5, "Expected 5, got %d\n", size); + + /* NULL szUserSid */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value); + ok(size == 5, "Expected 5, got %d\n", size); + + RegDeleteValueA(url, "1"); + RegDeleteKeyA(url, ""); + RegCloseKey(url); + + /* SourceList key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegCreateKeyA(source, "Net", &net); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Net key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegSetValueExA(net, "1", 0, REG_SZ, (LPBYTE)"first", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* sources exist */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value); + ok(size == 5, "Expected 5, got %d\n", size); + + RegDeleteValueA(net, "1"); + RegDeleteKeyA(net, ""); + RegCloseKey(net); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + + /* MSIINSTALLCONTEXT_MACHINE */ + + /* szUserSid is non-NULL */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, usersid, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + /* szUserSid is non-NULL */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegCreateKeyA(prodkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegCreateKeyA(source, "URL", &url); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* URL key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegSetValueExA(url, "1", 0, REG_SZ, (LPBYTE)"first", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* sources exist */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value); + ok(size == 5, "Expected 5, got %d\n", size); + + /* NULL szUserSid */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value); + ok(size == 5, "Expected 5, got %d\n", size); + + RegDeleteValueA(url, "1"); + RegDeleteKeyA(url, ""); + RegCloseKey(url); + + /* SourceList key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegCreateKeyA(source, "Net", &net); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Net key exists */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(!lstrcmpA(value, "aaa"), "Expected value to be unchanged, got %s\n", value); + ok(size == MAX_PATH, "Expected MAX_PATH, got %d\n", size); + + res = RegSetValueExA(net, "1", 0, REG_SZ, (LPBYTE)"first", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* sources exist */ + size = MAX_PATH; + lstrcpyA(value, "aaa"); + r = pMsiSourceListEnumSourcesA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, value, &size); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(value, "first"), "Expected \"first\", got %s\n", value); + ok(size == 5, "Expected 5, got %d\n", size); + + RegDeleteValueA(net, "1"); + RegDeleteKeyA(net, ""); + RegCloseKey(net); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); +} + +static void test_MsiSourceListSetInfo(void) +{ + CHAR prodcode[MAX_PATH]; + CHAR prod_squashed[MAX_PATH]; + CHAR keypath[MAX_PATH*2]; + HKEY prodkey, userkey; + HKEY net, url, media, source; + LPSTR usersid; + LONG res; + UINT r; + + if (!pMsiSourceListSetInfoA) + { + skip("MsiSourceListSetInfoA is not available\n"); + return; + } + + create_test_guid(prodcode, prod_squashed); + if (!get_user_sid(&usersid)) + { + skip("User SID not available -> skipping MsiSourceListSetInfoA tests\n"); + return; + } + + /* GetLastError is not set by the function */ + + /* NULL szProductCodeOrPatchCode */ + r = pMsiSourceListSetInfoA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* empty szProductCodeOrPatchCode */ + r = pMsiSourceListSetInfoA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* garbage szProductCodeOrPatchCode */ + r = pMsiSourceListSetInfoA("garbage", usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* guid without brackets */ + r = pMsiSourceListSetInfoA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA", + usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* guid with brackets */ + r = pMsiSourceListSetInfoA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", + usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + /* dwOptions is MSICODE_PRODUCT */ + r = pMsiSourceListSetInfoA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + /* dwOptions is MSICODE_PATCH */ + r = pMsiSourceListSetInfoA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PATCH, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + + /* dwOptions is both MSICODE_PRODUCT and MSICODE_PATCH */ + r = pMsiSourceListSetInfoA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSICODE_PATCH | MSISOURCETYPE_URL, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_UNKNOWN_PATCH, "Expected ERROR_UNKNOWN_PATCH, got %d\n", r); + + /* dwOptions has both MSISOURCETYPE_NETWORK and MSISOURCETYPE_URL */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + /* LastUsedSource and dwOptions has both + * MSISOURCETYPE_NETWORK and MSISOURCETYPE_URL + */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK | MSISOURCETYPE_URL, + INSTALLPROPERTY_LASTUSEDSOURCE, "path"); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + /* LastUsedSource and dwOptions has no source type */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_LASTUSEDSOURCE, "path"); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + /* MSIINSTALLCONTEXT_USERUNMANAGED */ + + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + + res = RegCreateKeyA(userkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists, no source type */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* Media key is created by MsiSourceListSetInfo */ + res = RegOpenKeyA(source, "Media", &media); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + CHECK_REG_STR(media, "MediaPackage", "path"); + + /* set the info again */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path2"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + CHECK_REG_STR(media, "MediaPackage", "path2"); + + /* NULL szProperty */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + NULL, "path"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* empty szProperty */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + "", "path"); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + + /* NULL szValue */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_MEDIAPACKAGEPATH, NULL); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + + /* empty szValue */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_MEDIAPACKAGEPATH, ""); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + CHECK_REG_STR(media, "MediaPackage", ""); + + /* INSTALLPROPERTY_MEDIAPACKAGEPATH, MSISOURCETYPE_NETWORK */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* INSTALLPROPERTY_MEDIAPACKAGEPATH, MSISOURCETYPE_URL */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* INSTALLPROPERTY_DISKPROMPT */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_DISKPROMPT, "prompt"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + CHECK_REG_STR(media, "DiskPrompt", "prompt"); + + /* INSTALLPROPERTY_DISKPROMPT, MSISOURCETYPE_NETWORK */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_DISKPROMPT, "prompt"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* INSTALLPROPERTY_DISKPROMPT, MSISOURCETYPE_URL */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, + INSTALLPROPERTY_DISKPROMPT, "prompt"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* INSTALLPROPERTY_LASTUSEDSOURCE */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_LASTUSEDSOURCE, "source"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* INSTALLPROPERTY_LASTUSEDSOURCE, MSISOURCETYPE_NETWORK */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_LASTUSEDSOURCE, "source"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* Net key is created by MsiSourceListSetInfo */ + res = RegOpenKeyA(source, "Net", &net); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + CHECK_REG_STR(net, "1", "source\\") + CHECK_REG_STR(source, "LastUsedSource", "n;1;source"); + + /* source has forward slash */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_LASTUSEDSOURCE, "source/"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + CHECK_REG_STR(net, "1", "source\\"); + CHECK_REG_STR(net, "2", "source/\\"); + CHECK_REG_STR(source, "LastUsedSource", "n;2;source/"); + + /* INSTALLPROPERTY_LASTUSEDSOURCE, MSISOURCETYPE_URL */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, + INSTALLPROPERTY_LASTUSEDSOURCE, "source"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* URL key is created by MsiSourceListSetInfo */ + res = RegOpenKeyA(source, "URL", &url); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + CHECK_REG_STR(url, "1", "source/"); + CHECK_REG_STR(source, "LastUsedSource", "u;1;source"); + + /* source has backslash */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, + INSTALLPROPERTY_LASTUSEDSOURCE, "source\\"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + CHECK_REG_STR(url, "1", "source/"); + CHECK_REG_STR(url, "2", "source\\/"); + CHECK_REG_STR(source, "LastUsedSource", "u;2;source\\"); + + /* INSTALLPROPERTY_LASTUSEDSOURCE, MSISOURCETYPE_MEDIA */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_MEDIA, + INSTALLPROPERTY_LASTUSEDSOURCE, "source"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* INSTALLPROPERTY_PACKAGENAME */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_PACKAGENAME, "name"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + CHECK_REG_STR(source, "PackageName", "name"); + + /* INSTALLPROPERTY_PACKAGENAME, MSISOURCETYPE_NETWORK */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, + INSTALLPROPERTY_PACKAGENAME, "name"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* INSTALLPROPERTY_PACKAGENAME, MSISOURCETYPE_URL */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, + INSTALLPROPERTY_PACKAGENAME, "name"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* INSTALLPROPERTY_LASTUSEDTYPE */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_LASTUSEDTYPE, "type"); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + + /* definitely unknown property */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, + "unknown", "val"); + ok(r == ERROR_UNKNOWN_PROPERTY, + "Expected ERROR_UNKNOWN_PROPERTY, got %d\n", r); + + RegDeleteValueA(net, "1"); + RegDeleteKeyA(net, ""); + RegCloseKey(net); + RegDeleteValueA(url, "1"); + RegDeleteKeyA(url, ""); + RegCloseKey(url); + RegDeleteValueA(media, "MediaPackage"); + RegDeleteValueA(media, "DiskPrompt"); + RegDeleteKeyA(media, ""); + RegCloseKey(media); + RegDeleteValueA(source, "PackageName"); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + + /* MSIINSTALLCONTEXT_USERMANAGED */ + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + + res = RegCreateKeyA(userkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists, no source type */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* Media key is created by MsiSourceListSetInfo */ + res = RegOpenKeyA(source, "Media", &media); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + CHECK_REG_STR(media, "MediaPackage", "path"); + + RegDeleteValueA(media, "MediaPackage"); + RegDeleteKeyA(media, ""); + RegCloseKey(media); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + + /* MSIINSTALLCONTEXT_MACHINE */ + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, MSICODE_PRODUCT, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + + res = RegCreateKeyA(prodkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists, no source type */ + r = pMsiSourceListSetInfoA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, MSICODE_PRODUCT, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* Media key is created by MsiSourceListSetInfo */ + res = RegOpenKeyA(source, "Media", &media); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + CHECK_REG_STR(media, "MediaPackage", "path"); + + /* szUserSid is non-NULL */ + r = pMsiSourceListSetInfoA(prodcode, usersid, + MSIINSTALLCONTEXT_MACHINE, MSICODE_PRODUCT, + INSTALLPROPERTY_MEDIAPACKAGEPATH, "path"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + RegDeleteValueA(media, "MediaPackage"); + RegDeleteKeyA(media, ""); + RegCloseKey(media); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); +} + +static void test_MsiSourceListAddMediaDisk(void) +{ + CHAR prodcode[MAX_PATH]; + CHAR prod_squashed[MAX_PATH]; + CHAR keypath[MAX_PATH*2]; + HKEY prodkey, userkey; + HKEY media, source; + LPSTR usersid; + LONG res; + UINT r; + + if (!pMsiSourceListAddMediaDiskA) + { + skip("MsiSourceListAddMediaDiskA is not available\n"); + return; + } + + create_test_guid(prodcode, prod_squashed); + if (!get_user_sid(&usersid)) + { + skip("User SID not available -> skipping MsiSourceListAddMediaDiskA tests\n"); + return; + } + + /* GetLastError is not set by the function */ + + /* NULL szProductCodeOrPatchCode */ + r = pMsiSourceListAddMediaDiskA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, "label", "prompt"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* empty szProductCodeOrPatchCode */ + r = pMsiSourceListAddMediaDiskA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, "label", "prompt"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* garbage szProductCodeOrPatchCode */ + r = pMsiSourceListAddMediaDiskA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, "label", "prompt"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* guid without brackets */ + r = pMsiSourceListAddMediaDiskA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA", + usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, "label", "prompt"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* guid with brackets */ + r = pMsiSourceListAddMediaDiskA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", + usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, "label", "prompt"); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + /* dwOptions has MSISOURCETYPE_NETWORK */ + r = pMsiSourceListAddMediaDiskA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", + usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, + 1, "label", "prompt"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* dwOptions has MSISOURCETYPE_URL */ + r = pMsiSourceListAddMediaDiskA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", + usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, + 1, "label", "prompt"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* dwOptions has MSISOURCETYPE_MEDIA */ + r = pMsiSourceListAddMediaDiskA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", + usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_MEDIA, + 1, "label", "prompt"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* MSIINSTALLCONTEXT_USERUNMANAGED */ + + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, "label", "prompt"); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + + res = RegCreateKeyA(userkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, "label", "prompt"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* Media subkey is created by MsiSourceListAddMediaDisk */ + res = RegOpenKeyA(source, "Media", &media); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(media, "1", "label;prompt"); + + /* dwDiskId is random */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 42, "label42", "prompt42"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + CHECK_REG_STR(media, "1", "label;prompt"); + CHECK_REG_STR(media, "42", "label42;prompt42"); + + /* dwDiskId is 0 */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, "label0", "prompt0"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + CHECK_REG_STR(media, "0", "label0;prompt0"); + CHECK_REG_STR(media, "1", "label;prompt"); + CHECK_REG_STR(media, "42", "label42;prompt42"); + + /* dwDiskId is < 0 */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, -1, "label-1", "prompt-1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + CHECK_REG_STR(media, "-1", "label-1;prompt-1"); + CHECK_REG_STR(media, "0", "label0;prompt0"); + CHECK_REG_STR(media, "1", "label;prompt"); + CHECK_REG_STR(media, "42", "label42;prompt42"); + + /* update dwDiskId 1 */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, "newlabel", "newprompt"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + CHECK_REG_STR(media, "-1", "label-1;prompt-1"); + CHECK_REG_STR(media, "0", "label0;prompt0"); + CHECK_REG_STR(media, "1", "newlabel;newprompt"); + CHECK_REG_STR(media, "42", "label42;prompt42"); + + /* update dwDiskId 1, szPrompt is NULL */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, "etiqueta", NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + CHECK_REG_STR(media, "-1", "label-1;prompt-1"); + CHECK_REG_STR(media, "0", "label0;prompt0"); + CHECK_REG_STR(media, "1", "etiqueta;"); + CHECK_REG_STR(media, "42", "label42;prompt42"); + + /* update dwDiskId 1, szPrompt is empty */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, "etikett", ""); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* update dwDiskId 1, szVolumeLable is NULL */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, NULL, "provocar"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + CHECK_REG_STR(media, "-1", "label-1;prompt-1"); + CHECK_REG_STR(media, "0", "label0;prompt0"); + CHECK_REG_STR(media, "1", ";provocar"); + CHECK_REG_STR(media, "42", "label42;prompt42"); + + /* update dwDiskId 1, szVolumeLable is empty */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, "", "provoquer"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* szUserSid is NULL */ + r = pMsiSourceListAddMediaDiskA(prodcode, NULL, + MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, NULL, "provoquer"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + CHECK_REG_STR(media, "-1", "label-1;prompt-1"); + CHECK_REG_STR(media, "0", "label0;prompt0"); + CHECK_REG_STR(media, "1", ";provoquer"); + CHECK_REG_STR(media, "42", "label42;prompt42"); + + RegDeleteValueA(media, "-1"); + RegDeleteValueA(media, "0"); + RegDeleteValueA(media, "1"); + RegDeleteValueA(media, "42"); + RegDeleteKeyA(media, ""); + RegCloseKey(media); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + + /* MSIINSTALLCONTEXT_USERMANAGED */ + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT, 1, "label", "prompt"); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + + res = RegCreateKeyA(userkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT, 1, "label", "prompt"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* Media subkey is created by MsiSourceListAddMediaDisk */ + res = RegOpenKeyA(source, "Media", &media); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(media, "1", "label;prompt"); + + RegDeleteValueA(media, "1"); + RegDeleteKeyA(media, ""); + RegCloseKey(media); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + + /* MSIINSTALLCONTEXT_MACHINE */ + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* machine product key exists */ + r = pMsiSourceListAddMediaDiskA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT, 1, "label", "prompt"); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + + res = RegCreateKeyA(prodkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists */ + r = pMsiSourceListAddMediaDiskA(prodcode, NULL, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT, 1, "label", "prompt"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* Media subkey is created by MsiSourceListAddMediaDisk */ + res = RegOpenKeyA(source, "Media", &media); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(media, "1", "label;prompt"); + + /* szUserSid is non-NULL */ + r = pMsiSourceListAddMediaDiskA(prodcode, usersid, + MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT, 1, "label", "prompt"); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + RegDeleteValueA(media, "1"); + RegDeleteKeyA(media, ""); + RegCloseKey(media); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); +} + +static void test_MsiSourceListEnumMediaDisks(void) +{ + CHAR prodcode[MAX_PATH]; + CHAR prod_squashed[MAX_PATH]; + CHAR keypath[MAX_PATH*2]; + CHAR label[MAX_PATH]; + CHAR prompt[MAX_PATH]; + HKEY prodkey, userkey; + HKEY media, source; + DWORD labelsz, promptsz; + LPSTR usersid; + DWORD val; + DWORD id; + LONG res; + UINT r; + + if (!pMsiSourceListEnumMediaDisksA) + { + skip("MsiSourceListEnumMediaDisksA is not available\n"); + return; + } + + create_test_guid(prodcode, prod_squashed); + if (!get_user_sid(&usersid)) + { + skip("User SID not available -> skipping MsiSourceListEnumMediaDisksA tests\n"); + return; + } + + /* GetLastError is not set by the function */ + + /* NULL szProductCodeOrPatchCode */ + r = pMsiSourceListEnumMediaDisksA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* empty szProductCodeOrPatchCode */ + r = pMsiSourceListEnumMediaDisksA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* garbage szProductCodeOrPatchCode */ + r = pMsiSourceListEnumMediaDisksA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* guid without brackets */ + r = pMsiSourceListEnumMediaDisksA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA", + usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* guid with brackets */ + r = pMsiSourceListEnumMediaDisksA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", + usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_UNKNOWN_PRODUCT, + "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + /* dwOptions has MSISOURCETYPE_NETWORK */ + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, + 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* dwOptions has MSISOURCETYPE_URL */ + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT | MSISOURCETYPE_URL, + 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* dwIndex is non-zero */ + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* MSIINSTALLCONTEXT_USERUNMANAGED */ + + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + + res = RegCreateKeyA(userkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = 0xdeadbeef; + lstrcpyA(prompt, "bbb"); + promptsz = 0xdeadbeef; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_NO_MORE_ITEMS, + "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", promptsz); + + res = RegCreateKeyA(source, "Media", &media); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Media key exists */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = 0xdeadbeef; + lstrcpyA(prompt, "bbb"); + promptsz = 0xdeadbeef; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_NO_MORE_ITEMS, + "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", promptsz); + + res = RegSetValueExA(media, "1", 0, REG_SZ, (LPBYTE)"label;prompt", 13); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* disk exists */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + res = RegSetValueExA(media, "2", 0, REG_SZ, (LPBYTE)"one;two", 8); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* now disk 2 exists, get the sizes */ + id = 0; + labelsz = MAX_PATH; + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, &id, NULL, &labelsz, + NULL, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 2, "Expected 2, got %d\n", id); + ok(labelsz == 3, "Expected 3, got %d\n", labelsz); + ok(promptsz == 3, "Expected 3, got %d\n", promptsz); + + /* now fill in the values */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == MAX_PATH, "Expected MAX_PATH, got %d\n", promptsz); + + res = RegSetValueExA(media, "4", 0, REG_SZ, (LPBYTE)"three;four", 11); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* disks 1, 2, 4 exist, reset the enumeration */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + /* disks 1, 2, 4 exist, index 1 */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 2, "Expected 2, got %d\n", id); + ok(!lstrcmpA(label, "one"), "Expected \"one\", got \"%s\"\n", label); + ok(labelsz == 3, "Expected 3, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "two"), "Expected \"two\", got \"%s\"\n", prompt); + ok(promptsz == 3, "Expected 3, got %d\n", promptsz); + + /* disks 1, 2, 4 exist, index 2 */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 2, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 4, "Expected 4, got %d\n", id); + ok(!lstrcmpA(label, "three"), "Expected \"three\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "four"), "Expected \"four\", got \"%s\"\n", prompt); + ok(promptsz == 4, "Expected 4, got %d\n", promptsz); + + /* disks 1, 2, 4 exist, index 3, invalid */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 3, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_NO_MORE_ITEMS, + "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == MAX_PATH, "Expected MAX_PATH, got %d\n", promptsz); + + /* disks 1, 2, 4 exist, reset the enumeration */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + /* try index 0 again */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + /* jump to index 2 */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 2, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == MAX_PATH, "Expected MAX_PATH, got %d\n", promptsz); + + /* after error, try index 1 */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 2, "Expected 2, got %d\n", id); + ok(!lstrcmpA(label, "one"), "Expected \"one\", got \"%s\"\n", label); + ok(labelsz == 3, "Expected 3, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "two"), "Expected \"two\", got \"%s\"\n", prompt); + ok(promptsz == 3, "Expected 3, got %d\n", promptsz); + + /* try index 1 again */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 1, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == MAX_PATH, "Expected MAX_PATH, got %d\n", promptsz); + + /* NULL pdwDiskId */ + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, NULL, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + /* szVolumeLabel is NULL */ + id = 0; + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, NULL, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + /* szVolumeLabel and pcchVolumeLabel are NULL */ + id = 0; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, NULL, NULL, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + /* szVolumeLabel is non-NULL while pcchVolumeLabel is NULL */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, NULL, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + /* szDiskPrompt is NULL */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + NULL, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + /* szDiskPrompt and pcchDiskPrompt are NULL */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + + /* szDiskPrompt is non-NULL while pcchDiskPrompt is NULL */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, NULL); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + + /* pcchVolumeLabel is exactly 5 */ + lstrcpyA(label, "aaa"); + labelsz = 5; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, NULL, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + /* pcchDiskPrompt is exactly 6 */ + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = 6; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, NULL, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", r); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + res = RegSetValueExA(media, "1", 0, REG_SZ, (LPBYTE)"label", 13); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* no semicolon */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "label"), "Expected \"label\", got \"%s\"\n", prompt); + ok(promptsz == 5, "Expected 5, got %d\n", promptsz); + + res = RegSetValueExA(media, "1", 0, REG_SZ, (LPBYTE)"label;", 13); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* semicolon, no disk prompt */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, ""), "Expected \"\", got \"%s\"\n", prompt); + ok(promptsz == 0, "Expected 0, got %d\n", promptsz); + + res = RegSetValueExA(media, "1", 0, REG_SZ, (LPBYTE)";prompt", 13); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* semicolon, label doesn't exist */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(!lstrcmpA(label, ""), "Expected \"\", got \"%s\"\n", label); + ok(labelsz == 0, "Expected 0, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + res = RegSetValueExA(media, "1", 0, REG_SZ, (LPBYTE)";", 13); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* semicolon, neither label nor disk prompt exist */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + ok(!lstrcmpA(label, ""), "Expected \"\", got \"%s\"\n", label); + ok(labelsz == 0, "Expected 0, got %d\n", labelsz); + ok(!lstrcmpA(prompt, ""), "Expected \"\", got \"%s\"\n", prompt); + ok(promptsz == 0, "Expected 0, got %d\n", promptsz); + + val = 42; + res = RegSetValueExA(media, "1", 0, REG_DWORD, (LPBYTE)&val, sizeof(DWORD)); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* type is REG_DWORD */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 1, "Expected 1, got %d\n", id); + todo_wine + { + ok(!lstrcmpA(label, "#42"), "Expected \"#42\", got \"%s\"\n", label); + ok(labelsz == 3, "Expected 3, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "#42"), "Expected \"#42\", got \"%s\"\n", prompt); + ok(promptsz == 3, "Expected 3, got %d\n", promptsz); + } + + RegDeleteValueA(media, "1"); + RegDeleteValueA(media, "2"); + RegDeleteValueA(media, "4"); + RegDeleteKeyA(media, ""); + RegCloseKey(media); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + + /* MSIINSTALLCONTEXT_USERMANAGED */ + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + + res = RegCreateKeyA(userkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = 0xdeadbeef; + lstrcpyA(prompt, "bbb"); + promptsz = 0xdeadbeef; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_NO_MORE_ITEMS, + "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", promptsz); + + res = RegCreateKeyA(source, "Media", &media); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Media key exists */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = 0xdeadbeef; + lstrcpyA(prompt, "bbb"); + promptsz = 0xdeadbeef; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_NO_MORE_ITEMS, + "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", promptsz); + + res = RegSetValueExA(media, "2", 0, REG_SZ, (LPBYTE)"label;prompt", 13); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* disk exists, but no id 1 */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERMANAGED, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 2, "Expected 2, got %d\n", id); + ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + RegDeleteValueA(media, "2"); + RegDeleteKeyA(media, ""); + RegCloseKey(media); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + + /* MSIINSTALLCONTEXT_MACHINE */ + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* machine product key exists */ + r = pMsiSourceListEnumMediaDisksA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_BAD_CONFIGURATION, + "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + + res = RegCreateKeyA(prodkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = 0xdeadbeef; + lstrcpyA(prompt, "bbb"); + promptsz = 0xdeadbeef; + r = pMsiSourceListEnumMediaDisksA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_NO_MORE_ITEMS, + "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", promptsz); + + res = RegCreateKeyA(source, "Media", &media); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* Media key exists */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = 0xdeadbeef; + lstrcpyA(prompt, "bbb"); + promptsz = 0xdeadbeef; + r = pMsiSourceListEnumMediaDisksA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_NO_MORE_ITEMS, + "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", promptsz); + + res = RegSetValueExA(media, "2", 0, REG_SZ, (LPBYTE)"label;prompt", 13); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* disk exists, but no id 1 */ + id = 0; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, NULL, MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(id == 2, "Expected 2, got %d\n", id); + ok(!lstrcmpA(label, "label"), "Expected \"label\", got \"%s\"\n", label); + ok(labelsz == 5, "Expected 5, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "prompt"), "Expected \"prompt\", got \"%s\"\n", prompt); + ok(promptsz == 6, "Expected 6, got %d\n", promptsz); + + /* szUserSid is non-NULL */ + id = 0xbeef; + lstrcpyA(label, "aaa"); + labelsz = MAX_PATH; + lstrcpyA(prompt, "bbb"); + promptsz = MAX_PATH; + r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_MACHINE, + MSICODE_PRODUCT, 0, &id, label, &labelsz, + prompt, &promptsz); + ok(r == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + ok(id == 0xbeef, "Expected 0xbeef, got %d\n", id); + ok(!lstrcmpA(label, "aaa"), "Expected \"aaa\", got \"%s\"\n", label); + ok(labelsz == MAX_PATH, "Expected MAX_PATH, got %d\n", labelsz); + ok(!lstrcmpA(prompt, "bbb"), "Expected \"bbb\", got \"%s\"\n", prompt); + ok(promptsz == MAX_PATH, "Expected MAX_PATH, got %d\n", promptsz); + + RegDeleteValueA(media, "2"); + RegDeleteKeyA(media, ""); + RegCloseKey(media); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); +} + +static void test_MsiSourceListAddSource(void) +{ + CHAR prodcode[MAX_PATH]; + CHAR prod_squashed[MAX_PATH]; + CHAR keypath[MAX_PATH*2]; + CHAR username[MAX_PATH]; + LPSTR usersid, ptr; + LONG res; + UINT r; + HKEY prodkey, userkey; + HKEY net, source; + DWORD size; + + if (!pMsiSourceListAddSourceA) + { + skip("Skipping MsiSourceListAddSourceA tests\n"); + return; + } + + create_test_guid(prodcode, prod_squashed); + if (!get_user_sid(&usersid)) + { + skip("User SID not available -> skipping MsiSourceListAddSourceA tests\n"); + return; + } + + /* MACHINENAME\username */ + size = MAX_PATH; + GetComputerNameA(username, &size); + lstrcatA(username, "\\"); + ptr = username + lstrlenA(username); + size = MAX_PATH; + GetUserNameA(ptr, &size); + + /* GetLastError is not set by the function */ + + /* NULL szProduct */ + r = pMsiSourceListAddSourceA(NULL, username, 0, "source"); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* empty szProduct */ + r = pMsiSourceListAddSourceA("", username, 0, "source"); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* garbage szProduct */ + r = pMsiSourceListAddSourceA("garbage", username, 0, "source"); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* guid without brackets */ + r = pMsiSourceListAddSourceA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA", username, 0, "source"); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* guid with brackets */ + r = pMsiSourceListAddSourceA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", username, 0, "source"); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + /* dwReserved is not 0 */ + r = pMsiSourceListAddSourceA(prodcode, username, 42, "source"); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* szSource is NULL */ + r = pMsiSourceListAddSourceA(prodcode, username, 0, NULL); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* szSource is empty */ + r = pMsiSourceListAddSourceA(prodcode, username, 0, ""); + ok(r == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", r); + + /* MSIINSTALLCONTEXT_USERMANAGED */ + + r = pMsiSourceListAddSourceA(prodcode, username, 0, "source"); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + r = pMsiSourceListAddSourceA(prodcode, username, 0, "source"); + ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + + res = RegCreateKeyA(userkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists */ + r = pMsiSourceListAddSourceA(prodcode, username, 0, "source"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* Net key is created */ + res = RegOpenKeyA(source, "Net", &net); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LastUsedSource does not exist and it is not created */ + res = RegQueryValueExA(source, "LastUsedSource", 0, NULL, NULL, NULL); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + CHECK_REG_STR(net, "1", "source\\"); + + RegDeleteValueA(net, "1"); + RegDeleteKeyA(net, ""); + RegCloseKey(net); + + res = RegSetValueExA(source, "LastUsedSource", 0, REG_SZ, (LPBYTE)"blah", 5); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LastUsedSource value exists */ + r = pMsiSourceListAddSourceA(prodcode, username, 0, "source"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* Net key is created */ + res = RegOpenKeyA(source, "Net", &net); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(source, "LastUsedSource", "blah"); + CHECK_REG_STR(net, "1", "source\\"); + + RegDeleteValueA(net, "1"); + RegDeleteKeyA(net, ""); + RegCloseKey(net); + + res = RegSetValueExA(source, "LastUsedSource", 0, REG_SZ, (LPBYTE)"5", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LastUsedSource is an integer */ + r = pMsiSourceListAddSourceA(prodcode, username, 0, "source"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* Net key is created */ + res = RegOpenKeyA(source, "Net", &net); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(source, "LastUsedSource", "5"); + CHECK_REG_STR(net, "1", "source\\"); + + /* Add a second source, has trailing backslash */ + r = pMsiSourceListAddSourceA(prodcode, username, 0, "another\\"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + CHECK_REG_STR(source, "LastUsedSource", "5"); + CHECK_REG_STR(net, "1", "source\\"); + CHECK_REG_STR(net, "2", "another\\"); + + res = RegSetValueExA(source, "LastUsedSource", 0, REG_SZ, (LPBYTE)"2", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* LastUsedSource is in the source list */ + r = pMsiSourceListAddSourceA(prodcode, username, 0, "third/"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + CHECK_REG_STR(source, "LastUsedSource", "2"); + CHECK_REG_STR(net, "1", "source\\"); + CHECK_REG_STR(net, "2", "another\\"); + CHECK_REG_STR(net, "3", "third/\\"); + + RegDeleteValueA(net, "1"); + RegDeleteValueA(net, "2"); + RegDeleteValueA(net, "3"); + RegDeleteKeyA(net, ""); + RegCloseKey(net); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + + /* MSIINSTALLCONTEXT_USERUNMANAGED */ + + r = pMsiSourceListAddSourceA(prodcode, username, 0, "source"); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* user product key exists */ + r = pMsiSourceListAddSourceA(prodcode, username, 0, "source"); + ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + + res = RegCreateKeyA(userkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists */ + r = pMsiSourceListAddSourceA(prodcode, username, 0, "source"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* Net key is created */ + res = RegOpenKeyA(source, "Net", &net); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(net, "1", "source\\"); + + RegDeleteValueA(net, "1"); + RegDeleteKeyA(net, ""); + RegCloseKey(net); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(userkey, ""); + RegCloseKey(userkey); + + /* MSIINSTALLCONTEXT_MACHINE */ + + r = pMsiSourceListAddSourceA(prodcode, NULL, 0, "source"); + ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &prodkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* machine product key exists */ + r = pMsiSourceListAddSourceA(prodcode, NULL, 0, "source"); + ok(r == ERROR_BAD_CONFIGURATION, "Expected ERROR_BAD_CONFIGURATION, got %d\n", r); + + res = RegCreateKeyA(prodkey, "SourceList", &source); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* SourceList key exists */ + r = pMsiSourceListAddSourceA(prodcode, NULL, 0, "source"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + /* Net key is created */ + res = RegOpenKeyA(source, "Net", &net); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(net, "1", "source\\"); + + /* empty szUserName */ + r = pMsiSourceListAddSourceA(prodcode, "", 0, "another"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + + CHECK_REG_STR(net, "1", "source\\"); + CHECK_REG_STR(net, "2", "another\\"); + + RegDeleteValueA(net, "2"); + RegDeleteValueA(net, "1"); + RegDeleteKeyA(net, ""); + RegCloseKey(net); + RegDeleteKeyA(source, ""); + RegCloseKey(source); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); +} + START_TEST(source) { init_functionpointers(); test_MsiSourceListGetInfo(); test_MsiSourceListAddSourceEx(); + test_MsiSourceListEnumSources(); + test_MsiSourceListSetInfo(); + test_MsiSourceListAddMediaDisk(); + test_MsiSourceListEnumMediaDisks(); + test_MsiSourceListAddSource(); } diff --git a/rostests/winetests/msi/suminfo.c b/rostests/winetests/msi/suminfo.c index 6ef98f7df77..3afd0d50d24 100644 --- a/rostests/winetests/msi/suminfo.c +++ b/rostests/winetests/msi/suminfo.c @@ -391,10 +391,11 @@ static void test_summary_binary(void) type = 0; r = MsiSummaryInfoGetProperty(hsuminfo, PID_LASTPRINTED, &type, NULL, NULL, sval, &sz); ok(r == ERROR_SUCCESS, "MsiSummaryInfoGetProperty failed\n"); - ok(!strcmp(sval, ""), "Expected empty string, got %s\n", sval); + ok(!lstrcmpA(sval, "") || !lstrcmpA(sval, "7"), + "Expected empty string or \"7\", got \"%s\"\n", sval); todo_wine { ok(type == VT_LPSTR, "Expected VT_LPSTR, got %d\n", type); - ok(sz == 0, "Expected 0, got %d\n", sz); + ok(sz == 0 || sz == 1, "Expected 0 or 1, got %d\n", sz); } ival = -1; diff --git a/rostests/winetests/netapi32/access.c b/rostests/winetests/netapi32/access.c index 3861768ef23..7d5f55a9074 100644 --- a/rostests/winetests/netapi32/access.c +++ b/rostests/winetests/netapi32/access.c @@ -244,7 +244,17 @@ static void run_userhandling_tests(void) usri.usri1_password = sTestUserOldPass; ret = pNetUserAdd(NULL, 1, (LPBYTE)&usri, NULL); - ok(ret == NERR_BadUsername, "Adding user with too long username returned 0x%08x\n", ret); + if (ret == NERR_Success || ret == NERR_UserExists) + { + /* Windows NT4 does create the user. Delete the user and also if it already existed + * due to a previous test run on NT4. + */ + trace("We are on NT4, we have to delete the user with the too long username\n"); + ret = pNetUserDel(NULL, sTooLongName); + ok(ret == NERR_Success, "Deleting the user failed : %d\n", ret); + } + else + ok(ret == NERR_BadUsername, "Adding user with too long username returned 0x%08x\n", ret); usri.usri1_name = sTestUserName; usri.usri1_password = sTooLongPassword; @@ -256,7 +266,10 @@ static void run_userhandling_tests(void) usri.usri1_password = sTooLongPassword; ret = pNetUserAdd(NULL, 1, (LPBYTE)&usri, NULL); - ok(ret == NERR_BadUsername, + /* NT4 doesn't have a problem with the username so it will report the too long password + * as the error. NERR_PasswordTooShort is reported for all kind of password related errors. + */ + ok(ret == NERR_BadUsername || ret == NERR_PasswordTooShort, "Adding user with too long username/password returned 0x%08x\n", ret); usri.usri1_name = sTestUserName; @@ -283,7 +296,7 @@ static void run_userhandling_tests(void) ret = pNetUserChangePassword(NULL, sNonexistentUser, sTestUserOldPass, sTestUserNewPass); - ok(ret == NERR_UserNotFound, + ok(ret == NERR_UserNotFound || ret == ERROR_INVALID_PASSWORD, "Changing password for nonexistent user returned 0x%08x.\n", ret); ret = pNetUserChangePassword(NULL, sTestUserName, sTestUserOldPass, diff --git a/rostests/winetests/netapi32/netapi32.rbuild b/rostests/winetests/netapi32/netapi32.rbuild index 1baa392a26e..42143d0bab6 100644 --- a/rostests/winetests/netapi32/netapi32.rbuild +++ b/rostests/winetests/netapi32/netapi32.rbuild @@ -1,17 +1,18 @@ + . 0x600 0x600 - wine - netapi32 - advapi32 - kernel32 - ntdll access.c apibuf.c ds.c wksta.c testlist.c + wine + advapi32 + kernel32 + ntdll + diff --git a/rostests/winetests/netapi32/wksta.c b/rostests/winetests/netapi32/wksta.c index ba68eb49809..5eefba4e552 100644 --- a/rostests/winetests/netapi32/wksta.c +++ b/rostests/winetests/netapi32/wksta.c @@ -48,7 +48,7 @@ static int init_wksta_tests(void) BOOL rc; user_name[0] = 0; - dwSize = sizeof(user_name); + dwSize = sizeof(user_name)/sizeof(user_name[0]); rc=GetUserNameW(user_name, &dwSize); if (rc==FALSE && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) { skip("GetUserNameW is not implemented\n"); @@ -57,7 +57,7 @@ static int init_wksta_tests(void) ok(rc, "User Name Retrieved\n"); computer_name[0] = 0; - dwSize = sizeof(computer_name); + dwSize = sizeof(computer_name)/sizeof(computer_name[0]); ok(GetComputerNameW(computer_name, &dwSize), "Computer Name Retrieved\n"); return 1; } diff --git a/rostests/winetests/odbccp32/odbccp32.rbuild b/rostests/winetests/odbccp32/odbccp32.rbuild index d3550a35842..3c39cc72303 100644 --- a/rostests/winetests/odbccp32/odbccp32.rbuild +++ b/rostests/winetests/odbccp32/odbccp32.rbuild @@ -1,14 +1,15 @@ + . 0x600 0x600 + misc.c + testlist.c wine odbccp32 - user32 kernel32 ntdll - misc.c - testlist.c + diff --git a/rostests/winetests/riched20/editor.c b/rostests/winetests/riched20/editor.c index 48a79f52f81..090eaad0320 100644 --- a/rostests/winetests/riched20/editor.c +++ b/rostests/winetests/riched20/editor.c @@ -656,14 +656,60 @@ static void test_WM_GETTEXT(void) { HWND hwndRichEdit = new_richedit(NULL); static const char text[] = "Hello. My name is RichEdit!"; + static const char text2[] = "Hello. My name is RichEdit!\r"; + static const char text2_after[] = "Hello. My name is RichEdit!\r\n"; char buffer[1024] = {0}; int result; + /* Baseline test with normal-sized buffer */ SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text); + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok(result == lstrlen(buffer), + "WM_GETTEXT returned %d, expected %d\n", result, lstrlen(buffer)); SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); result = strcmp(buffer,text); ok(result == 0, "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); + + /* Test for returned value of WM_GETTEXTLENGTH */ + result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); + ok(result == lstrlen(text), + "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n", + result, lstrlen(text)); + + /* Test for behavior in overflow case */ + memset(buffer, 0, 1024); + result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text), (LPARAM)buffer); + ok(result == 0, + "WM_GETTEXT returned %d, expected 0\n", result); + result = strcmp(buffer,text); + ok(result == 0, + "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); + + /* Baseline test with normal-sized buffer and carriage return */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2); + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer); + ok(result == lstrlen(buffer), + "WM_GETTEXT returned %d, expected %d\n", result, lstrlen(buffer)); + result = strcmp(buffer,text2_after); + ok(result == 0, + "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); + + /* Test for returned value of WM_GETTEXTLENGTH */ + result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); + ok(result == lstrlen(text2_after), + "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n", + result, lstrlen(text2_after)); + + /* Test for behavior of CRLF conversion in case of overflow */ + memset(buffer, 0, 1024); + result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text2), (LPARAM)buffer); + ok(result == 0, + "WM_GETTEXT returned %d, expected 0\n", result); + result = strcmp(buffer,text2); + ok(result == 0, + "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result); + DestroyWindow(hwndRichEdit); } @@ -1024,9 +1070,9 @@ static void test_WM_SETTEXT() result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) a); \ ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \ result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf); \ - ok (result == strlen(buf), \ + ok (result == lstrlen(buf), \ "WM_GETTEXT returned %ld instead of expected %u\n", \ - result, strlen(buf)); \ + result, lstrlen(buf)); \ result = strcmp(b, buf); \ ok(result == 0, \ "WM_SETTEXT round trip: strcmp = %ld\n", result); @@ -1116,6 +1162,33 @@ static void test_EM_SETTEXTEX(void) ok(strcmp((const char *)buf, TestItem2_after) == 0, "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n"); + /* Baseline test for just-enough buffer space for string */ + getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR); + getText.codepage = 1200; /* no constant for unicode */ + getText.flags = GT_DEFAULT; + getText.lpDefaultChar = NULL; + getText.lpUsedDefChar = NULL; + memset(buf, 0, MAX_BUF_LEN); + SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf); + ok(lstrcmpW(buf, TestItem2) == 0, + "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); + + /* When there is enough space for one character, but not both, of the CRLF + pair at the end of the string, the CR is not copied at all. That is, + the caller must not see CRLF pairs truncated to CR at the end of the + string. + */ + getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR); + getText.codepage = 1200; /* no constant for unicode */ + getText.flags = GT_USECRLF; /* <-- asking for CR -> CRLF conversion */ + getText.lpDefaultChar = NULL; + getText.lpUsedDefChar = NULL; + memset(buf, 0, MAX_BUF_LEN); + SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf); + ok(lstrcmpW(buf, TestItem1) == 0, + "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n"); + + /* \r\n pairs get changed into \r */ setText.codepage = 1200; /* no constant for unicode */ getText.codepage = 1200; /* no constant for unicode */ @@ -2443,8 +2516,10 @@ static void test_EM_GETTEXTLENGTHEX(void) HWND hwnd; GETTEXTLENGTHEX gtl; int ret; + const char * base_string = "base string"; const char * test_string = "a\nb\n\n\r\n"; const char * test_string_after = "a"; + const char * test_string_2 = "a\rtest\rstring"; char buffer[64] = {0}; /* single line */ @@ -2462,6 +2537,18 @@ static void test_EM_GETTEXTLENGTHEX(void) ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); ok(ret == 0, "ret %d\n",ret); + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) base_string); + + gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; + gtl.codepage = CP_ACP; + ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); + ok(ret == strlen(base_string), "ret %d\n",ret); + + gtl.flags = GTL_NUMCHARS | GTL_PRECISE; + gtl.codepage = CP_ACP; + ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); + ok(ret == strlen(base_string), "ret %d\n",ret); + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string); gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; @@ -2488,19 +2575,43 @@ static void test_EM_GETTEXTLENGTHEX(void) gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; gtl.codepage = CP_ACP; ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); - todo_wine ok(ret == 0, "ret %d\n",ret); + ok(ret == 0, "ret %d\n",ret); gtl.flags = GTL_NUMCHARS | GTL_PRECISE; gtl.codepage = CP_ACP; ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); ok(ret == 0, "ret %d\n",ret); + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) base_string); + + gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; + gtl.codepage = CP_ACP; + ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); + ok(ret == strlen(base_string), "ret %d\n",ret); + + gtl.flags = GTL_NUMCHARS | GTL_PRECISE; + gtl.codepage = CP_ACP; + ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); + ok(ret == strlen(base_string), "ret %d\n",ret); + + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string_2); + + gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; + gtl.codepage = CP_ACP; + ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); + ok(ret == strlen(test_string_2) + 2, "ret %d\n",ret); + + gtl.flags = GTL_NUMCHARS | GTL_PRECISE; + gtl.codepage = CP_ACP; + ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); + ok(ret == strlen(test_string_2), "ret %d\n",ret); + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string); gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF; gtl.codepage = CP_ACP; ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); - todo_wine ok(ret == 10, "ret %d\n",ret); + ok(ret == 10, "ret %d\n",ret); gtl.flags = GTL_NUMCHARS | GTL_PRECISE; gtl.codepage = CP_ACP; diff --git a/rostests/winetests/riched20/riched20.rbuild b/rostests/winetests/riched20/riched20.rbuild index f9fac8b44cf..86c225b7b2d 100644 --- a/rostests/winetests/riched20/riched20.rbuild +++ b/rostests/winetests/riched20/riched20.rbuild @@ -1,16 +1,17 @@ + . 0x600 0x600 + editor.c + testlist.c wine - riched20 ole32 user32 gdi32 kernel32 ntdll - editor.c - testlist.c + diff --git a/rostests/winetests/riched32/editor.c b/rostests/winetests/riched32/editor.c new file mode 100644 index 00000000000..66a30909f3e --- /dev/null +++ b/rostests/winetests/riched32/editor.c @@ -0,0 +1,166 @@ +/* +* Unit test suite for rich edit control 1.0 +* +* Copyright 2006 Google (Thomas Kho) +* Copyright 2007 Matt Finnicum +* Copyright 2007 Dmitry Timoshkov +* Copyright 2007 Alex Villacís Lasso +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static HMODULE hmoduleRichEdit; + +static HWND new_window(LPCTSTR lpClassName, DWORD dwStyle, HWND parent) { + HWND hwnd; + hwnd = CreateWindow(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL + |WS_VISIBLE, 0, 0, 200, 60, parent, NULL, + hmoduleRichEdit, NULL); + ok(hwnd != NULL, "class: %s, error: %d\n", lpClassName, (int) GetLastError()); + return hwnd; +} + +static HWND new_richedit(HWND parent) { + return new_window(RICHEDIT_CLASS10A, ES_MULTILINE, parent); +} + +static void test_WM_SETTEXT() +{ + HWND hwndRichEdit = new_richedit(NULL); + const char * TestItem1 = "TestSomeText"; + const char * TestItem2 = "TestSomeText\r"; + const char * TestItem3 = "TestSomeText\rSomeMoreText\r"; + const char * TestItem4 = "TestSomeText\n\nTestSomeText"; + const char * TestItem5 = "TestSomeText\r\r\nTestSomeText"; + const char * TestItem6 = "TestSomeText\r\r\n\rTestSomeText"; + const char * TestItem7 = "TestSomeText\r\n\r\r\n\rTestSomeText"; + const char * TestItem8 = "TestSomeText\r\n"; + const char * TestItem9 = "TestSomeText\r\nSomeMoreText\r\n"; + const char * TestItem10 = "TestSomeText\r\n\r\nTestSomeText"; + const char * TestItem11 = "TestSomeText TestSomeText"; + const char * TestItem12 = "TestSomeText \r\nTestSomeText"; + const char * TestItem13 = "TestSomeText\r\n \r\nTestSomeText"; + char buf[1024] = {0}; + LRESULT result; + + /* This test attempts to show that WM_SETTEXT on a riched32 control does not + attempt to modify the text that is pasted into the control, and should + return it as is. In particular, \r\r\n is NOT converted, unlike riched20. + Currently, builtin riched32 mangles solitary \r or \n when not part of + a \r\n pair. + */ + +#define TEST_SETTEXT(a, b, is_todo) \ + result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) a); \ + ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \ + result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf); \ + ok (result == lstrlen(buf), \ + "WM_GETTEXT returned %ld instead of expected %u\n", \ + result, lstrlen(buf)); \ + result = strcmp(b, buf); \ + if (is_todo) todo_wine { \ + ok(result == 0, \ + "WM_SETTEXT round trip: strcmp = %ld\n", result); \ + } else { \ + ok(result == 0, \ + "WM_SETTEXT round trip: strcmp = %ld\n", result); \ + } + + TEST_SETTEXT(TestItem1, TestItem1, 0) + TEST_SETTEXT(TestItem2, TestItem2, 1) + TEST_SETTEXT(TestItem3, TestItem3, 1) + TEST_SETTEXT(TestItem4, TestItem4, 1) + TEST_SETTEXT(TestItem5, TestItem5, 1) + TEST_SETTEXT(TestItem6, TestItem6, 1) + TEST_SETTEXT(TestItem7, TestItem7, 1) + TEST_SETTEXT(TestItem8, TestItem8, 0) + TEST_SETTEXT(TestItem9, TestItem9, 0) + TEST_SETTEXT(TestItem10, TestItem10, 0) + TEST_SETTEXT(TestItem11, TestItem11, 0) + TEST_SETTEXT(TestItem12, TestItem12, 0) + TEST_SETTEXT(TestItem13, TestItem13, 0) + +#undef TEST_SETTEXT + DestroyWindow(hwndRichEdit); +} + +static void test_WM_GETTEXTLENGTH(void) +{ + HWND hwndRichEdit = new_richedit(NULL); + static const char text3[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee"; + static const char text4[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n"; + int result; + + /* Test for WM_GETTEXTLENGTH */ + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text3); + result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); + ok(result == lstrlen(text3), + "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n", + result, lstrlen(text3)); + + SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text4); + result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0); + ok(result == lstrlen(text4), + "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n", + result, lstrlen(text4)); + + DestroyWindow(hwndRichEdit); +} + +START_TEST( editor ) +{ + MSG msg; + time_t end; + + /* Must explicitly LoadLibrary(). The test has no references to functions in + * RICHED32.DLL, so the linker doesn't actually link to it. */ + hmoduleRichEdit = LoadLibrary("RICHED32.DLL"); + ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError()); + + test_WM_SETTEXT(); + test_WM_GETTEXTLENGTH(); + + /* Set the environment variable WINETEST_RICHED32 to keep windows + * responsive and open for 30 seconds. This is useful for debugging. + * + * The message pump uses PeekMessage() to empty the queue and then sleeps for + * 50ms before retrying the queue. */ + end = time(NULL) + 30; + if (getenv( "WINETEST_RICHED32" )) { + while (time(NULL) < end) { + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } else { + Sleep(50); + } + } + } + + OleFlushClipboard(); + ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError()); +} diff --git a/rostests/winetests/riched32/riched32.rbuild b/rostests/winetests/riched32/riched32.rbuild new file mode 100644 index 00000000000..4c328a2301f --- /dev/null +++ b/rostests/winetests/riched32/riched32.rbuild @@ -0,0 +1,16 @@ + + + + + . + 0x600 + 0x600 + editor.c + testlist.c + wine + ole32 + user32 + kernel32 + ntdll + + diff --git a/rostests/winetests/riched32/testlist.c b/rostests/winetests/riched32/testlist.c new file mode 100644 index 00000000000..08e717eeb0d --- /dev/null +++ b/rostests/winetests/riched32/testlist.c @@ -0,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_editor(void); + +const struct test winetest_testlist[] = +{ + { "editor", func_editor }, + { 0, 0 } +}; diff --git a/rostests/winetests/rsaenh/rsaenh.c b/rostests/winetests/rsaenh/rsaenh.c index 5a7b47422c9..4fef6e9fb5b 100644 --- a/rostests/winetests/rsaenh/rsaenh.c +++ b/rostests/winetests/rsaenh/rsaenh.c @@ -175,12 +175,20 @@ static void test_prov(void) DWORD dwLen, dwInc; dwLen = (DWORD)sizeof(DWORD); + SetLastError(0xdeadbeef); result = CryptGetProvParam(hProv, PP_SIG_KEYSIZE_INC, (BYTE*)&dwInc, &dwLen, 0); - ok(result && dwInc==8, "%08x, %d\n", GetLastError(), dwInc); + if (!result && GetLastError() == NTE_BAD_TYPE) + skip("PP_SIG_KEYSIZE_INC is not supported (win9x or NT)\n"); + else + ok(result && dwInc==8, "%08x, %d\n", GetLastError(), dwInc); dwLen = (DWORD)sizeof(DWORD); + SetLastError(0xdeadbeef); result = CryptGetProvParam(hProv, PP_KEYX_KEYSIZE_INC, (BYTE*)&dwInc, &dwLen, 0); - ok(result && dwInc==8, "%08x, %d\n", GetLastError(), dwInc); + if (!result && GetLastError() == NTE_BAD_TYPE) + skip("PP_KEYX_KEYSIZE_INC is not supported (win9x or NT)\n"); + else + ok(result && dwInc==8, "%08x, %d\n", GetLastError(), dwInc); } static void test_gen_random(void) @@ -1823,9 +1831,13 @@ static void test_null_provider(void) ok(result && dataLen == sizeof(dwParam) && (dwParam & CRYPT_SEC_DESCR), "Expected CRYPT_SEC_DESCR to be set, got 0x%08X\n",dwParam); dataLen = sizeof(keySpec); + SetLastError(0xdeadbeef); result = CryptGetProvParam(prov, PP_KEYSPEC, (LPBYTE)&keySpec, &dataLen, 0); - ok(result && keySpec == (AT_KEYEXCHANGE | AT_SIGNATURE), - "Expected AT_KEYEXCHANGE | AT_SIGNATURE, got %08x\n", keySpec); + if (!result && GetLastError() == NTE_BAD_TYPE) + skip("PP_KEYSPEC is not supported (win9x or NT)\n"); + else + ok(result && keySpec == (AT_KEYEXCHANGE | AT_SIGNATURE), + "Expected AT_KEYEXCHANGE | AT_SIGNATURE, got %08x\n", keySpec); /* PP_CONTAINER parameter */ dataLen = sizeof(szName); result = CryptGetProvParam(prov, PP_CONTAINER, (LPBYTE)szName, &dataLen, 0); @@ -1834,10 +1846,14 @@ static void test_null_provider(void) (result)? "TRUE":"FALSE",GetLastError(),dataLen); /* PP_UNIQUE_CONTAINER parameter */ dataLen = sizeof(szName); + SetLastError(0xdeadbeef); result = CryptGetProvParam(prov, PP_UNIQUE_CONTAINER, (LPBYTE)szName, &dataLen, 0); - ok(result && dataLen == strlen(szContainer)+1 && strcmp(szContainer,szName) == 0, - "failed getting PP_CONTAINER. result = %s. Error 0x%08X. returned length = %d\n", - (result)? "TRUE":"FALSE",GetLastError(),dataLen); + if (!result && GetLastError() == NTE_BAD_TYPE) + skip("PP_UNIQUE_CONTAINER is not supported (win9x or NT)\n"); + else + ok(result && dataLen == strlen(szContainer)+1 && strcmp(szContainer,szName) == 0, + "failed getting PP_UNIQUE_CONTAINER. result = %s. Error 0x%08X. returned length = %d\n", + (result)? "TRUE":"FALSE",GetLastError(),dataLen); result = CryptGetUserKey(prov, AT_KEYEXCHANGE, &key); ok(!result && GetLastError() == NTE_NO_KEY, "Expected NTE_NO_KEY, got %08x\n", GetLastError()); diff --git a/rostests/winetests/rsaenh/rsaenh.rbuild b/rostests/winetests/rsaenh/rsaenh.rbuild index f8f3ad2f317..94d58ac95b8 100644 --- a/rostests/winetests/rsaenh/rsaenh.rbuild +++ b/rostests/winetests/rsaenh/rsaenh.rbuild @@ -5,11 +5,11 @@ . 0x600 0x600 + rsaenh.c + testlist.c wine advapi32 kernel32 ntdll - rsaenh.c - testlist.c diff --git a/rostests/winetests/shlwapi/generated.c b/rostests/winetests/shlwapi/generated.c index d1bfa4c8200..6d50fbcf32e 100755 --- a/rostests/winetests/shlwapi/generated.c +++ b/rostests/winetests/shlwapi/generated.c @@ -21,7 +21,7 @@ #include "wine/test.h" /*********************************************************************** - * Compability macros + * Compatibility macros */ #define DWORD_PTR UINT_PTR diff --git a/rostests/winetests/shlwapi/istream.c b/rostests/winetests/shlwapi/istream.c new file mode 100644 index 00000000000..7172e31f764 --- /dev/null +++ b/rostests/winetests/shlwapi/istream.c @@ -0,0 +1,577 @@ +/* Unit test suite for SHLWAPI ShCreateStreamOnFile functions. + * + * Copyright 2008 Reece H. Dunn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include +#include + +#include "wine/test.h" +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "shlwapi.h" + + +/* Function pointers for the SHCreateStreamOnFile functions */ +static HMODULE hShlwapi; +static HRESULT (WINAPI *pSHCreateStreamOnFileA)(LPCSTR file, DWORD mode, IStream **stream); +static HRESULT (WINAPI *pSHCreateStreamOnFileW)(LPCWSTR file, DWORD mode, IStream **stream); +static HRESULT (WINAPI *pSHCreateStreamOnFileEx)(LPCWSTR file, DWORD mode, DWORD attributes, BOOL create, IStream *template, IStream **stream); + + +static void test_IStream_invalid_operations(IStream * stream, DWORD mode) +{ + HRESULT ret; + IStream * clone; + ULONG refcount; + ULARGE_INTEGER uzero; + ULARGE_INTEGER uret; + LARGE_INTEGER zero; + ULONG count; + char data[256]; + + U(uzero).HighPart = 0; + U(uzero).LowPart = 0; + U(uret).HighPart = 0; + U(uret).LowPart = 0; + U(zero).HighPart = 0; + U(zero).LowPart = 0; + + /* IStream::Read */ + + /* IStream_Read from the COBJMACROS is undefined by shlwapi.h, replaced by the IStream_Read helper function. */ + + ret = stream->lpVtbl->Read(stream, NULL, 0, &count); + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + ret = stream->lpVtbl->Read(stream, data, 5, NULL); + ok(ret == S_FALSE || ret == S_OK, "expected S_FALSE or S_OK, got 0x%08x\n", ret); + + ret = stream->lpVtbl->Read(stream, data, 0, NULL); + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + ret = stream->lpVtbl->Read(stream, data, 3, &count); + ok(ret == S_FALSE || ret == S_OK, "expected S_FALSE or S_OK, got 0x%08x\n", ret); + + /* IStream::Write */ + + /* IStream_Write from the COBJMACROS is undefined by shlwapi.h, replaced by the IStream_Write helper function. */ + + ret = stream->lpVtbl->Write(stream, NULL, 0, &count); + if (mode == STGM_READ) + ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret); + else + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + strcpy(data, "Hello"); + ret = stream->lpVtbl->Write(stream, data, 5, NULL); + if (mode == STGM_READ) + ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret); + else + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + strcpy(data, "Hello"); + ret = stream->lpVtbl->Write(stream, data, 0, NULL); + if (mode == STGM_READ) + ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret); + else + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + strcpy(data, "Hello"); + ret = stream->lpVtbl->Write(stream, data, 0, &count); + if (mode == STGM_READ) + ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret); + else + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + strcpy(data, "Hello"); + ret = stream->lpVtbl->Write(stream, data, 3, &count); + if (mode == STGM_READ) + ok(ret == STG_E_ACCESSDENIED, "expected STG_E_ACCESSDENIED, got 0x%08x\n", ret); + else + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + /* IStream::Seek */ + + ret = IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL); + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + ret = IStream_Seek(stream, zero, 20, NULL); + ok(ret == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", ret); + + /* IStream::CopyTo */ + + ret = IStream_CopyTo(stream, NULL, uzero, &uret, &uret); + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + clone = NULL; + ret = IStream_CopyTo(stream, clone, uzero, &uret, &uret); + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + ret = IStream_CopyTo(stream, stream, uzero, &uret, &uret); + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + ret = IStream_CopyTo(stream, stream, uzero, &uret, NULL); + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + ret = IStream_CopyTo(stream, stream, uzero, NULL, &uret); + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + /* IStream::Commit */ + + ret = IStream_Commit(stream, STGC_DEFAULT); + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + /* IStream::Revert */ + + ret = IStream_Revert(stream); + ok(ret == E_NOTIMPL, "expected E_NOTIMPL, got 0x%08x\n", ret); + + /* IStream::LockRegion */ + + ret = IStream_LockRegion(stream, uzero, uzero, 0); + ok(ret == E_NOTIMPL /* XP */ || ret == S_OK /* Vista */, + "expected E_NOTIMPL or S_OK, got 0x%08x\n", ret); + + /* IStream::UnlockRegion */ + + if (ret == E_NOTIMPL) /* XP */ { + ret = IStream_UnlockRegion(stream, uzero, uzero, 0); + ok(ret == E_NOTIMPL, "expected E_NOTIMPL, got 0x%08x\n", ret); + } else /* Vista */ { + ret = IStream_UnlockRegion(stream, uzero, uzero, 0); + ok(ret == S_OK, "expected S_OK, got 0x%08x\n", ret); + + ret = IStream_UnlockRegion(stream, uzero, uzero, 0); + ok(ret == STG_E_LOCKVIOLATION, "expected STG_E_LOCKVIOLATION, got 0x%08x\n", ret); + } + + /* IStream::Stat */ + + ret = IStream_Stat(stream, NULL, 0); + ok(ret == STG_E_INVALIDPOINTER, "expected STG_E_INVALIDPOINTER, got 0x%08x\n", ret); + + /* IStream::Clone */ + + ret = IStream_Clone(stream, NULL); + ok(ret == E_NOTIMPL, "expected E_NOTIMPL, got 0x%08x\n", ret); + + clone = NULL; + ret = IStream_Clone(stream, &clone); + ok(ret == E_NOTIMPL, "expected E_NOTIMPL, got 0x%08x\n", ret); + ok(clone == NULL, "expected a NULL IStream object, got %p\n", stream); + + if (clone) { + refcount = IStream_Release(clone); + ok(refcount == 0, "expected 0, got %d\n", refcount); + } +} + + +static void test_SHCreateStreamOnFileA(DWORD mode) +{ + IStream * stream; + HRESULT ret; + ULONG refcount; + static const char * test_file = "c:\\test.txt"; + + trace("SHCreateStreamOnFileA: testing mode %d\n", mode); + + /* invalid arguments */ + + stream = NULL; + ret = (*pSHCreateStreamOnFileA)(NULL, mode, &stream); + todo_wine + ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); + +#if 0 /* This test crashes on WinXP SP2 */ + ret = (*pSHCreateStreamOnFileA)(test_file, mode, NULL); + ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret); +#endif + + stream = NULL; + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CONVERT, &stream); + ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); + + stream = NULL; + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_DELETEONRELEASE, &stream); + ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); + + stream = NULL; + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_TRANSACTED, &stream); + ok(ret == E_INVALIDARG, "SHCreateStreamOnFileA: expected E_INVALIDARG, got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); + + /* file does not exist */ + + stream = NULL; + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_FAILIFTHERE, &stream); + todo_wine + ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream); + + stream = NULL; + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CREATE, &stream); + todo_wine + ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret); + todo_wine + ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n"); + + if (stream) { + test_IStream_invalid_operations(stream, mode); + + refcount = IStream_Release(stream); + ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount); + } + + /* NOTE: don't delete the file, as it will be used for the file exists tests. */ + + /* file exists */ + + stream = NULL; + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_FAILIFTHERE, &stream); + todo_wine + ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret); + todo_wine + ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n"); + + if (stream) { + test_IStream_invalid_operations(stream, mode); + + refcount = IStream_Release(stream); + ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount); + } + + stream = NULL; + ret = (*pSHCreateStreamOnFileA)(test_file, mode | STGM_CREATE, &stream); + todo_wine + ok(ret == S_OK, "SHCreateStreamOnFileA: expected S_OK, got 0x%08x\n", ret); + todo_wine + ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n"); + + if (stream) { + test_IStream_invalid_operations(stream, mode); + + refcount = IStream_Release(stream); + ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount); + + ok(DeleteFileA(test_file), "SHCreateStreamOnFileA: could not delete file '%s', got error %d\n", test_file, GetLastError()); + } +} + + +static void test_SHCreateStreamOnFileW(DWORD mode) +{ + IStream * stream; + HRESULT ret; + ULONG refcount; + static const WCHAR test_file[] = { 'c', ':', '\\', 't', 'e', 's', 't', '.', 't', 'x', 't', '\0' }; + + trace("SHCreateStreamOnFileW: testing mode %d\n", mode); + + /* invalid arguments */ + + stream = NULL; + ret = (*pSHCreateStreamOnFileW)(NULL, mode, &stream); + ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* XP */ + ret == E_INVALIDARG /* Vista */, + "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); + +#if 0 /* This test crashes on WinXP SP2 */ + ret = (*pSHCreateStreamOnFileW)(test_file, mode, NULL); + ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); +#endif + + stream = NULL; + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CONVERT, &stream); + ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); + + stream = NULL; + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_DELETEONRELEASE, &stream); + ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); + + stream = NULL; + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_TRANSACTED, &stream); + ok(ret == E_INVALIDARG, "SHCreateStreamOnFileW: expected E_INVALIDARG, got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); + + /* file does not exist */ + + stream = NULL; + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_FAILIFTHERE, &stream); + todo_wine + ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream); + + stream = NULL; + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CREATE, &stream); + todo_wine + ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret); + todo_wine + ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n"); + + if (stream) { + test_IStream_invalid_operations(stream, mode); + + refcount = IStream_Release(stream); + ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount); + } + + /* NOTE: don't delete the file, as it will be used for the file exists tests. */ + + /* file exists */ + + stream = NULL; + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_FAILIFTHERE, &stream); + todo_wine + ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret); + todo_wine + ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n"); + + if (stream) { + test_IStream_invalid_operations(stream, mode); + + refcount = IStream_Release(stream); + ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount); + } + + stream = NULL; + ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_CREATE, &stream); + todo_wine + ok(ret == S_OK, "SHCreateStreamOnFileW: expected S_OK, got 0x%08x\n", ret); + todo_wine + ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n"); + + if (stream) { + test_IStream_invalid_operations(stream, mode); + + refcount = IStream_Release(stream); + ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount); + + ok(DeleteFileW(test_file), "SHCreateStreamOnFileW: could not delete the test file, got error %d\n", GetLastError()); + } +} + + +static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) +{ + IStream * stream; + IStream * template = NULL; + HRESULT ret; + ULONG refcount; + static const WCHAR test_file[] = { 'c', ':', '\\', 't', 'e', 's', 't', '.', 't', 'x', 't', '\0' }; + + trace("SHCreateStreamOnFileEx: testing mode %d, STGM flags %08x\n", mode, stgm); + + /* invalid arguments */ + + stream = NULL; + ret = (*pSHCreateStreamOnFileEx)(NULL, mode, 0, FALSE, NULL, &stream); + ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* XP */ + ret == E_INVALIDARG /* Vista */, + "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) or E_INVALIDARG, got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); + + stream = NULL; + ret = (*pSHCreateStreamOnFileEx)(test_file, mode, 0, FALSE, template, &stream); + todo_wine + ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); + +#if 0 /* This test crashes on WinXP SP2 */ + ret = (*pSHCreateStreamOnFileEx)(test_file, mode, 0, FALSE, NULL, NULL); + ok(ret == E_INVALIDARG, "SHCreateStreamOnFileEx: expected E_INVALIDARG, got 0x%08x\n", ret); +#endif + + /* file does not exist */ + + stream = NULL; + ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, FALSE, NULL, &stream); + if ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED && mode == STGM_READ) { + ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) /* XP */ || ret == E_INVALIDARG /* Vista */, + "SHCreateStreamOnFileEx: expected E_INVALIDARG or HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); + + if (ret == E_INVALIDARG) { + skip("SHCreateStreamOnFileEx: STGM_TRANSACTED not supported in this configuration.\n"); + return; + } + } else { + todo_wine + ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret); + } + ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); + + stream = NULL; + ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, TRUE, NULL, &stream); + todo_wine + ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); + todo_wine + ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); + + if (stream) { + test_IStream_invalid_operations(stream, mode); + + refcount = IStream_Release(stream); + ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); + + ok(DeleteFileW(test_file), "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", GetLastError()); + } + + stream = NULL; + ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream); + todo_wine + ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); + todo_wine + ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); + + if (stream) { + test_IStream_invalid_operations(stream, mode); + + refcount = IStream_Release(stream); + ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); + + ok(DeleteFileW(test_file), "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", GetLastError()); + } + + stream = NULL; + ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream); + todo_wine + ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); + todo_wine + ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); + + if (stream) { + test_IStream_invalid_operations(stream, mode); + + refcount = IStream_Release(stream); + ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); + } + + /* NOTE: don't delete the file, as it will be used for the file exists tests. */ + + /* file exists */ + + stream = NULL; + ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, FALSE, NULL, &stream); + todo_wine + ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); + todo_wine + ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); + + if (stream) { + test_IStream_invalid_operations(stream, mode); + + refcount = IStream_Release(stream); + ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); + } + + stream = NULL; + ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_FAILIFTHERE | stgm, 0, TRUE, NULL, &stream); + todo_wine + ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), got 0x%08x\n", ret); + ok(stream == NULL, "SHCreateStreamOnFileEx: expected a NULL IStream object, got %p\n", stream); + + stream = NULL; + ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream); + todo_wine + ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); + todo_wine + ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); + + if (stream) { + test_IStream_invalid_operations(stream, mode); + + refcount = IStream_Release(stream); + ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); + } + + stream = NULL; + ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream); + todo_wine + ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret); + todo_wine + ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n"); + + if (stream) { + test_IStream_invalid_operations(stream, mode); + + refcount = IStream_Release(stream); + ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); + } + + todo_wine + ok(DeleteFileW(test_file), "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", GetLastError()); +} + + +START_TEST(istream) +{ + static const DWORD stgm_access[] = { + STGM_READ, + STGM_WRITE, + STGM_READWRITE + }; + + static const DWORD stgm_flags[] = { + 0, + STGM_CONVERT, + STGM_DELETEONRELEASE, + STGM_CONVERT | STGM_DELETEONRELEASE, + STGM_TRANSACTED | STGM_CONVERT, + STGM_TRANSACTED | STGM_DELETEONRELEASE, + STGM_TRANSACTED | STGM_CONVERT | STGM_DELETEONRELEASE + }; + + int i, j; + + hShlwapi = GetModuleHandleA("shlwapi.dll"); + + pSHCreateStreamOnFileA = (void*)GetProcAddress(hShlwapi, "SHCreateStreamOnFileA"); + pSHCreateStreamOnFileW = (void*)GetProcAddress(hShlwapi, "SHCreateStreamOnFileW"); + pSHCreateStreamOnFileEx = (void*)GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx"); + + if (!pSHCreateStreamOnFileA) + skip("SHCreateStreamOnFileA not found.\n"); + + if (!pSHCreateStreamOnFileW) + skip("SHCreateStreamOnFileW not found.\n"); + + if (!pSHCreateStreamOnFileEx) + skip("SHCreateStreamOnFileEx not found.\n"); + + for (i = 0; i != sizeof(stgm_access)/sizeof(stgm_access[0]); i++) { + if (pSHCreateStreamOnFileA) + test_SHCreateStreamOnFileA(stgm_access[i]); + + if (pSHCreateStreamOnFileW) + test_SHCreateStreamOnFileW(stgm_access[i]); + + if (pSHCreateStreamOnFileEx) { + for (j = 0; j != sizeof(stgm_flags)/sizeof(stgm_flags[0]); j++) + test_SHCreateStreamOnFileEx(stgm_access[i], stgm_flags[j]); + } + } +} diff --git a/rostests/winetests/shlwapi/path.c b/rostests/winetests/shlwapi/path.c index 5fb490d0fad..b2d2a9ea7b1 100755 --- a/rostests/winetests/shlwapi/path.c +++ b/rostests/winetests/shlwapi/path.c @@ -76,11 +76,13 @@ static struct { } TEST_PATH_IS_URL[] = { {"http://foo/bar", TRUE}, {"c:\\foo\\bar", FALSE}, + {"c:/foo/bar", FALSE}, {"foo://foo/bar", TRUE}, {"foo\\bar", FALSE}, {"foo.bar", FALSE}, {"bogusscheme:", TRUE}, - {"http:partial", TRUE} + {"http:partial", TRUE}, + {"www.winehq.org", FALSE} }; struct { @@ -906,9 +908,9 @@ static void test_PathCanonicalizeA(void) lstrcpy(dest, "test"); SetLastError(0xdeadbeef); res = PathCanonicalizeA(dest, too_long); + ok(!res, "Expected failure\n"); todo_wine { - ok(!res, "Expected failure\n"); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); } ok(lstrlen(too_long) == LONG_LEN - 1, "Expected length LONG_LEN - 1, got %i\n", lstrlen(too_long)); diff --git a/rostests/winetests/shlwapi/shlwapi.rbuild b/rostests/winetests/shlwapi/shlwapi.rbuild index 205175e03ef..f6d735e0b63 100644 --- a/rostests/winetests/shlwapi/shlwapi.rbuild +++ b/rostests/winetests/shlwapi/shlwapi.rbuild @@ -5,22 +5,23 @@ . 0x600 0x600 - wine - shlwapi - advapi32 - ole32 - oleaut32 - kernel32 - uuid - ntdll clist.c clsid.c generated.c + istream.c ordinal.c path.c shreg.c string.c url.c testlist.c + wine + shlwapi + advapi32 + ole32 + oleaut32 + kernel32 + uuid + ntdll diff --git a/rostests/winetests/shlwapi/string.c b/rostests/winetests/shlwapi/string.c index b90dcc630cc..0b4f28ba29e 100755 --- a/rostests/winetests/shlwapi/string.c +++ b/rostests/winetests/shlwapi/string.c @@ -35,16 +35,24 @@ ok(ret == val, "Unexpected value of '" #expr "': " #fmt " instead of " #val "\n", ret); \ } while (0); -static HMODULE hShlwapi; -static LPSTR (WINAPI *pStrCpyNXA)(LPSTR,LPCSTR,int); -static LPWSTR (WINAPI *pStrCpyNXW)(LPWSTR,LPCWSTR,int); -static HRESULT (WINAPI *pStrRetToBSTR)(STRRET*,void*,BSTR*); +static BOOL (WINAPI *pIntlStrEqWorkerA)(BOOL,LPCSTR,LPCSTR,int); +static BOOL (WINAPI *pIntlStrEqWorkerW)(BOOL,LPCWSTR,LPCWSTR,int); static DWORD (WINAPI *pSHAnsiToAnsi)(LPCSTR,LPSTR,int); static DWORD (WINAPI *pSHUnicodeToUnicode)(LPCWSTR,LPWSTR,int); +static LPSTR (WINAPI *pStrCatBuffA)(LPSTR,LPCSTR,INT); +static LPWSTR (WINAPI *pStrCatBuffW)(LPWSTR,LPCWSTR,INT); +static LPSTR (WINAPI *pStrCpyNXA)(LPSTR,LPCSTR,int); +static LPWSTR (WINAPI *pStrCpyNXW)(LPWSTR,LPCWSTR,int); +static LPSTR (WINAPI *pStrFormatByteSize64A)(LONGLONG,LPSTR,UINT); +static LPSTR (WINAPI *pStrFormatKBSizeA)(LONGLONG,LPSTR,UINT); +static LPWSTR (WINAPI *pStrFormatKBSizeW)(LONGLONG,LPWSTR,UINT); static BOOL (WINAPI *pStrIsIntlEqualA)(BOOL,LPCSTR,LPCSTR,int); -static BOOL (WINAPI *pIntlStrEqWorkerA)(BOOL,LPCSTR,LPCSTR,int); static BOOL (WINAPI *pStrIsIntlEqualW)(BOOL,LPCWSTR,LPCWSTR,int); -static BOOL (WINAPI *pIntlStrEqWorkerW)(BOOL,LPCWSTR,LPCWSTR,int); +static HRESULT (WINAPI *pStrRetToBSTR)(STRRET*,void*,BSTR*); +static HRESULT (WINAPI *pStrRetToBufA)(STRRET*,LPCITEMIDLIST,LPSTR,UINT); +static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT); +static INT (WINAPIV *pwnsprintfA)(LPSTR,INT,LPCSTR, ...); +static INT (WINAPIV *pwnsprintfW)(LPWSTR,INT,LPCWSTR, ...); static int strcmpW(const WCHAR *str1, const WCHAR *str2) { @@ -491,9 +499,15 @@ static void test_StrFormatByteSize64A(void) char szBuff[256]; const StrFormatSizeResult* result = StrFormatSize_results; + if (!pStrFormatByteSize64A) + { + skip("StrFormatByteSize64A() is not available. Tests skipped\n"); + return; + } + while(result->value) { - StrFormatByteSize64A(result->value, szBuff, 256); + pStrFormatByteSize64A(result->value, szBuff, 256); ok(!strcmp(result->byte_size_64, szBuff), "Formatted %x%08x wrong: got %s, expected %s\n", @@ -509,9 +523,15 @@ static void test_StrFormatKBSizeW(void) char szBuff[256]; const StrFormatSizeResult* result = StrFormatSize_results; + if (!pStrFormatKBSizeW) + { + skip("StrFormatKBSizeW() is not available. Tests skipped\n"); + return; + } + while(result->value) { - StrFormatKBSizeW(result->value, szBuffW, 256); + pStrFormatKBSizeW(result->value, szBuffW, 256); WideCharToMultiByte(0,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),0,0); ok(!strcmp(result->kb_size, szBuff), "Formatted %x%08x wrong: got %s, expected %s\n", @@ -525,9 +545,15 @@ static void test_StrFormatKBSizeA(void) char szBuff[256]; const StrFormatSizeResult* result = StrFormatSize_results; + if (!pStrFormatKBSizeA) + { + skip("StrFormatKBSizeA() is not available. Tests skipped\n"); + return; + } + while(result->value) { - StrFormatKBSizeA(result->value, szBuff, 256); + pStrFormatKBSizeA(result->value, szBuff, 256); ok(!strcmp(result->kb_size, szBuff), "Formatted %x%08x wrong: got %s, expected %s\n", @@ -561,20 +587,21 @@ static void test_StrCmpA(void) ok(!ChrCmpIA('b', 'B'), "ChrCmpIA is not case-insensitive\n"); ok(ChrCmpIA('a', 'z'), "ChrCmpIA believes that a == z!\n"); - pStrIsIntlEqualA = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualA"); - pIntlStrEqWorkerA = (void *)GetProcAddress(hShlwapi, "IntlStrEqWorkerA"); - - if (!pStrIsIntlEqualA) - return; - - ok(pStrIsIntlEqualA(FALSE, str1, str2, 5), "StrIsIntlEqualA(FALSE,...) isn't case-insensitive\n"); - ok(!pStrIsIntlEqualA(TRUE, str1, str2, 5), "StrIsIntlEqualA(TRUE,...) isn't case-sensitive\n"); - - if (!pIntlStrEqWorkerA) - return; + if (pStrIsIntlEqualA) + { + ok(pStrIsIntlEqualA(FALSE, str1, str2, 5), "StrIsIntlEqualA(FALSE,...) isn't case-insensitive\n"); + ok(!pStrIsIntlEqualA(TRUE, str1, str2, 5), "StrIsIntlEqualA(TRUE,...) isn't case-sensitive\n"); + } + else + skip("StrIsIntlEqualA() is not available. Tests skipped\n"); - ok(pIntlStrEqWorkerA(FALSE, str1, str2, 5), "IntlStrEqWorkerA(FALSE,...) isn't case-insensitive\n"); - ok(!pIntlStrEqWorkerA(TRUE, str1, str2, 5), "pIntlStrEqWorkerA(TRUE,...) isn't case-sensitive\n"); + if (pIntlStrEqWorkerA) + { + ok(pIntlStrEqWorkerA(FALSE, str1, str2, 5), "IntlStrEqWorkerA(FALSE,...) isn't case-insensitive\n"); + ok(!pIntlStrEqWorkerA(TRUE, str1, str2, 5), "pIntlStrEqWorkerA(TRUE,...) isn't case-sensitive\n"); + } + else + skip("IntlStrEqWorkerA() is not available. Tests skipped\n"); } static void test_StrCmpW(void) @@ -587,20 +614,21 @@ static void test_StrCmpW(void) ok(!ChrCmpIW('b', 'B'), "ChrCmpIW is not case-insensitive\n"); ok(ChrCmpIW('a', 'z'), "ChrCmpIW believes that a == z!\n"); - pStrIsIntlEqualW = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualW"); - pIntlStrEqWorkerW = (void *)GetProcAddress(hShlwapi, "IntlStrEqWorkerW"); - - if (!pStrIsIntlEqualW) - return; - - ok(pStrIsIntlEqualW(FALSE, str1, str2, 5), "StrIsIntlEqualW(FALSE,...) isn't case-insensitive\n"); - ok(!pStrIsIntlEqualW(TRUE, str1, str2, 5), "StrIsIntlEqualW(TRUE,...) isn't case-sensitive\n"); - - if (!pIntlStrEqWorkerW) - return; + if (pStrIsIntlEqualW) + { + ok(pStrIsIntlEqualW(FALSE, str1, str2, 5), "StrIsIntlEqualW(FALSE,...) isn't case-insensitive\n"); + ok(!pStrIsIntlEqualW(TRUE, str1, str2, 5), "StrIsIntlEqualW(TRUE,...) isn't case-sensitive\n"); + } + else + skip("StrIsIntlEqualW() is not available. Tests skipped\n"); - ok(pIntlStrEqWorkerW(FALSE, str1, str2, 5), "IntlStrEqWorkerW(FALSE,...) isn't case-insensitive\n"); - ok(!pIntlStrEqWorkerW(TRUE, str1, str2, 5), "IntlStrEqWorkerW(TRUE,...) isn't case-sensitive\n"); + if (pIntlStrEqWorkerW) + { + ok(pIntlStrEqWorkerW(FALSE, str1, str2, 5), "IntlStrEqWorkerW(FALSE,...) isn't case-insensitive\n"); + ok(!pIntlStrEqWorkerW(TRUE, str1, str2, 5), "IntlStrEqWorkerW(TRUE,...) isn't case-sensitive\n"); + } + else + skip("IntlStrEqWorkerW() is not available. Tests skipped\n"); } static WCHAR *CoDupStrW(const char* src) @@ -619,8 +647,11 @@ static void test_StrRetToBSTR(void) STRRET strret; HRESULT ret; - pStrRetToBSTR = (void *)GetProcAddress(hShlwapi, "StrRetToBSTR"); - if (!pStrRetToBSTR) return; + if (!pStrRetToBSTR) + { + skip("StrRetToBSTR() is not available. Tests skipped\n"); + return; + } strret.uType = STRRET_WSTR; U(strret).pOleStr = CoDupStrW("Test"); @@ -657,9 +688,11 @@ static void test_StrCpyNXA(void) LPSTR lpszRes; char dest[8]; - pStrCpyNXA = (void *)GetProcAddress(hShlwapi, (LPSTR)399); if (!pStrCpyNXA) + { + skip("StrCpyNXA() is not available. Tests skipped\n"); return; + } memset(dest, '\n', sizeof(dest)); lpszRes = pStrCpyNXA(dest, lpSrc, sizeof(dest)/sizeof(dest[0])); @@ -676,14 +709,16 @@ static void test_StrCpyNXW(void) LPWSTR lpszRes; WCHAR dest[8]; - pStrCpyNXW = (void *)GetProcAddress(hShlwapi, (LPSTR)400); if (!pStrCpyNXW) + { + skip("StrCpyNXW() is not available. Tests skipped\n"); return; + } memcpy(dest, lpInit, sizeof(lpInit)); lpszRes = pStrCpyNXW(dest, lpSrc, sizeof(dest)/sizeof(dest[0])); ok(lpszRes == dest + 5 && !memcmp(dest, lpRes, sizeof(dest)), - "StrCpyNXA: expected %p, \"hello\\0\\n\\n\", got %p, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n", + "StrCpyNXW: expected %p, \"hello\\0\\n\\n\", got %p, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n", dest + 5, lpszRes, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); } @@ -731,9 +766,11 @@ static void test_SHAnsiToAnsi(void) char dest[8]; DWORD dwRet; - pSHAnsiToAnsi = (void *)GetProcAddress(hShlwapi, (LPSTR)345); if (!pSHAnsiToAnsi) + { + skip("SHAnsiToAnsi() is not available. Tests skipped\n"); return; + } memset(dest, '\n', sizeof(dest)); dwRet = pSHAnsiToAnsi("hello", dest, sizeof(dest)/sizeof(dest[0])); @@ -750,9 +787,11 @@ static void test_SHUnicodeToUnicode(void) WCHAR dest[8]; DWORD dwRet; - pSHUnicodeToUnicode = (void *)GetProcAddress(hShlwapi, (LPSTR)346); if (!pSHUnicodeToUnicode) + { + skip("SHUnicodeToUnicode() is not available. Tests skipped\n"); return; + } memcpy(dest, lpInit, sizeof(lpInit)); dwRet = pSHUnicodeToUnicode(lpSrc, dest, sizeof(dest)/sizeof(dest[0])); @@ -782,46 +821,80 @@ static void test_StrXXX_overflows(void) expect_eq(StrCpyNA(buf, str1, 10), buf, PCHAR, "%p"); expect_eq(buf[9], 0, CHAR, "%x"); expect_eq(buf[10], '\xbf', CHAR, "%x"); - expect_eq(StrCatBuffA(buf, str1, 100), buf, PCHAR, "%p"); - expect_eq(buf[99], 0, CHAR, "%x"); - expect_eq(buf[100], '\xbf', CHAR, "%x"); + + if (pStrCatBuffA) + { + expect_eq(pStrCatBuffA(buf, str1, 100), buf, PCHAR, "%p"); + expect_eq(buf[99], 0, CHAR, "%x"); + expect_eq(buf[100], '\xbf', CHAR, "%x"); + } + else + skip("StrCatBuffA() is not available. Tests skipped\n"); memset(wbuf, 0xbf, sizeof(wbuf)); expect_eq(StrCpyNW(wbuf, wstr1, 10), wbuf, PWCHAR, "%p"); expect_eq(wbuf[9], 0, WCHAR, "%x"); expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x"); - expect_eq(StrCatBuffW(wbuf, wstr1, 100), wbuf, PWCHAR, "%p"); - expect_eq(wbuf[99], 0, WCHAR, "%x"); - expect_eq(wbuf[100], (WCHAR)0xbfbf, WCHAR, "%x"); - memset(wbuf, 0xbf, sizeof(wbuf)); - strret.uType = STRRET_WSTR; - U(strret).pOleStr = StrDupW(wstr1); - expect_eq(StrRetToBufW(&strret, NULL, wbuf, 10), S_OK, HRESULT, "%x"); - expect_eq(wbuf[9], 0, WCHAR, "%x"); - expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x"); + if (pStrCatBuffW) + { + expect_eq(pStrCatBuffW(wbuf, wstr1, 100), wbuf, PWCHAR, "%p"); + expect_eq(wbuf[99], 0, WCHAR, "%x"); + expect_eq(wbuf[100], (WCHAR)0xbfbf, WCHAR, "%x"); + } + else + skip("StrCatBuffW() is not available. Tests skipped\n"); - memset(buf, 0xbf, sizeof(buf)); - strret.uType = STRRET_CSTR; - StrCpyN(U(strret).cStr, str1, MAX_PATH); - expect_eq(StrRetToBufA(&strret, NULL, buf, 10), S_OK, HRESULT, "%x"); - expect_eq(buf[9], 0, CHAR, "%x"); - expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x"); + if (pStrRetToBufW) + { + memset(wbuf, 0xbf, sizeof(wbuf)); + strret.uType = STRRET_WSTR; + U(strret).pOleStr = StrDupW(wstr1); + expect_eq(pStrRetToBufW(&strret, NULL, wbuf, 10), S_OK, HRESULT, "%x"); + expect_eq(wbuf[9], 0, WCHAR, "%x"); + expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x"); + } + else + skip("StrRetToBufW() is not available. Tests skipped\n"); - memset(buf, 0xbf, sizeof(buf)); - ret = wnsprintfA(buf, 10, "%s", str1); - todo_wine ok(ret == 9, "Unexpected wsnprintfA return %d, expected 9\n", ret); - expect_eq(buf[9], 0, CHAR, "%x"); - expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x"); - memset(wbuf, 0xbf, sizeof(wbuf)); - ret = wnsprintfW(wbuf, 10, fmt, wstr1); - todo_wine ok(ret == 9, "Unexpected wsnprintfW return %d, expected 9\n", ret); - expect_eq(wbuf[9], 0, WCHAR, "%x"); - expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x"); + if (pStrRetToBufA) + { + memset(buf, 0xbf, sizeof(buf)); + strret.uType = STRRET_CSTR; + StrCpyN(U(strret).cStr, str1, MAX_PATH); + expect_eq(pStrRetToBufA(&strret, NULL, buf, 10), S_OK, HRESULT, "%x"); + expect_eq(buf[9], 0, CHAR, "%x"); + expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x"); + } + else + skip("StrRetToBufA() is not available. Tests skipped\n"); + + if (pwnsprintfA) + { + memset(buf, 0xbf, sizeof(buf)); + ret = pwnsprintfA(buf, 10, "%s", str1); + todo_wine ok(ret == 9, "Unexpected wsnprintfA return %d, expected 9\n", ret); + expect_eq(buf[9], 0, CHAR, "%x"); + expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x"); + } + else + skip("wnsprintfA() is not available. Tests skipped\n"); + + if (pwnsprintfW) + { + memset(wbuf, 0xbf, sizeof(wbuf)); + ret = pwnsprintfW(wbuf, 10, fmt, wstr1); + todo_wine ok(ret == 9, "Unexpected wsnprintfW return %d, expected 9\n", ret); + expect_eq(wbuf[9], 0, WCHAR, "%x"); + expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x"); + } + else + skip("wnsprintfW() is not available. Tests skipped\n"); } START_TEST(string) { + HMODULE hShlwapi; TCHAR thousandDelim[8]; TCHAR decimalDelim[8]; CoInitialize(0); @@ -830,6 +903,24 @@ START_TEST(string) GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimalDelim, 8); hShlwapi = GetModuleHandleA("shlwapi"); + pIntlStrEqWorkerA = (void *)GetProcAddress(hShlwapi, "IntlStrEqWorkerA"); + pIntlStrEqWorkerW = (void *)GetProcAddress(hShlwapi, "IntlStrEqWorkerW"); + pSHAnsiToAnsi = (void *)GetProcAddress(hShlwapi, (LPSTR)345); + pSHUnicodeToUnicode = (void *)GetProcAddress(hShlwapi, (LPSTR)346); + pStrCatBuffA = (void *)GetProcAddress(hShlwapi, "StrCatBuffA"); + pStrCatBuffW = (void *)GetProcAddress(hShlwapi, "StrCatBuffW"); + pStrCpyNXA = (void *)GetProcAddress(hShlwapi, (LPSTR)399); + pStrCpyNXW = (void *)GetProcAddress(hShlwapi, (LPSTR)400); + pStrFormatByteSize64A = (void *)GetProcAddress(hShlwapi, "StrFormatByteSize64A"); + pStrFormatKBSizeA = (void *)GetProcAddress(hShlwapi, "StrFormatKBSizeA"); + pStrFormatKBSizeW = (void *)GetProcAddress(hShlwapi, "StrFormatKBSizeW"); + pStrIsIntlEqualA = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualA"); + pStrIsIntlEqualW = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualW"); + pStrRetToBSTR = (void *)GetProcAddress(hShlwapi, "StrRetToBSTR"); + pStrRetToBufA = (void *)GetProcAddress(hShlwapi, "StrRetToBufA"); + pStrRetToBufW = (void *)GetProcAddress(hShlwapi, "StrRetToBufW"); + pwnsprintfA = (void *)GetProcAddress(hShlwapi, "wnsprintfA"); + pwnsprintfW = (void *)GetProcAddress(hShlwapi, "wnsprintfW"); test_StrChrA(); test_StrChrW(); diff --git a/rostests/winetests/shlwapi/testlist.c b/rostests/winetests/shlwapi/testlist.c index c34cd62b55a..dec5a258ff7 100755 --- a/rostests/winetests/shlwapi/testlist.c +++ b/rostests/winetests/shlwapi/testlist.c @@ -9,6 +9,7 @@ extern void func_clist(void); extern void func_clsid(void); extern void func_generated(void); +extern void func_istream(void); extern void func_ordinal(void); extern void func_path(void); extern void func_shreg(void); @@ -20,6 +21,7 @@ const struct test winetest_testlist[] = { "clist", func_clist }, { "clsid", func_clsid }, { "generated", func_generated }, + { "istream", func_istream }, { "ordinal", func_ordinal }, { "path", func_path }, { "shreg", func_shreg }, diff --git a/rostests/winetests/shlwapi/url.c b/rostests/winetests/shlwapi/url.c index 87b8b1de09e..2d63a216f61 100644 --- a/rostests/winetests/shlwapi/url.c +++ b/rostests/winetests/shlwapi/url.c @@ -206,6 +206,7 @@ static const TEST_URL_COMBINE TEST_COMBINE[] = { {"http://www.winehq.org/tests/../tests/", "/tests10/..", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests10/.."}, {"http://www.winehq.org/tests/../", "tests11", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../tests11"}, {"file:///C:\\dir\\file.txt", "test.txt", 0, S_OK, "file:///C:/dir/test.txt"}, + {"C:\\winehq\\winehq.txt", "C:\\Test\\test.txt", 0, S_OK, "file:///C:/Test/test.txt"}, {"http://www.winehq.org/test/", "test%20file.txt", 0, S_OK, "http://www.winehq.org/test/test%20file.txt"}, {"http://www.winehq.org/test/", "test%20file.txt", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org/test/test%20file.txt"}, {"http://www.winehq.org%2ftest/", "test%20file.txt", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org%2ftest/test%20file.txt"}, diff --git a/rostests/winetests/urlmon/generated.c b/rostests/winetests/urlmon/generated.c index 99bec8140b5..d29c226ca17 100644 --- a/rostests/winetests/urlmon/generated.c +++ b/rostests/winetests/urlmon/generated.c @@ -19,7 +19,7 @@ #include "wine/test.h" /*********************************************************************** - * Compability macros + * Compatibility macros */ #define DWORD_PTR UINT_PTR diff --git a/rostests/winetests/urlmon/misc.c b/rostests/winetests/urlmon/misc.c index ba36d8ac300..96612b076df 100644 --- a/rostests/winetests/urlmon/misc.c +++ b/rostests/winetests/urlmon/misc.c @@ -18,6 +18,7 @@ #define COBJMACROS #define CONST_VTABLE +#define NONAMELESSUNION #include #include @@ -249,7 +250,7 @@ static void test_RegisterFormatEnumerator(void) static const WCHAR url1[] = {'r','e','s',':','/','/','m','s','h','t','m','l','.','d','l','l', '/','b','l','a','n','k','.','h','t','m',0}; static const WCHAR url2[] = {'i','n','d','e','x','.','h','t','m',0}; -static const WCHAR url3[] = {'f','i','l','e',':','c',':','\\','I','n','d','e','x','.','h','t','m',0}; +static const WCHAR url3[] = {'f','i','l','e',':','/','/','c',':','\\','I','n','d','e','x','.','h','t','m',0}; static const WCHAR url4[] = {'f','i','l','e',':','s','o','m','e','%','2','0','f','i','l','e', '%','2','e','j','p','g',0}; static const WCHAR url5[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q', @@ -258,7 +259,11 @@ static const WCHAR url6[] = {'a','b','o','u','t',':','b','l','a','n','k',0}; static const WCHAR url7[] = {'f','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g','/', 'f','i','l','e','.','t','e','s','t',0}; static const WCHAR url8[] = {'t','e','s','t',':','1','2','3','a','b','c',0}; - +static const WCHAR url9[] = + {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g', + '/','s','i','t','e','/','a','b','o','u','t',0}; +static const WCHAR url10[] = {'f','i','l','e',':','/','/','s','o','m','e','%','2','0','f','i','l','e', + '.','j','p','g',0}; static const WCHAR url4e[] = {'f','i','l','e',':','s','o','m','e',' ','f','i','l','e', '.','j','p','g',0}; @@ -417,6 +422,7 @@ static const WCHAR mimeAppPdf[] = {'a','p','p','l','i','c','a','t','i','o','n',' static const WCHAR mimeAppXMSDownload[] = {'a','p','p','l','i','c','a','t','i','o','n','/','x','-','m','s','d','o','w','n','l','o','a','d',0}; static const WCHAR mimeAudioWav[] = {'a','u','d','i','o','/','w','a','v',0}; +static const WCHAR mimeAudioBasic[] = {'a','u','d','i','o','/','b','a','s','i','c',0}; static const struct { LPCWSTR url; @@ -513,6 +519,10 @@ static BYTE data78[] = {'R','I','F','F',0xff,0xff,0xff,0xff,'<','h','t','m','l', static BYTE data79[] = {'%','!',0xff}; static BYTE data80[] = {'%','!'}; static BYTE data81[] = {'%','!','P','S','<','h','t','m','l','>'}; +static BYTE data82[] = {'.','s','n','d',0}; +static BYTE data83[] = {'.','s','n','d'}; +static BYTE data84[] = {'.','s','n','d',0,'<','h','t','m','l','>',1,1}; +static BYTE data85[] = {'.','S','N','D',0}; static const struct { BYTE *data; @@ -599,7 +609,11 @@ static const struct { {data78, sizeof(data78), mimeTextHtml}, {data79, sizeof(data79), mimeAppPostscript}, {data80, sizeof(data80), mimeTextPlain}, - {data81, sizeof(data81), mimeTextHtml} + {data81, sizeof(data81), mimeTextHtml}, + {data82, sizeof(data82), mimeAudioBasic}, + {data83, sizeof(data83), mimeTextPlain}, + {data84, sizeof(data84), mimeTextHtml}, + {data85, sizeof(data85), mimeTextPlain} }; static void test_FindMimeFromData(void) @@ -700,12 +714,13 @@ static void test_FindMimeFromData(void) } static const BYTE secid1[] = {'f','i','l','e',':',0,0,0,0}; -static const BYTE secid4[] ={'f','i','l','e',':',3,0,0,0}; static const BYTE secid5[] = {'h','t','t','p',':','w','w','w','.','w','i','n','e','h','q', '.','o','r','g',3,0,0,0}; static const BYTE secid6[] = {'a','b','o','u','t',':','b','l','a','n','k',3,0,0,0}; static const BYTE secid7[] = {'f','t','p',':','w','i','n','e','h','q','.','o','r','g', 3,0,0,0}; +static const BYTE secid10[] = + {'f','i','l','e',':','s','o','m','e','%','2','0','f','i','l','e','.','j','p','g',3,0,0,0}; static struct secmgr_test { LPCWSTR url; @@ -718,7 +733,7 @@ static struct secmgr_test { {url1, 0, S_OK, sizeof(secid1), secid1, S_OK}, {url2, 100, 0x80041001, 0, NULL, E_INVALIDARG}, {url3, 0, S_OK, sizeof(secid1), secid1, S_OK}, - {url4, 3, S_OK, sizeof(secid4), secid4, S_OK}, + {url10,3, S_OK, sizeof(secid10),secid10,S_OK}, {url5, 3, S_OK, sizeof(secid5), secid5, S_OK}, {url6, 3, S_OK, sizeof(secid6), secid6, S_OK}, {url7, 3, S_OK, sizeof(secid7), secid7, S_OK} @@ -729,7 +744,7 @@ static void test_SecurityManager(void) int i; IInternetSecurityManager *secmgr = NULL; BYTE buf[512]; - DWORD zone, size; + DWORD zone, size, policy; HRESULT hres; hres = CoInternetCreateSecurityManager(NULL, &secmgr, 0); @@ -741,7 +756,8 @@ static void test_SecurityManager(void) zone = 100; hres = IInternetSecurityManager_MapUrlToZone(secmgr, secmgr_tests[i].url, &zone, 0); - ok(hres == secmgr_tests[i].zone_hres, + ok(hres == secmgr_tests[i].zone_hres /* IE <=6 */ + || (FAILED(secmgr_tests[i].zone_hres) && hres == E_INVALIDARG), /* IE7 */ "[%d] MapUrlToZone failed: %08x, expected %08x\n", i, hres, secmgr_tests[i].zone_hres); if(SUCCEEDED(hres)) @@ -782,7 +798,101 @@ static void test_SecurityManager(void) ok(hres == E_INVALIDARG, "GetSecurityId failed: %08x, expected E_INVALIDARG\n", hres); + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, NULL, URLACTION_SCRIPT_RUN, (BYTE*)&policy, + sizeof(WCHAR), NULL, 0, 0, 0); + ok(hres == E_INVALIDARG, "ProcessUrlAction failed: %08x, expected E_INVALIDARG\n", hres); + + IInternetSecurityManager_Release(secmgr); +} + +static void test_url_action(IInternetSecurityManager *secmgr, IInternetZoneManager *zonemgr, DWORD action) +{ + DWORD res, size, policy, reg_policy; + char buf[10]; + HKEY hkey; + HRESULT hres; + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3", &hkey); + if(res != ERROR_SUCCESS) { + ok(0, "Could not open zone key\n"); + return; + } + + wsprintf(buf, "%X", action); + size = sizeof(DWORD); + res = RegQueryValueExA(hkey, buf, NULL, NULL, (BYTE*)®_policy, &size); + RegCloseKey(hkey); + if(res != ERROR_SUCCESS || size != sizeof(DWORD)) { + policy = 0xdeadbeef; + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url9, action, (BYTE*)&policy, + sizeof(WCHAR), NULL, 0, 0, 0); + ok(hres == E_FAIL, "ProcessUrlAction(%x) failed: %08x, expected E_FAIL\n", action, hres); + ok(policy == 0xdeadbeef, "(%x) policy=%x\n", action, policy); + + policy = 0xdeadbeef; + hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, action, (BYTE*)&policy, + sizeof(DWORD), URLZONEREG_DEFAULT); + ok(hres == E_FAIL, "GetZoneActionPolicy failed: %08x, expected E_FAIL\n", hres); + ok(policy == 0xdeadbeef, "(%x) policy=%x\n", action, policy); + return; + } + + policy = 0xdeadbeef; + hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, action, (BYTE*)&policy, + sizeof(DWORD), URLZONEREG_DEFAULT); + ok(hres == S_OK, "GetZoneActionPolicy failed: %08x\n", hres); + ok(policy == reg_policy, "(%x) policy=%x, expected %x\n", action, policy, reg_policy); + + if(policy != URLPOLICY_QUERY) { + policy = 0xdeadbeef; + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url9, action, (BYTE*)&policy, + sizeof(WCHAR), NULL, 0, 0, 0); + if(reg_policy == URLPOLICY_DISALLOW) + ok(hres == S_FALSE, "ProcessUrlAction(%x) failed: %08x, expected S_FALSE\n", action, hres); + else + ok(hres == S_OK, "ProcessUrlAction(%x) failed: %08x\n", action, hres); + ok(policy == 0xdeadbeef, "(%x) policy=%x\n", action, policy); + } +} + +static void test_special_url_action(IInternetSecurityManager *secmgr, IInternetZoneManager *zonemgr, DWORD action) +{ + DWORD policy; + HRESULT hres; + + policy = 0xdeadbeef; + hres = IInternetZoneManager_GetZoneActionPolicy(zonemgr, 3, action, (BYTE*)&policy, + sizeof(DWORD), URLZONEREG_DEFAULT); + ok(hres == S_OK, "GetZoneActionPolicy failed: %08x\n", hres); + ok(policy == URLPOLICY_DISALLOW, "(%x) policy=%x, expected URLPOLIVY_DISALLOW\n", action, policy); + + policy = 0xdeadbeef; + hres = IInternetSecurityManager_ProcessUrlAction(secmgr, url1, action, (BYTE*)&policy, + sizeof(WCHAR), NULL, 0, 0, 0); + ok(hres == S_FALSE, "ProcessUrlAction(%x) failed: %08x, expected S_FALSE\n", action, hres); +} + +static void test_polices(void) +{ + IInternetZoneManager *zonemgr = NULL; + IInternetSecurityManager *secmgr = NULL; + HRESULT hres; + + hres = CoInternetCreateSecurityManager(NULL, &secmgr, 0); + ok(hres == S_OK, "CoInternetCreateSecurityManager failed: %08x\n", hres); + hres = CoInternetCreateZoneManager(NULL, &zonemgr, 0); + ok(hres == S_OK, "CoInternetCreateZoneManager failed: %08x\n", hres); + + test_url_action(secmgr, zonemgr, URLACTION_SCRIPT_RUN); + test_url_action(secmgr, zonemgr, URLACTION_ACTIVEX_OVERRIDE_OBJECT_SAFETY); + test_url_action(secmgr, zonemgr, URLACTION_CHANNEL_SOFTDIST_PERMISSIONS); + test_url_action(secmgr, zonemgr, 0xdeadbeef); + + test_special_url_action(secmgr, zonemgr, URLACTION_SCRIPT_OVERRIDE_SAFETY); + IInternetSecurityManager_Release(secmgr); + IInternetZoneManager_Release(zonemgr); } static void test_ZoneManager(void) @@ -1174,6 +1284,50 @@ static void test_ReleaseBindInfo(void) ok(bi.pUnk == &unk, "bi.pUnk=%p, expected %p\n", bi.pUnk, &unk); } +static void test_CopyStgMedium(void) +{ + STGMEDIUM src, dst; + HRESULT hres; + + static WCHAR fileW[] = {'f','i','l','e',0}; + + memset(&src, 0xf0, sizeof(src)); + memset(&dst, 0xe0, sizeof(dst)); + src.tymed = TYMED_NULL; + src.pUnkForRelease = NULL; + hres = CopyStgMedium(&src, &dst); + ok(hres == S_OK, "CopyStgMedium failed: %08x\n", hres); + ok(dst.tymed == TYMED_NULL, "tymed=%d\n", dst.tymed); + ok(dst.u.hGlobal == (void*)0xf0f0f0f0, "u=%p\n", dst.u.hGlobal); + ok(!dst.pUnkForRelease, "pUnkForRelease=%p, expected NULL\n", dst.pUnkForRelease); + + memset(&dst, 0xe0, sizeof(dst)); + src.tymed = TYMED_ISTREAM; + src.u.pstm = NULL; + src.pUnkForRelease = NULL; + hres = CopyStgMedium(&src, &dst); + ok(hres == S_OK, "CopyStgMedium failed: %08x\n", hres); + ok(dst.tymed == TYMED_ISTREAM, "tymed=%d\n", dst.tymed); + ok(!dst.u.pstm, "pstm=%p\n", dst.u.pstm); + ok(!dst.pUnkForRelease, "pUnkForRelease=%p, expected NULL\n", dst.pUnkForRelease); + + memset(&dst, 0xe0, sizeof(dst)); + src.tymed = TYMED_FILE; + src.u.lpszFileName = fileW; + src.pUnkForRelease = NULL; + hres = CopyStgMedium(&src, &dst); + ok(hres == S_OK, "CopyStgMedium failed: %08x\n", hres); + ok(dst.tymed == TYMED_FILE, "tymed=%d\n", dst.tymed); + ok(dst.u.lpszFileName && dst.u.lpszFileName != fileW, "lpszFileName=%p\n", dst.u.lpszFileName); + ok(!lstrcmpW(dst.u.lpszFileName, fileW), "wrong file name\n"); + ok(!dst.pUnkForRelease, "pUnkForRelease=%p, expected NULL\n", dst.pUnkForRelease); + + hres = CopyStgMedium(&src, NULL); + ok(hres == E_POINTER, "CopyStgMedium failed: %08x, expected E_POINTER\n", hres); + hres = CopyStgMedium(NULL, &dst); + ok(hres == E_POINTER, "CopyStgMedium failed: %08x, expected E_POINTER\n", hres); +} + static void test_UrlMkGetSessionOption(void) { DWORD encoding, size; @@ -1271,6 +1425,54 @@ static void test_ObtainUserAgentString(void) HeapFree(GetProcessHeap(), 0, str2); } +static void test_MkParseDisplayNameEx(void) +{ + IMoniker *mon = NULL; + LPWSTR name; + DWORD issys; + ULONG eaten = 0; + IBindCtx *bctx; + HRESULT hres; + + static const WCHAR clsid_nameW[] = {'c','l','s','i','d',':', + '2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8', + '-','0','8','0','0','2','B','3','0','3','0','9','D',':',0}; + + CreateBindCtx(0, &bctx); + + hres = MkParseDisplayNameEx(bctx, url9, &eaten, &mon); + ok(hres == S_OK, "MkParseDisplayNameEx failed: %08x\n", hres); + ok(eaten == sizeof(url9)/sizeof(WCHAR)-1, "eaten=%d\n", eaten); + ok(mon != NULL, "mon == NULL\n"); + + hres = IMoniker_GetDisplayName(mon, NULL, 0, &name); + ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres); + ok(!lstrcmpW(name, url9), "wrong display name %s\n", debugstr_w(name)); + CoTaskMemFree(name); + + hres = IMoniker_IsSystemMoniker(mon, &issys); + ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres); + ok(issys == MKSYS_URLMONIKER, "issys=%x\n", issys); + + IMoniker_Release(mon); + + hres = MkParseDisplayNameEx(bctx, clsid_nameW, &eaten, &mon); + ok(hres == S_OK, "MkParseDisplayNameEx failed: %08x\n", hres); + ok(eaten == sizeof(clsid_nameW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten); + ok(mon != NULL, "mon == NULL\n"); + + hres = IMoniker_IsSystemMoniker(mon, &issys); + ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres); + ok(issys == MKSYS_CLASSMONIKER, "issys=%x\n", issys); + + IMoniker_Release(mon); + + hres = MkParseDisplayNameEx(bctx, url8, &eaten, &mon); + ok(FAILED(hres), "MkParseDisplayNameEx succeeded: %08x\n", hres); + + IBindCtx_Release(bctx); +} + START_TEST(misc) { OleInitialize(NULL); @@ -1284,12 +1486,15 @@ START_TEST(misc) test_CoInternetQueryInfo(); test_FindMimeFromData(); test_SecurityManager(); + test_polices(); test_ZoneManager(); test_NameSpace(); test_MimeFilter(); test_ReleaseBindInfo(); + test_CopyStgMedium(); test_UrlMkGetSessionOption(); test_ObtainUserAgentString(); + test_MkParseDisplayNameEx(); OleUninitialize(); } diff --git a/rostests/winetests/urlmon/protocol.c b/rostests/winetests/urlmon/protocol.c index fd92171e10d..c21134b0280 100644 --- a/rostests/winetests/urlmon/protocol.c +++ b/rostests/winetests/urlmon/protocol.c @@ -36,17 +36,16 @@ #define SET_EXPECT(func) \ expect_ ## func = TRUE -#define CHECK_EXPECT(func) \ +#define CHECK_EXPECT2(func) \ do { \ - ok(expect_ ##func, "unexpected call " #func "\n"); \ - expect_ ## func = FALSE; \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ called_ ## func = TRUE; \ }while(0) -#define CHECK_EXPECT2(func) \ +#define CHECK_EXPECT(func) \ do { \ - ok(expect_ ##func, "unexpected call " #func "\n"); \ - called_ ## func = TRUE; \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ }while(0) #define CHECK_CALLED(func) \ @@ -357,6 +356,8 @@ static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOL CHECK_CALLED(ReportProgress_SENDINGREQUEST); SET_EXPECT(OnResponse); SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE); + if(bindf & BINDF_NEEDFILE) + SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE); } SET_EXPECT(ReportData); @@ -368,6 +369,8 @@ static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOL state = 1; CHECK_CALLED(OnResponse); CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE); + if(bindf & BINDF_NEEDFILE) + CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE); } SetEvent(event_complete); @@ -423,8 +426,10 @@ static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, if(szStatusText) { if(binding_test) ok(szStatusText == expect_wsz, "unexpected szStatusText\n"); + else if(tested_protocol == FILE_TEST) + ok(!lstrcmpW(szStatusText, file_name), "szStatusText = \"%s\"\n", debugstr_w(szStatusText)); else - ok(!lstrcmpW(szStatusText, file_name), "szStatusText != file_name\n"); + ok(szStatusText != NULL, "szStatusText == NULL\n"); } break; case BINDSTATUS_FINDINGRESOURCE: @@ -1408,6 +1413,8 @@ static void test_file_protocol(void) { test_file_protocol_url(index_url); bindf = BINDF_FROMURLMON; test_file_protocol_url(index_url); + bindf = BINDF_FROMURLMON | BINDF_NEEDFILE; + test_file_protocol_url(index_url); memcpy(buf, wszFile, sizeof(wszFile)); len = sizeof(wszFile)/sizeof(WCHAR)-1; @@ -1639,11 +1646,15 @@ static void test_http_protocol(void) bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON; test_http_protocol_url(winehq_url, FALSE); + trace("Testing http protocol (to file)...\n"); + bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NEEDFILE; + test_http_protocol_url(winehq_url, FALSE); + trace("Testing http protocol (post data)...\n"); http_post_test = TRUE; /* Without this flag we get a ReportProgress_CACHEFILENAMEAVAILABLE * notification with BINDVERB_POST */ - bindf |= BINDF_NOWRITECACHE; + bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA | BINDF_FROMURLMON | BINDF_NOWRITECACHE; test_http_protocol_url(posttest_url, TRUE); http_post_test = FALSE; } @@ -1700,7 +1711,7 @@ static void test_mk_protocol(void) ok(hres == INET_E_RESOURCE_NOT_FOUND, "Start failed: %08x, expected INET_E_RESOURCE_NOT_FOUND\n", hres); CHECK_CALLED(GetBindInfo); - CHECK_CALLED(ReportProgress_DIRECTBIND); + CLEAR_CALLED(ReportProgress_DIRECTBIND); CHECK_CALLED(ReportProgress_SENDINGREQUEST); CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE); CHECK_CALLED(ReportResult); diff --git a/rostests/winetests/urlmon/stream.c b/rostests/winetests/urlmon/stream.c index 12133f9e730..72a1d43c61c 100644 --- a/rostests/winetests/urlmon/stream.c +++ b/rostests/winetests/urlmon/stream.c @@ -167,7 +167,7 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP ok(szStatusText != NULL, "szStatusText == NULL\n"); break; default: - todo_wine { ok(0, "unexpexted code %d\n", ulStatusCode); } + todo_wine { ok(0, "unexpected code %d\n", ulStatusCode); } }; return S_OK; } diff --git a/rostests/winetests/urlmon/url.c b/rostests/winetests/urlmon/url.c index 8ac533a6768..5c8505c88e5 100644 --- a/rostests/winetests/urlmon/url.c +++ b/rostests/winetests/urlmon/url.c @@ -23,6 +23,7 @@ #include #define COBJMACROS +#define NONAMELESSUNION #define CONST_VTABLE #include "windef.h" @@ -37,7 +38,7 @@ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE #define SET_EXPECT(func) \ - expect_ ## func = TRUE + do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0) #define CHECK_EXPECT2(func) \ do { \ @@ -89,6 +90,7 @@ DEFINE_EXPECT(OnProgress_MIMETYPEAVAILABLE); DEFINE_EXPECT(OnProgress_BEGINDOWNLOADDATA); DEFINE_EXPECT(OnProgress_DOWNLOADINGDATA); DEFINE_EXPECT(OnProgress_ENDDOWNLOADDATA); +DEFINE_EXPECT(OnProgress_CACHEFILENAMEAVAILABLE); DEFINE_EXPECT(OnStopBinding); DEFINE_EXPECT(OnDataAvailable); DEFINE_EXPECT(OnObjectAvailable); @@ -104,6 +106,7 @@ DEFINE_EXPECT(Obj_OnProgress_BEGINSYNCOPERATION); DEFINE_EXPECT(Obj_OnProgress_ENDSYNCOPERATION); DEFINE_EXPECT(Obj_OnProgress_FINDINGRESOURCE); DEFINE_EXPECT(Obj_OnProgress_CONNECTING); +DEFINE_EXPECT(Obj_OnProgress_CACHEFILENAMEAVAILABLE); DEFINE_EXPECT(Start); DEFINE_EXPECT(Read); DEFINE_EXPECT(LockRequest); @@ -140,11 +143,13 @@ static const WCHAR wszWineHQSite[] = static const WCHAR wszWineHQIP[] = {'2','0','9','.','3','2','.','1','4','1','.','3',0}; static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0}; +static const WCHAR cache_fileW[] = {'c',':','\\','c','a','c','h','e','.','h','t','m',0}; +static const WCHAR dwl_htmlW[] = {'d','w','l','.','h','t','m','l',0}; static const WCHAR emptyW[] = {0}; static BOOL stopped_binding = FALSE, stopped_obj_binding = FALSE, emulate_protocol = FALSE, - data_available = FALSE, http_is_first = TRUE, bind_to_object = FALSE; -static DWORD read = 0, bindf = 0, prot_state = 0, thread_id; + data_available = FALSE, http_is_first = TRUE, bind_to_object = FALSE, filedwl_api; +static DWORD read = 0, bindf = 0, prot_state = 0, thread_id, tymed; static CHAR mime_type[512]; static IInternetProtocolSink *protocol_sink = NULL; static HANDLE complete_event, complete_event2; @@ -160,6 +165,8 @@ static LPCWSTR urls[] = { MK_URL }; +static WCHAR file_url[INTERNET_MAX_URL_LENGTH]; + static enum { HTTP_TEST, ABOUT_TEST, @@ -337,8 +344,9 @@ static DWORD WINAPI thread_proc(PVOID arg) CHECK_CALLED(OnDataAvailable); CHECK_CALLED(OnStopBinding); - SetEvent(complete_event2); + SET_EXPECT(Read); + SetEvent(complete_event2); return 0; } @@ -357,13 +365,14 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, read = 0; - ok(szUrl && !lstrcmpW(szUrl, urls[test_protocol]), "wrong url\n"); + if(!filedwl_api) /* FIXME */ + ok(szUrl && !lstrcmpW(szUrl, urls[test_protocol]), "wrong url %s\n", debugstr_w(szUrl)); ok(pOIProtSink != NULL, "pOIProtSink == NULL\n"); ok(pOIBindInfo != NULL, "pOIBindInfo == NULL\n"); ok(grfPI == 0, "grfPI=%d, expected 0\n", grfPI); ok(dwReserved == 0, "dwReserved=%d, expected 0\n", dwReserved); - if(binding_hres != S_OK) { + if(!filedwl_api && binding_hres != S_OK) { SET_EXPECT(OnStopBinding); SET_EXPECT(Terminate); hres = IInternetProtocolSink_ReportResult(pOIProtSink, binding_hres, 0, NULL); @@ -379,13 +388,16 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo); ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres); - if(test_protocol == FILE_TEST || test_protocol == MK_TEST || test_protocol == HTTP_TEST) { + if(filedwl_api) { + ok(bindf == (BINDF_PULLDATA|BINDF_FROMURLMON|BINDF_NEEDFILE), "bindf=%08x\n", bindf); + }else if(tymed == TYMED_ISTREAM + && (test_protocol == FILE_TEST || test_protocol == MK_TEST || test_protocol == HTTP_TEST)) { ok(bindf == (BINDF_ASYNCHRONOUS|BINDF_ASYNCSTORAGE|BINDF_PULLDATA |BINDF_FROMURLMON), "bindf=%08x\n", bindf); }else { - ok(bindf == (BINDF_ASYNCHRONOUS|BINDF_ASYNCSTORAGE|BINDF_PULLDATA| - BINDF_FROMURLMON|BINDF_NEEDFILE), + ok(bindf == (BINDF_ASYNCHRONOUS|BINDF_ASYNCSTORAGE|BINDF_PULLDATA + |BINDF_FROMURLMON|BINDF_NEEDFILE), "bindf=%08x\n", bindf); } @@ -513,7 +525,7 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, if(test_protocol == FILE_TEST) { hres = IInternetProtocolSink_ReportProgress(pOIProtSink, - BINDSTATUS_CACHEFILENAMEAVAILABLE, emptyW); + BINDSTATUS_CACHEFILENAMEAVAILABLE, file_url+8); ok(hres == S_OK, "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres); @@ -546,6 +558,8 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, if(test_protocol != FILE_TEST && test_protocol != MK_TEST) SET_EXPECT(Obj_OnProgress_MIMETYPEAVAILABLE); SET_EXPECT(Obj_OnProgress_BEGINDOWNLOADDATA); + if(test_protocol == FILE_TEST) + SET_EXPECT(Obj_OnProgress_CACHEFILENAMEAVAILABLE); SET_EXPECT(Obj_OnProgress_ENDDOWNLOADDATA); SET_EXPECT(Obj_OnProgress_CLASSIDAVAILABLE); SET_EXPECT(Obj_OnProgress_BEGINSYNCOPERATION); @@ -560,9 +574,12 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, if(test_protocol != FILE_TEST && test_protocol != MK_TEST) SET_EXPECT(OnProgress_MIMETYPEAVAILABLE); SET_EXPECT(OnProgress_BEGINDOWNLOADDATA); + if(test_protocol == FILE_TEST) + SET_EXPECT(OnProgress_CACHEFILENAMEAVAILABLE); SET_EXPECT(OnProgress_ENDDOWNLOADDATA); SET_EXPECT(LockRequest); - SET_EXPECT(OnDataAvailable); + if(!filedwl_api) + SET_EXPECT(OnDataAvailable); SET_EXPECT(OnStopBinding); } @@ -574,6 +591,8 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, if(test_protocol != FILE_TEST && test_protocol != MK_TEST) CHECK_CALLED(Obj_OnProgress_MIMETYPEAVAILABLE); CHECK_CALLED(Obj_OnProgress_BEGINDOWNLOADDATA); + if(test_protocol == FILE_TEST) + CHECK_CALLED(Obj_OnProgress_CACHEFILENAMEAVAILABLE); CHECK_CALLED(Obj_OnProgress_ENDDOWNLOADDATA); CHECK_CALLED(Obj_OnProgress_CLASSIDAVAILABLE); CHECK_CALLED(Obj_OnProgress_BEGINSYNCOPERATION); @@ -588,9 +607,12 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, if(test_protocol != FILE_TEST && test_protocol != MK_TEST) CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE); CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA); + if(test_protocol == FILE_TEST) + CHECK_CALLED(OnProgress_CACHEFILENAMEAVAILABLE); CHECK_CALLED(OnProgress_ENDDOWNLOADDATA); CHECK_CALLED(LockRequest); - CHECK_CALLED(OnDataAvailable); + if(!filedwl_api) + CHECK_CALLED(OnDataAvailable); CHECK_CALLED(OnStopBinding); } @@ -648,6 +670,13 @@ static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface, ok(hres == S_OK, "ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE) failed: %08x\n", hres); + if(tymed == TYMED_FILE) { + hres = IInternetProtocolSink_ReportProgress(protocol_sink, + BINDSTATUS_CACHEFILENAMEAVAILABLE, cache_fileW); + ok(hres == S_OK, + "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres); + } + bscf |= BSCF_FIRSTDATANOTIFICATION; break; } @@ -1133,8 +1162,13 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP else CHECK_EXPECT(OnProgress_BEGINDOWNLOADDATA); ok(szStatusText != NULL, "szStatusText == NULL\n"); - if(szStatusText) - ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText\n"); + if(szStatusText) { + if(filedwl_api) { + /* FIXME */ + }else { + ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText %s\n", debugstr_w(szStatusText)); + } + } if(!bind_to_object) ok(download_state == BEFORE_DOWNLOAD, "Download state was %d, expected BEFORE_DOWNLOAD\n", download_state); @@ -1153,16 +1187,31 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP else CHECK_EXPECT(OnProgress_ENDDOWNLOADDATA); ok(szStatusText != NULL, "szStatusText == NULL\n"); - if(szStatusText) - ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText\n"); + if(szStatusText) { + if(filedwl_api) { + /* FIXME */ + }else { + ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText %s\n", debugstr_w(szStatusText)); + } + } ok(download_state == DOWNLOADING, "Download state was %d, expected DOWNLOADING\n", download_state); download_state = END_DOWNLOAD; break; case BINDSTATUS_CACHEFILENAMEAVAILABLE: + if(test_protocol != HTTP_TEST) { + if(iface == &objbsc) + CHECK_EXPECT(Obj_OnProgress_CACHEFILENAMEAVAILABLE); + else + CHECK_EXPECT(OnProgress_CACHEFILENAMEAVAILABLE); + }else { /* FIXME */ + CLEAR_CALLED(OnProgress_CACHEFILENAMEAVAILABLE); + CLEAR_CALLED(Obj_OnProgress_CACHEFILENAMEAVAILABLE); + } + ok(szStatusText != NULL, "szStatusText == NULL\n"); if(szStatusText && test_protocol == FILE_TEST) - ok(!lstrcmpW(INDEX_HTML+7, szStatusText), "wrong szStatusText\n"); + ok(!lstrcmpW(file_url+8, szStatusText), "wrong szStatusText %s\n", debugstr_w(szStatusText)); break; case BINDSTATUS_CLASSIDAVAILABLE: { @@ -1193,7 +1242,7 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP ok(szStatusText == NULL, "Expected szStatusText to be NULL\n"); break; default: - ok(0, "unexpexted code %d\n", ulStatusCode); + ok(0, "unexpected code %d\n", ulStatusCode); }; return S_OK; } @@ -1214,7 +1263,10 @@ static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallback *iface, HRESUL if (hresult == HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED)) return S_OK; - ok(hresult == binding_hres, "binding failed: %08x, expected %08x\n", hresult, binding_hres); + if(filedwl_api) + ok(SUCCEEDED(hresult), "binding failed: %08x\n", hresult); + else + ok(hresult == binding_hres, "binding failed: %08x, expected %08x\n", hresult, binding_hres); ok(szError == NULL, "szError should be NULL\n"); if(test_protocol == HTTP_TEST && emulate_protocol) { @@ -1279,34 +1331,42 @@ static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWOR ok(pformatetc->ptd == NULL, "ptd = %p\n", pformatetc->ptd); ok(pformatetc->dwAspect == 1, "dwAspect=%u\n", pformatetc->dwAspect); ok(pformatetc->lindex == -1, "lindex=%d\n", pformatetc->lindex); - ok(pformatetc->tymed == TYMED_ISTREAM, "tymed=%u\n", pformatetc->tymed); + ok(pformatetc->tymed == tymed, "tymed=%u, expected %u\n", pformatetc->tymed, tymed); } ok(pstgmed != NULL, "stgmeg == NULL\n"); - if(pstgmed) { - ok(pstgmed->tymed == TYMED_ISTREAM, "tymed=%u\n", pstgmed->tymed); - ok(U(*pstgmed).pstm != NULL, "pstm == NULL\n"); - ok(pstgmed->pUnkForRelease != NULL, "pUnkForRelease == NULL\n"); - } + ok(pstgmed->tymed == tymed, "tymed=%u, expected %u\n", pstgmed->tymed, tymed); + ok(pstgmed->pUnkForRelease != NULL, "pUnkForRelease == NULL\n"); - if(grfBSCF & BSCF_FIRSTDATANOTIFICATION) { - hres = IStream_Write(U(*pstgmed).pstm, buf, 10, NULL); - ok(hres == STG_E_ACCESSDENIED, - "Write failed: %08x, expected STG_E_ACCESSDENIED\n", hres); + switch(pstgmed->tymed) { + case TYMED_ISTREAM: + if(grfBSCF & BSCF_FIRSTDATANOTIFICATION) { + hres = IStream_Write(U(*pstgmed).pstm, buf, 10, NULL); + ok(hres == STG_E_ACCESSDENIED, + "Write failed: %08x, expected STG_E_ACCESSDENIED\n", hres); - hres = IStream_Commit(U(*pstgmed).pstm, 0); - ok(hres == E_NOTIMPL, "Commit failed: %08x, expected E_NOTIMPL\n", hres); - - hres = IStream_Revert(U(*pstgmed).pstm); - ok(hres == E_NOTIMPL, "Revert failed: %08x, expected E_NOTIMPL\n", hres); - } + hres = IStream_Commit(U(*pstgmed).pstm, 0); + ok(hres == E_NOTIMPL, "Commit failed: %08x, expected E_NOTIMPL\n", hres); - ok(U(*pstgmed).pstm != NULL, "U(*pstgmed).pstm == NULL\n"); + hres = IStream_Revert(U(*pstgmed).pstm); + ok(hres == E_NOTIMPL, "Revert failed: %08x, expected E_NOTIMPL\n", hres); + } - if(U(*pstgmed).pstm) { + ok(U(*pstgmed).pstm != NULL, "U(*pstgmed).pstm == NULL\n"); do hres = IStream_Read(U(*pstgmed).pstm, buf, 512, &readed); while(hres == S_OK); ok(hres == S_FALSE || hres == E_PENDING, "IStream_Read returned %08x\n", hres); + break; + + case TYMED_FILE: + if(test_protocol == FILE_TEST) + ok(!lstrcmpW(pstgmed->u.lpszFileName, INDEX_HTML+7), + "unexpected file name %s\n", debugstr_w(pstgmed->u.lpszFileName)); + else if(emulate_protocol) + ok(!lstrcmpW(pstgmed->u.lpszFileName, cache_fileW), + "unexpected file name %s\n", debugstr_w(pstgmed->u.lpszFileName)); + else + ok(pstgmed->u.lpszFileName != NULL, "lpszFileName == NULL\n"); } if(test_protocol == HTTP_TEST && emulate_protocol && prot_state < 4 && (!bind_to_object || prot_state > 1)) @@ -1325,9 +1385,6 @@ static HRESULT WINAPI statusclb_OnObjectAvailable(IBindStatusCallback *iface, RE ok(IsEqualGUID(&IID_IUnknown, riid), "riid = %s\n", debugstr_guid(riid)); ok(punk != NULL, "punk == NULL\n"); - if(0&&test_protocol == HTTP_TEST) - SetEvent(complete_event); - return S_OK; } @@ -1441,8 +1498,6 @@ static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAva CHECK_EXPECT(Load); ok(GetCurrentThreadId() == thread_id, "wrong thread %d\n", GetCurrentThreadId()); - trace("LOAD %p\n", pibc); - if(test_protocol == HTTP_TEST) ok(!fFullyAvailable, "fFulyAvailable = %x\n", fFullyAvailable); else @@ -1470,9 +1525,9 @@ static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAva SET_EXPECT(GetBindInfo); SET_EXPECT(OnStartBinding); - if(test_protocol == FILE_TEST) - SET_EXPECT(OnProgress_MIMETYPEAVAILABLE); SET_EXPECT(OnProgress_BEGINDOWNLOADDATA); + if(test_protocol == FILE_TEST) + SET_EXPECT(OnProgress_CACHEFILENAMEAVAILABLE); if(test_protocol != HTTP_TEST) SET_EXPECT(OnProgress_ENDDOWNLOADDATA); SET_EXPECT(LockRequest); @@ -1485,9 +1540,9 @@ static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAva CHECK_CALLED(GetBindInfo); CHECK_CALLED(OnStartBinding); - if(test_protocol == FILE_TEST) - todo_wine CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE); CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA); + if(test_protocol == FILE_TEST) + CHECK_CALLED(OnProgress_CACHEFILENAMEAVAILABLE); if(test_protocol != HTTP_TEST) CHECK_CALLED(OnProgress_ENDDOWNLOADDATA); CHECK_CALLED(LockRequest); @@ -1764,26 +1819,27 @@ static void test_bscholder(IBindStatusCallback *holder) IHttpNegotiate_Release(http_negotiate_serv); hres = IBindStatusCallback_QueryInterface(holder, &IID_IHttpNegotiate2, (void**)&http_negotiate2); - ok(hres == S_OK, "Could not get IHttpNegotiate2 interface: %08x\n", hres); - - hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, (void*)0xdeadbeef, (void*)0xdeadbeef, 0); - ok(hres == E_FAIL, "GetRootSecurityId failed: %08x\n", hres); - - IHttpNegotiate_Release(http_negotiate2); + if(SUCCEEDED(hres)) { + hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, (void*)0xdeadbeef, (void*)0xdeadbeef, 0); + ok(hres == E_FAIL, "GetRootSecurityId failed: %08x\n", hres); - SET_EXPECT(QueryInterface_IHttpNegotiate2); - hres = IServiceProvider_QueryService(serv_prov, &IID_IHttpNegotiate2, &IID_IHttpNegotiate2, - (void**)&http_negotiate2_serv); - ok(hres == S_OK, "Could not get IHttpNegotiate2 service: %08x\n", hres); - CHECK_CALLED(QueryInterface_IHttpNegotiate2); - ok(http_negotiate2 == http_negotiate2_serv, "http_negotiate != http_negotiate_serv\n"); + SET_EXPECT(QueryInterface_IHttpNegotiate2); + hres = IServiceProvider_QueryService(serv_prov, &IID_IHttpNegotiate2, &IID_IHttpNegotiate2, + (void**)&http_negotiate2_serv); + ok(hres == S_OK, "Could not get IHttpNegotiate2 service: %08x\n", hres); + CHECK_CALLED(QueryInterface_IHttpNegotiate2); + ok(http_negotiate2 == http_negotiate2_serv, "http_negotiate != http_negotiate_serv\n"); - SET_EXPECT(GetRootSecurityId); - hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, (void*)0xdeadbeef, (void*)0xdeadbeef, 0); - ok(hres == E_NOTIMPL, "GetRootSecurityId failed: %08x\n", hres); - CHECK_CALLED(GetRootSecurityId); + SET_EXPECT(GetRootSecurityId); + hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, (void*)0xdeadbeef, (void*)0xdeadbeef, 0); + ok(hres == E_NOTIMPL, "GetRootSecurityId failed: %08x\n", hres); + CHECK_CALLED(GetRootSecurityId); - IHttpNegotiate_Release(http_negotiate2_serv); + IHttpNegotiate_Release(http_negotiate2_serv); + IHttpNegotiate_Release(http_negotiate2); + }else { + skip("Could not get IHttpNegotiate2\n"); + } SET_EXPECT(OnProgress_FINDINGRESOURCE); hres = IBindStatusCallback_OnProgress(holder, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL); @@ -1896,20 +1952,26 @@ static void test_RegisterBindStatusCallback(void) IBindCtx_Release(bindctx); } -static void init_bind_test(int protocol, BOOL emul, BOOL bto) +#define BINDTEST_EMULATE 1 +#define BINDTEST_TOOBJECT 2 +#define BINDTEST_FILEDWLAPI 4 + +static void init_bind_test(int protocol, DWORD flags, DWORD t) { test_protocol = protocol; - emulate_protocol = emul; + emulate_protocol = (flags & BINDTEST_EMULATE) != 0; download_state = BEFORE_DOWNLOAD; stopped_binding = FALSE; stopped_obj_binding = FALSE; data_available = FALSE; mime_type[0] = 0; binding_hres = S_OK; - bind_to_object = bto; + bind_to_object = (flags & BINDTEST_TOOBJECT) != 0; + tymed = t; + filedwl_api = (flags & BINDTEST_FILEDWLAPI) != 0; } -static void test_BindToStorage(int protocol, BOOL emul) +static void test_BindToStorage(int protocol, BOOL emul, DWORD t) { IMoniker *mon; HRESULT hres; @@ -1920,7 +1982,7 @@ static void test_BindToStorage(int protocol, BOOL emul) IUnknown *unk = (IUnknown*)0x00ff00ff; IBinding *bind; - init_bind_test(protocol, emul, FALSE); + init_bind_test(protocol, emul ? BINDTEST_EMULATE : 0, t); SET_EXPECT(QueryInterface_IServiceProvider); hres = CreateAsyncBindCtx(0, &bsc, NULL, &bctx); @@ -1937,16 +1999,13 @@ static void test_BindToStorage(int protocol, BOOL emul) if(previousclb) IBindStatusCallback_Release(previousclb); - hres = CreateURLMoniker(NULL, urls[test_protocol], &mon); + hres = CreateURLMoniker(NULL, test_protocol == FILE_TEST ? file_url : urls[test_protocol], &mon); ok(SUCCEEDED(hres), "failed to create moniker: %08x\n", hres); if(FAILED(hres)) { IBindCtx_Release(bctx); return; } - if(test_protocol == FILE_TEST && INDEX_HTML[7] == '/') - memmove(INDEX_HTML+7, INDEX_HTML+8, lstrlenW(INDEX_HTML+7)*sizeof(WCHAR)); - hres = IMoniker_QueryInterface(mon, &IID_IBinding, (void**)&bind); ok(hres == E_NOINTERFACE, "IMoniker should not have IBinding interface\n"); if(SUCCEEDED(hres)) @@ -1958,6 +2017,9 @@ static void test_BindToStorage(int protocol, BOOL emul) "GetDisplayName got wrong name %s\n", debugstr_w(display_name)); CoTaskMemFree(display_name); + if(tymed == TYMED_FILE && (test_protocol == ABOUT_TEST || test_protocol == ITS_TEST)) + binding_hres = INET_E_DATA_NOT_AVAILABLE; + SET_EXPECT(GetBindInfo); SET_EXPECT(QueryInterface_IInternetProtocol); if(!emulate_protocol) @@ -1967,9 +2029,12 @@ static void test_BindToStorage(int protocol, BOOL emul) SET_EXPECT(Start); if(test_protocol == HTTP_TEST) SET_EXPECT(Terminate); - SET_EXPECT(UnlockRequest); + if(tymed != TYMED_FILE || (test_protocol != ABOUT_TEST && test_protocol != ITS_TEST)) + SET_EXPECT(UnlockRequest); }else { if(test_protocol == HTTP_TEST) { + SET_EXPECT(QueryInterface_IInternetBindInfo); + SET_EXPECT(QueryService_IInternetBindInfo); SET_EXPECT(QueryInterface_IHttpNegotiate); SET_EXPECT(BeginningTransaction); SET_EXPECT(QueryInterface_IHttpNegotiate2); @@ -1983,24 +2048,31 @@ static void test_BindToStorage(int protocol, BOOL emul) SET_EXPECT(OnResponse); SET_EXPECT(OnProgress_MIMETYPEAVAILABLE); SET_EXPECT(OnProgress_BEGINDOWNLOADDATA); + if(test_protocol == FILE_TEST) + SET_EXPECT(OnProgress_CACHEFILENAMEAVAILABLE); if(test_protocol == HTTP_TEST) SET_EXPECT(OnProgress_DOWNLOADINGDATA); SET_EXPECT(OnProgress_ENDDOWNLOADDATA); - SET_EXPECT(OnDataAvailable); + if(tymed != TYMED_FILE || test_protocol != ABOUT_TEST) + SET_EXPECT(OnDataAvailable); SET_EXPECT(OnStopBinding); } - hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk); + hres = IMoniker_BindToStorage(mon, bctx, NULL, tymed == TYMED_ISTREAM ? &IID_IStream : &IID_IUnknown, (void**)&unk); if (test_protocol == HTTP_TEST && hres == HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED)) { - trace( "Network unreachable, skipping tests\n" ); + skip("Network unreachable, skipping tests\n"); return; } - if (!SUCCEEDED(hres)) return; - if((bindf & BINDF_ASYNCHRONOUS) && !data_available) { + if(((bindf & BINDF_ASYNCHRONOUS) && !data_available) + || (tymed == TYMED_FILE && test_protocol == FILE_TEST)) { ok(hres == MK_S_ASYNCHRONOUS, "IMoniker_BindToStorage failed: %08x\n", hres); ok(unk == NULL, "istr should be NULL\n"); + }else if(tymed == TYMED_FILE && test_protocol == ABOUT_TEST) { + ok(hres == INET_E_DATA_NOT_AVAILABLE, + "IMoniker_BindToStorage failed: %08x, expected INET_E_DATA_NOT_AVAILABLE\n", hres); + ok(unk == NULL, "istr should be NULL\n"); }else { ok(hres == S_OK, "IMoniker_BindToStorage failed: %08x\n", hres); ok(unk != NULL, "unk == NULL\n"); @@ -2008,6 +2080,9 @@ static void test_BindToStorage(int protocol, BOOL emul) if(unk) IUnknown_Release(unk); + if(FAILED(hres)) + return; + while((bindf & BINDF_ASYNCHRONOUS) && !stopped_binding && GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); @@ -2021,11 +2096,17 @@ static void test_BindToStorage(int protocol, BOOL emul) CHECK_CALLED(OnStartBinding); if(emulate_protocol) { CHECK_CALLED(Start); - if(test_protocol == HTTP_TEST) + if(test_protocol == HTTP_TEST) { + if(tymed == TYMED_FILE) + CLEAR_CALLED(Read); CHECK_CALLED(Terminate); - CHECK_CALLED(UnlockRequest); + } + if(tymed != TYMED_FILE || (test_protocol != ABOUT_TEST && test_protocol != ITS_TEST)) + CHECK_CALLED(UnlockRequest); }else { if(test_protocol == HTTP_TEST) { + CLEAR_CALLED(QueryInterface_IInternetBindInfo); + CLEAR_CALLED(QueryService_IInternetBindInfo); CHECK_CALLED(QueryInterface_IHttpNegotiate); CHECK_CALLED(BeginningTransaction); /* QueryInterface_IHttpNegotiate2 and GetRootSecurityId @@ -2046,10 +2127,13 @@ static void test_BindToStorage(int protocol, BOOL emul) CHECK_CALLED(OnResponse); CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE); CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA); + if(test_protocol == FILE_TEST) + CHECK_CALLED(OnProgress_CACHEFILENAMEAVAILABLE); if(test_protocol == HTTP_TEST) CLEAR_CALLED(OnProgress_DOWNLOADINGDATA); CHECK_CALLED(OnProgress_ENDDOWNLOADDATA); - CHECK_CALLED(OnDataAvailable); + if(tymed != TYMED_FILE || test_protocol != ABOUT_TEST) + CHECK_CALLED(OnDataAvailable); CHECK_CALLED(OnStopBinding); } @@ -2071,7 +2155,7 @@ static void test_BindToObject(int protocol, BOOL emul) IUnknown *unk = (IUnknown*)0x00ff00ff; IBinding *bind; - init_bind_test(protocol, emul, TRUE); + init_bind_test(protocol, BINDTEST_TOOBJECT | (emul ? BINDTEST_EMULATE : 0), TYMED_ISTREAM); if(emul) CoRegisterClassObject(&CLSID_HTMLDocument, (IUnknown *)&mime_cf, @@ -2084,16 +2168,13 @@ static void test_BindToObject(int protocol, BOOL emul) if(FAILED(hres)) return; - hres = CreateURLMoniker(NULL, urls[test_protocol], &mon); + hres = CreateURLMoniker(NULL, test_protocol == FILE_TEST ? file_url : urls[test_protocol], &mon); ok(SUCCEEDED(hres), "failed to create moniker: %08x\n", hres); if(FAILED(hres)) { IBindCtx_Release(bctx); return; } - if(test_protocol == FILE_TEST && INDEX_HTML[7] == '/') - memmove(INDEX_HTML+7, INDEX_HTML+8, lstrlenW(INDEX_HTML+7)*sizeof(WCHAR)); - hres = IMoniker_QueryInterface(mon, &IID_IBinding, (void**)&bind); ok(hres == E_NOINTERFACE, "IMoniker should not have IBinding interface\n"); if(SUCCEEDED(hres)) @@ -2128,6 +2209,8 @@ static void test_BindToObject(int protocol, BOOL emul) SET_EXPECT(OnResponse); SET_EXPECT(Obj_OnProgress_MIMETYPEAVAILABLE); SET_EXPECT(Obj_OnProgress_BEGINDOWNLOADDATA); + if(test_protocol == FILE_TEST) + SET_EXPECT(Obj_OnProgress_CACHEFILENAMEAVAILABLE); if(test_protocol == HTTP_TEST) SET_EXPECT(OnProgress_DOWNLOADINGDATA); SET_EXPECT(Obj_OnProgress_ENDDOWNLOADDATA); @@ -2142,7 +2225,7 @@ static void test_BindToObject(int protocol, BOOL emul) if (test_protocol == HTTP_TEST && hres == HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED)) { - trace( "Network unreachable, skipping tests\n" ); + skip( "Network unreachable, skipping tests\n" ); return; } @@ -2193,12 +2276,18 @@ static void test_BindToObject(int protocol, BOOL emul) CHECK_NOT_CALLED(Obj_OnProgress_CONNECTING); } } - if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST) - CHECK_CALLED(Obj_OnProgress_SENDINGREQUEST); + if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST) { + if(urls[test_protocol] == SHORT_RESPONSE_URL) + CLEAR_CALLED(Obj_OnProgress_SENDINGREQUEST); + else + CHECK_CALLED(Obj_OnProgress_SENDINGREQUEST); + } if(test_protocol == HTTP_TEST) CHECK_CALLED(OnResponse); CHECK_CALLED(Obj_OnProgress_MIMETYPEAVAILABLE); CHECK_CALLED(Obj_OnProgress_BEGINDOWNLOADDATA); + if(test_protocol == FILE_TEST) + CHECK_CALLED(Obj_OnProgress_CACHEFILENAMEAVAILABLE); if(test_protocol == HTTP_TEST) CLEAR_CALLED(OnProgress_DOWNLOADINGDATA); CLEAR_CALLED(Obj_OnProgress_ENDDOWNLOADDATA); @@ -2224,18 +2313,106 @@ static void test_BindToObject(int protocol, BOOL emul) http_is_first = FALSE; } +static void test_URLDownloadToFile(DWORD prot, BOOL emul) +{ + BOOL res; + HRESULT hres; + + init_bind_test(prot, BINDTEST_FILEDWLAPI | (emul ? BINDTEST_EMULATE : 0), TYMED_FILE); + + SET_EXPECT(GetBindInfo); + SET_EXPECT(QueryInterface_IInternetProtocol); + if(!emulate_protocol) { + SET_EXPECT(QueryInterface_IServiceProvider); + SET_EXPECT(QueryService_IInternetProtocol); + } + SET_EXPECT(OnStartBinding); + if(emulate_protocol) { + SET_EXPECT(Start); + SET_EXPECT(UnlockRequest); + }else { + if(test_protocol == HTTP_TEST) { + SET_EXPECT(QueryInterface_IHttpNegotiate); + SET_EXPECT(BeginningTransaction); + SET_EXPECT(QueryInterface_IHttpNegotiate2); + SET_EXPECT(GetRootSecurityId); + } + if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST) + SET_EXPECT(OnProgress_SENDINGREQUEST); + if(test_protocol == HTTP_TEST) + SET_EXPECT(OnResponse); + SET_EXPECT(OnProgress_MIMETYPEAVAILABLE); + SET_EXPECT(OnProgress_BEGINDOWNLOADDATA); + if(test_protocol == FILE_TEST) + SET_EXPECT(OnProgress_CACHEFILENAMEAVAILABLE); + if(test_protocol == HTTP_TEST) + SET_EXPECT(OnProgress_DOWNLOADINGDATA); + SET_EXPECT(OnProgress_ENDDOWNLOADDATA); + SET_EXPECT(OnStopBinding); + } + + hres = URLDownloadToFileW(NULL, test_protocol == FILE_TEST ? file_url : urls[test_protocol], dwl_htmlW, 0, &bsc); + ok(hres == S_OK, "URLDownloadToFile failed: %08x\n", hres); + + CHECK_CALLED(GetBindInfo); + CHECK_CALLED(QueryInterface_IInternetProtocol); + if(!emulate_protocol) { + CHECK_CALLED(QueryInterface_IServiceProvider); + CHECK_CALLED(QueryService_IInternetProtocol); + } + CHECK_CALLED(OnStartBinding); + if(emulate_protocol) { + CHECK_CALLED(Start); + CHECK_CALLED(UnlockRequest); + }else { + if(test_protocol == HTTP_TEST) { + CHECK_CALLED(QueryInterface_IHttpNegotiate); + CHECK_CALLED(BeginningTransaction); + CHECK_CALLED(QueryInterface_IHttpNegotiate2); + CHECK_CALLED(GetRootSecurityId); + } + if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST) + CHECK_CALLED(OnProgress_SENDINGREQUEST); + if(test_protocol == HTTP_TEST) + CHECK_CALLED(OnResponse); + CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE); + CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA); + if(test_protocol == FILE_TEST) + CHECK_CALLED(OnProgress_CACHEFILENAMEAVAILABLE); + if(test_protocol == HTTP_TEST) + CLEAR_CALLED(OnProgress_DOWNLOADINGDATA); + CHECK_CALLED(OnProgress_ENDDOWNLOADDATA); + CHECK_CALLED(OnStopBinding); + } + + res = DeleteFileW(dwl_htmlW); + ok(res, "DeleteFile failed: %u\n", GetLastError()); + + if(prot != FILE_TEST || emul) + return; + + hres = URLDownloadToFileW(NULL, urls[test_protocol], dwl_htmlW, 0, NULL); + ok(hres == S_OK, "URLDownloadToFile failed: %08x\n", hres); + + res = DeleteFileW(dwl_htmlW); + ok(res, "DeleteFile failed: %u\n", GetLastError()); +} + static void set_file_url(void) { int len; static const WCHAR wszFile[] = {'f','i','l','e',':','/','/'}; - memcpy(INDEX_HTML, wszFile, sizeof(wszFile)); + memcpy(file_url, wszFile, sizeof(wszFile)); len = sizeof(wszFile)/sizeof(WCHAR); - INDEX_HTML[len++] = '/'; - len += GetCurrentDirectoryW(sizeof(INDEX_HTML)/sizeof(WCHAR)-len, INDEX_HTML+len); - INDEX_HTML[len++] = '\\'; - memcpy(INDEX_HTML+len, wszIndexHtml, sizeof(wszIndexHtml)); + file_url[len++] = '/'; + len += GetCurrentDirectoryW(sizeof(file_url)/sizeof(WCHAR)-len, file_url+len); + file_url[len++] = '\\'; + memcpy(file_url+len, wszIndexHtml, sizeof(wszIndexHtml)); + + memcpy(INDEX_HTML, wszFile, sizeof(wszIndexHtml)); + memmove(INDEX_HTML+7, file_url+8, (lstrlenW(file_url+8)+1)*sizeof(WCHAR)); } static void create_file(void) @@ -2264,7 +2441,7 @@ static void test_ReportResult(HRESULT exhres) IUnknown *unk = (void*)0xdeadbeef; HRESULT hres; - init_bind_test(ABOUT_TEST, TRUE, FALSE); + init_bind_test(ABOUT_TEST, BINDTEST_EMULATE, TYMED_ISTREAM); binding_hres = exhres; hres = CreateURLMoniker(NULL, ABOUT_BLANK, &mon); @@ -2282,9 +2459,10 @@ static void test_ReportResult(HRESULT exhres) hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk); if(SUCCEEDED(exhres)) - ok(hres == S_OK, "BindToStorage failed: %08x\n", hres); + ok(hres == S_OK || hres == MK_S_ASYNCHRONOUS, "BindToStorage failed: %08x\n", hres); else - ok(hres == exhres, "BindToStorage failed: %08x, expected %08x\n", hres, exhres); + ok(hres == exhres || hres == MK_S_ASYNCHRONOUS, + "BindToStorage failed: %08x, expected %08x or MK_S_ASYNCHRONOUS\n", hres, exhres); CHECK_CALLED(GetBindInfo); CHECK_CALLED(QueryInterface_IInternetProtocol); @@ -2313,7 +2491,8 @@ static void test_BindToStorage_fail(void) ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08x\n", hres); hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk); - ok(hres == MK_E_SYNTAX, "hres=%08x, expected INET_E_SYNTAX\n", hres); + ok(hres == MK_E_SYNTAX || hres == INET_E_DATA_NOT_AVAILABLE, + "hres=%08x, expected MK_E_SYNTAX or INET_E_DATA_NOT_AVAILABLE\n", hres); IBindCtx_Release(bctx); @@ -2323,11 +2502,44 @@ static void test_BindToStorage_fail(void) test_ReportResult(S_FALSE); } +static void gecko_installer_workaround(BOOL disable) +{ + HKEY hkey; + DWORD res; + + static BOOL has_url = FALSE; + static char url[2048]; + + if(!disable && !has_url) + return; + + res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey); + if(res != ERROR_SUCCESS) + return; + + if(disable) { + DWORD type, size = sizeof(url); + + res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size); + if(res == ERROR_SUCCESS && type == REG_SZ) + has_url = TRUE; + + RegDeleteValue(hkey, "GeckoUrl"); + }else { + RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1); + } + + RegCloseKey(hkey); +} + START_TEST(url) { + gecko_installer_workaround(TRUE); + complete_event = CreateEvent(NULL, FALSE, FALSE, NULL); complete_event2 = CreateEvent(NULL, FALSE, FALSE, NULL); thread_id = GetCurrentThreadId(); + create_file(); test_create(); test_CreateAsyncBindCtx(); @@ -2336,65 +2548,111 @@ START_TEST(url) test_BindToStorage_fail(); trace("synchronous http test (COM not initialised)...\n"); - test_BindToStorage(HTTP_TEST, FALSE); + test_BindToStorage(HTTP_TEST, FALSE, TYMED_ISTREAM); CoInitialize(NULL); trace("synchronous http test...\n"); - test_BindToStorage(HTTP_TEST, FALSE); + test_BindToStorage(HTTP_TEST, FALSE, TYMED_ISTREAM); + + trace("synchronous http test (to object)...\n"); test_BindToObject(HTTP_TEST, FALSE); trace("synchronous file test...\n"); - create_file(); - test_BindToStorage(FILE_TEST, FALSE); + test_BindToStorage(FILE_TEST, FALSE, TYMED_ISTREAM); + + trace("synchronous file test (to object)...\n"); test_BindToObject(FILE_TEST, FALSE); - DeleteFileW(wszIndexHtml); bindf = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; trace("http test...\n"); - test_BindToStorage(HTTP_TEST, FALSE); + test_BindToStorage(HTTP_TEST, FALSE, TYMED_ISTREAM); + + trace("http test (to file)...\n"); + test_BindToStorage(HTTP_TEST, FALSE, TYMED_FILE); + + trace("http test (to object)...\n"); test_BindToObject(HTTP_TEST, FALSE); trace("http test (short response)...\n"); http_is_first = TRUE; urls[HTTP_TEST] = SHORT_RESPONSE_URL; - test_BindToStorage(HTTP_TEST, FALSE); + test_BindToStorage(HTTP_TEST, FALSE, TYMED_ISTREAM); + + trace("http test (short response, to object)...\n"); test_BindToObject(HTTP_TEST, FALSE); trace("emulated http test...\n"); - test_BindToStorage(HTTP_TEST, TRUE); + test_BindToStorage(HTTP_TEST, TRUE, TYMED_ISTREAM); + + trace("emulated http test (to object)...\n"); test_BindToObject(HTTP_TEST, TRUE); + trace("emulated http test (to file)...\n"); + test_BindToStorage(HTTP_TEST, TRUE, TYMED_FILE); + trace("about test...\n"); - test_BindToStorage(ABOUT_TEST, FALSE); + test_BindToStorage(ABOUT_TEST, FALSE, TYMED_ISTREAM); + + trace("about test (to file)...\n"); + test_BindToStorage(ABOUT_TEST, FALSE, TYMED_FILE); + + trace("about test (to object)...\n"); test_BindToObject(ABOUT_TEST, FALSE); trace("emulated about test...\n"); - test_BindToStorage(ABOUT_TEST, TRUE); + test_BindToStorage(ABOUT_TEST, TRUE, TYMED_ISTREAM); + + trace("emulated about test (to file)...\n"); + test_BindToStorage(ABOUT_TEST, TRUE, TYMED_FILE); + + trace("emulated about test (to object)...\n"); test_BindToObject(ABOUT_TEST, TRUE); trace("file test...\n"); - create_file(); - test_BindToStorage(FILE_TEST, FALSE); + test_BindToStorage(FILE_TEST, FALSE, TYMED_ISTREAM); + + trace("file test (to file)...\n"); + test_BindToStorage(FILE_TEST, FALSE, TYMED_FILE); + + trace("file test (to object)...\n"); test_BindToObject(FILE_TEST, FALSE); - DeleteFileW(wszIndexHtml); trace("emulated file test...\n"); - set_file_url(); - test_BindToStorage(FILE_TEST, TRUE); + test_BindToStorage(FILE_TEST, TRUE, TYMED_ISTREAM); + + trace("emulated file test (to file)...\n"); + test_BindToStorage(FILE_TEST, TRUE, TYMED_FILE); + + trace("emulated file test (to object)...\n"); test_BindToObject(FILE_TEST, TRUE); trace("emulated its test...\n"); - test_BindToStorage(ITS_TEST, TRUE); + test_BindToStorage(ITS_TEST, TRUE, TYMED_ISTREAM); + + trace("emulated its test (to file)...\n"); + test_BindToStorage(ITS_TEST, TRUE, TYMED_FILE); trace("emulated mk test...\n"); - test_BindToStorage(MK_TEST, TRUE); + test_BindToStorage(MK_TEST, TRUE, TYMED_ISTREAM); + + trace("test URLDownloadToFile for file protocol...\n"); + test_URLDownloadToFile(FILE_TEST, FALSE); + + trace("test URLDownloadToFile for emulated file protocol...\n"); + test_URLDownloadToFile(FILE_TEST, TRUE); + + trace("test URLDownloadToFile for http protocol...\n"); + test_URLDownloadToFile(HTTP_TEST, FALSE); trace("test failures...\n"); test_BindToStorage_fail(); + DeleteFileW(wszIndexHtml); CloseHandle(complete_event); CloseHandle(complete_event2); CoUninitialize(); + + gecko_installer_workaround(FALSE); } diff --git a/rostests/winetests/urlmon/urlmon.rbuild b/rostests/winetests/urlmon/urlmon.rbuild index ba4ef138350..07c20c419d5 100644 --- a/rostests/winetests/urlmon/urlmon.rbuild +++ b/rostests/winetests/urlmon/urlmon.rbuild @@ -5,18 +5,19 @@ . 0x600 0x600 - wine - urlmon - user32 - kernel32 - ole32 - uuid - ntdll generated.c misc.c protocol.c stream.c url.c testlist.c + wine + urlmon + ole32 + user32 + advapi32 + kernel32 + uuid + ntdll diff --git a/rostests/winetests/uxtheme/system.c b/rostests/winetests/uxtheme/system.c index 1fd3d974293..b5f661975fb 100644 --- a/rostests/winetests/uxtheme/system.c +++ b/rostests/winetests/uxtheme/system.c @@ -128,7 +128,7 @@ static void test_GetWindowTheme(void) "Expected E_HANDLE, got 0x%08x\n", GetLastError()); - /* Only do the bare minumum to get a valid hwnd */ + /* Only do the bare minimum to get a valid hwnd */ hWnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,0, 0, 0, NULL); if (!hWnd) return; @@ -161,7 +161,7 @@ static void test_SetWindowTheme(void) GetLastError()); } - /* Only do the bare minumum to get a valid hwnd */ + /* Only do the bare minimum to get a valid hwnd */ hWnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,0, 0, 0, NULL); if (!hWnd) return; @@ -231,7 +231,7 @@ static void test_OpenThemeData(void) GetLastError()); } - /* Only do the bare minumum to get a valid hdc */ + /* Only do the bare minimum to get a valid hdc */ hWnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,0, 0, 0, NULL); if (!hWnd) return; @@ -417,8 +417,10 @@ static void test_GetCurrentThemeName(void) /* Given number of characters for the theme name is too large */ SetLastError(0xdeadbeef); hRes = pGetCurrentThemeName(currentTheme, sizeof(currentTheme), NULL, 0, NULL, 0); - todo_wine - ok( hRes == E_POINTER, "Expected E_POINTER, got 0x%08x\n", hRes); + if (bThemeActive) + ok( hRes == E_POINTER || hRes == S_OK, "Expected E_POINTER or S_OK, got 0x%08x\n", hRes); + else + ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); diff --git a/rostests/winetests/uxtheme/uxtheme.rbuild b/rostests/winetests/uxtheme/uxtheme.rbuild index 1c91cd74204..7e557299de6 100644 --- a/rostests/winetests/uxtheme/uxtheme.rbuild +++ b/rostests/winetests/uxtheme/uxtheme.rbuild @@ -1,13 +1,15 @@ + . 0x600 0x600 + system.c + testlist.c wine user32 kernel32 ntdll - system.c - testlist.c + diff --git a/rostests/winetests/version/info.c b/rostests/winetests/version/info.c index be1852fc024..3bfc9fb5e40 100644 --- a/rostests/winetests/version/info.c +++ b/rostests/winetests/version/info.c @@ -44,6 +44,18 @@ "ERROR_PATH_NOT_FOUND (NT4)/ERROR_FILE_NOT_FOUND (2k3)" \ "expected, got %u\n", GetLastError()); +static void create_file(const CHAR *name) +{ + HANDLE file; + DWORD written; + + file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name); + WriteFile(file, name, strlen(name), &written, NULL); + WriteFile(file, "\n", strlen("\n"), &written, NULL); + CloseHandle(file); +} + static void test_info_size(void) { DWORD hdl, retval; char mypath[MAX_PATH] = ""; @@ -153,6 +165,19 @@ static void test_info_size(void) } else trace("skipping GetModuleFileNameA(NULL,..) failed\n"); + + create_file("test.txt"); + + /* no version info */ + SetLastError(0xdeadbeef); + hdl = 0xcafe; + retval = GetFileVersionInfoSizeA("test.txt", &hdl); + ok(retval == 0, "Expected 0, got %d\n", retval); + ok(hdl == 0, "Expected 0, got %d\n", hdl); + ok(GetLastError() == ERROR_RESOURCE_DATA_NOT_FOUND, + "Expected ERROR_RESOURCE_DATA_NOT_FOUND, got %d\n", GetLastError()); + + DeleteFileA("test.txt"); } static void VersionDwordLong2String(DWORDLONG Version, LPSTR lpszVerString) @@ -451,7 +476,8 @@ static void test_VerQueryValue(void) SetLastError(0xdeadbeef); ret = VerQueryValue(ver, "String", (LPVOID*)&p, &len); ok(!ret, "VerQueryValue should fail\n"); - ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND, + ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND || + GetLastError() == 0xdeadbeef /* Win9x, NT4, W2K */, "VerQueryValue returned %u\n", GetLastError()); ok(p == (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p); ok(len == 0, "expected 0 got %x\n", len); @@ -517,7 +543,8 @@ todo_wine ok(len == 0, "VerQueryValue returned %u, expected 0\n", len); SetLastError(0xdeadbeef); ret = VerQueryValue(ver, buf, (LPVOID*)&p, &len); ok(!ret, "VerQueryValue(%s) succeeded\n", buf); - ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND, + ok(GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND || + GetLastError() == 0xdeadbeef /* Win9x, NT4, W2K */, "VerQueryValue returned %u\n", GetLastError()); ok(p == (char *)0xdeadbeef, "expected 0xdeadbeef got %p\n", p); ok(len == 0, "expected 0 got %x\n", len); diff --git a/rostests/winetests/version/version.rbuild b/rostests/winetests/version/version.rbuild index 5846259b24a..a90ee2eae51 100644 --- a/rostests/winetests/version/version.rbuild +++ b/rostests/winetests/version/version.rbuild @@ -1,15 +1,17 @@ + . 0x600 0x600 - wine - version - kernel32 - ntdll info.c install.c version.rc testlist.c + wine + version + kernel32 + ntdll +