diff --git a/rostests/winetests/advpack/advpack.c b/rostests/winetests/advpack/advpack.c index b90df2d4b65..eeb35c6264c 100644 --- a/rostests/winetests/advpack/advpack.c +++ b/rostests/winetests/advpack/advpack.c @@ -82,7 +82,11 @@ static BOOL init_function_pointers(void) if (!pCloseINFEngine || !pDelNode || !pGetVersionFromFile || !pOpenINFEngine || !pSetPerUserSecValues || !pTranslateInfString) + { + skip("Needed functions are not available\n"); + FreeLibrary(hAdvPack); return FALSE; + } return TRUE; } @@ -331,8 +335,9 @@ static void translateinfstringex_test(void) /* try an empty filename */ hr = pOpenINFEngine("", "Options.NTx86", 0, &hinf, NULL); - ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), - "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %08x\n", hr); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) /* NT+ */ || + hr == HRESULT_FROM_WIN32(E_UNEXPECTED) /* 9x */, + "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND or E_UNEXPECTED), got %08x\n", hr); /* try a NULL hinf */ hr = pOpenINFEngine(inf_file, "Options.NTx86", 0, NULL, NULL); @@ -465,6 +470,63 @@ static void translateinfstringex_test(void) ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); DeleteFileA(inf_file); + + /* Create another .inf file which is just here to trigger a wine bug */ + { + char data[1024]; + char *ptr = data; + DWORD dwNumberOfBytesWritten; + HANDLE hf = CreateFile(inf_file, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + append_str(&ptr, "[Version]\n"); + append_str(&ptr, "Signature=\"$Chicago$\"\n"); + append_str(&ptr, "[section]\n"); + append_str(&ptr, "NotACustomDestination=Version\n"); + append_str(&ptr, "CustomDestination=CustInstDestSection\n"); + append_str(&ptr, "[CustInstDestSection]\n"); + append_str(&ptr, "49010=DestA,1\n"); + append_str(&ptr, "49020=DestB\n"); + append_str(&ptr, "49030=DestC\n"); + append_str(&ptr, "49040=DestD\n"); + append_str(&ptr, "[Options.NTx86]\n"); + append_str(&ptr, "Result2=%%49030%%\n"); + append_str(&ptr, "[DestA]\n"); + append_str(&ptr, "HKLM,\"Software\\Garbage\",\"ProgramFilesDir\",,'%%24%%'\n"); + /* The point of this test is to have HKCU just before the quoted HKLM */ + append_str(&ptr, "[DestB]\n"); + append_str(&ptr, "HKCU,\"Software\\Garbage\",\"ProgramFilesDir\",,'%%24%%'\n"); + append_str(&ptr, "[DestC]\n"); + append_str(&ptr, "'HKLM','Software\\Microsoft\\Windows\\CurrentVersion',"); + append_str(&ptr, "'ProgramFilesDir',,\"%%24%%\"\n"); + append_str(&ptr, "[DestD]\n"); + append_str(&ptr, "HKLM,\"Software\\Garbage\",\"ProgramFilesDir\",,'%%24%%'\n"); + + WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL); + CloseHandle(hf); + } + + /* open the inf with the install section */ + hr = pOpenINFEngine(inf_file, "section", 0, &hinf, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + /* Single quote test (Note size includes null on return from call) */ + memset(buffer, 'a', APP_PATH_LEN); + buffer[APP_PATH_LEN - 1] = '\0'; + size = MAX_PATH; + hr = pTranslateInfStringEx(hinf, inf_file, "Options.NTx86", "Result2", + buffer, size, &size, NULL); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok(!lstrcmpi(buffer, PROG_FILES_ROOT), + "Expected %s, got %s\n", PROG_FILES_ROOT, buffer); + ok(size == lstrlenA(PROG_FILES_ROOT)+1, "Expected size %d, got %d\n", + lstrlenA(PROG_FILES_ROOT)+1, size); + + /* close the INF again */ + hr = pCloseINFEngine(hinf); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + DeleteFileA(inf_file); } static BOOL check_reg_str(HKEY hkey, LPCSTR name, LPCSTR value) diff --git a/rostests/winetests/advpack/files.c b/rostests/winetests/advpack/files.c index 530c3b2aebc..d018975dcaf 100644 --- a/rostests/winetests/advpack/files.c +++ b/rostests/winetests/advpack/files.c @@ -63,14 +63,6 @@ static void createTestFile(const CHAR *name) static void create_test_files(void) { - int len; - - GetCurrentDirectoryA(MAX_PATH, CURR_DIR); - len = lstrlenA(CURR_DIR); - - if(len && (CURR_DIR[len-1] == '\\')) - CURR_DIR[len-1] = 0; - createTestFile("a.txt"); createTestFile("b.txt"); CreateDirectoryA("testdir", NULL); @@ -528,7 +520,21 @@ static void test_AdvInstallFile(void) START_TEST(files) { + DWORD len; + char temp_path[MAX_PATH], prev_path[MAX_PATH]; + init_function_pointers(); + + GetCurrentDirectoryA(MAX_PATH, prev_path); + GetTempPath(MAX_PATH, temp_path); + SetCurrentDirectoryA(temp_path); + + lstrcpyA(CURR_DIR, temp_path); + len = lstrlenA(CURR_DIR); + + if(len && (CURR_DIR[len - 1] == '\\')) + CURR_DIR[len - 1] = 0; + create_test_files(); create_cab_file(); @@ -539,4 +545,5 @@ START_TEST(files) delete_test_files(); FreeLibrary(hAdvPack); + SetCurrentDirectoryA(prev_path); } diff --git a/rostests/winetests/advpack/install.c b/rostests/winetests/advpack/install.c index 564ecda71c9..854ede6dae5 100644 --- a/rostests/winetests/advpack/install.c +++ b/rostests/winetests/advpack/install.c @@ -73,9 +73,7 @@ static void create_inf_file(LPCSTR filename) append_str(&ptr, "Signature=\"$Chicago$\"\n"); append_str(&ptr, "AdvancedINF=2.5\n"); append_str(&ptr, "[DefaultInstall]\n"); - append_str(&ptr, "RegisterOCXs=RegisterOCXsSection\n"); - append_str(&ptr, "[RegisterOCXsSection]\n"); - append_str(&ptr, "%%11%%\\ole32.dll\n"); + append_str(&ptr, "CheckAdminRights=1\n"); WriteFile(hf, data, ptr - data, &dwNumberOfBytesWritten, NULL); CloseHandle(hf); @@ -118,7 +116,9 @@ static void test_RunSetupCommand(void) /* try to run an exe with the RSC_FLAG_INF flag */ hexe = (HANDLE)0xdeadbeef; hr = pRunSetupCommand(NULL, "winver.exe", "Install", systemdir, "Title", &hexe, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); - ok(is_spapi_err(hr), "Expected a setupapi error, got %d\n", hr); + ok(is_spapi_err(hr) || + hr == E_FAIL, /* win9x */ + "Expected a setupapi error or E_FAIL, got %d\n", hr); ok(hexe == (HANDLE)0xdeadbeef, "Expected hexe to be 0xdeadbeef\n"); ok(!TerminateProcess(hexe, 0), "Expected TerminateProcess to fail\n"); @@ -151,7 +151,9 @@ static void test_RunSetupCommand(void) /* try a relative path to the INF, with working dir provided */ hr = pRunSetupCommand(NULL, "one\\test.inf", "DefaultInstall", dir, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); - ok(hr == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", hr); + ok(hr == ERROR_SUCCESS || + hr == E_FAIL, /* win9x */ + "Expected ERROR_SUCCESS, got %d\n", hr); /* try a relative path to the INF, NULL working dir */ hr = pRunSetupCommand(NULL, "one\\test.inf", "DefaultInstall", NULL, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); @@ -160,12 +162,15 @@ static void test_RunSetupCommand(void) /* try a relative path to the INF, empty working dir */ hr = pRunSetupCommand(NULL, "one\\test.inf", "DefaultInstall", "", "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); - ok(hr == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", hr); + ok(hr == ERROR_SUCCESS || + hr == E_FAIL, /* win9x */ + "Expected ERROR_SUCCESS or E_FAIL, got %d\n", hr); /* try only the INF filename, with working dir provided */ hr = pRunSetupCommand(NULL, "test.inf", "DefaultInstall", dir, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); - ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), - "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %d\n", hr); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + hr == E_FAIL, /* win9x */ + "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or E_FAIL, got %d\n", hr); /* try only the INF filename, NULL working dir */ hr = pRunSetupCommand(NULL, "test.inf", "DefaultInstall", NULL, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); @@ -174,8 +179,9 @@ static void test_RunSetupCommand(void) /* try only the INF filename, empty working dir */ hr = pRunSetupCommand(NULL, "test.inf", "DefaultInstall", "", "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); - ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), - "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %d\n", hr); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + hr == E_FAIL, /* win9x */ + "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or E_FAIL, got %d\n", hr); DeleteFileA("one\\test.inf"); RemoveDirectoryA("one"); @@ -184,8 +190,9 @@ static void test_RunSetupCommand(void) /* try INF file in the current directory, working directory provided */ hr = pRunSetupCommand(NULL, "test.inf", "DefaultInstall", CURR_DIR, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); - ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), - "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %d\n", hr); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + hr == E_FAIL, /* win9x */ + "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or E_FAIL, got %d\n", hr); /* try INF file in the current directory, NULL working directory */ hr = pRunSetupCommand(NULL, "test.inf", "DefaultInstall", NULL, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); @@ -194,8 +201,9 @@ static void test_RunSetupCommand(void) /* try INF file in the current directory, empty working directory */ hr = pRunSetupCommand(NULL, "test.inf", "DefaultInstall", CURR_DIR, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); - ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), - "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %d\n", hr); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + hr == E_FAIL, /* win9x */ + "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or E_FAIL, got %d\n", hr); } static void test_LaunchINFSection(void) @@ -266,14 +274,26 @@ static void test_LaunchINFSectionEx(void) START_TEST(install) { + DWORD len; + char temp_path[MAX_PATH], prev_path[MAX_PATH]; + if (!init_function_pointers()) return; - GetCurrentDirectoryA(MAX_PATH, CURR_DIR); + GetCurrentDirectoryA(MAX_PATH, prev_path); + GetTempPath(MAX_PATH, temp_path); + SetCurrentDirectoryA(temp_path); + + lstrcpyA(CURR_DIR, temp_path); + len = lstrlenA(CURR_DIR); + + if(len && (CURR_DIR[len - 1] == '\\')) + CURR_DIR[len - 1] = 0; test_RunSetupCommand(); test_LaunchINFSection(); test_LaunchINFSectionEx(); FreeLibrary(hAdvPack); + SetCurrentDirectoryA(prev_path); } diff --git a/rostests/winetests/comctl32/comboex.c b/rostests/winetests/comctl32/comboex.c index ad58643f648..eca7ca4b6ee 100644 --- a/rostests/winetests/comctl32/comboex.c +++ b/rostests/winetests/comctl32/comboex.c @@ -169,7 +169,106 @@ static void test_comboboxex(void) { /* Cleanup */ HeapFree(GetProcessHeap(), 0, textBuffer); + DestroyWindow(myHwnd); +} +static void test_WM_LBUTTONDOWN(void) +{ + HWND hComboEx, hCombo, hEdit, hList; + COMBOBOXINFO cbInfo; + UINT x, y, item_height; + LRESULT result; + int i, idx; + RECT rect; + WCHAR buffer[3]; + static const UINT choices[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72}; + static const WCHAR stringFormat[] = {'%','2','d','\0'}; + + hComboEx = CreateWindowExA(0, WC_COMBOBOXEXA, NULL, + WS_VISIBLE|WS_CHILD|CBS_DROPDOWN, 0, 0, 200, 150, + hComboExParentWnd, NULL, hMainHinst, NULL); + + for (i = 0; i < sizeof(choices)/sizeof(UINT); i++){ + COMBOBOXEXITEMW cbexItem; + wsprintfW(buffer, stringFormat, choices[i]); + + memset(&cbexItem, 0x00, sizeof(cbexItem)); + cbexItem.mask = CBEIF_TEXT; + cbexItem.iItem = i; + cbexItem.pszText = buffer; + cbexItem.cchTextMax = 0; + ok(SendMessageW(hComboEx, CBEM_INSERTITEMW, 0, (LPARAM)&cbexItem) >= 0, + "Failed to add item %d\n", i); + } + + hCombo = (HWND)SendMessage(hComboEx, CBEM_GETCOMBOCONTROL, 0, 0); + hEdit = (HWND)SendMessage(hComboEx, CBEM_GETEDITCONTROL, 0, 0); + + cbInfo.cbSize = sizeof(COMBOBOXINFO); + result = SendMessage(hCombo, CB_GETCOMBOBOXINFO, 0, (LPARAM)&cbInfo); + ok(result, "Failed to get combobox info structure. LastError=%d\n", + GetLastError()); + hList = cbInfo.hwndList; + + trace("hWnd=%p, hComboEx=%p, hCombo=%p, hList=%p, hEdit=%p\n", + hComboExParentWnd, hComboEx, hCombo, hList, hEdit); + ok(GetFocus() == hComboExParentWnd, + "Focus not on Main Window, instead on %p\n", GetFocus()); + + /* Click on the button to drop down the list */ + x = cbInfo.rcButton.left + (cbInfo.rcButton.right-cbInfo.rcButton.left)/2; + y = cbInfo.rcButton.top + (cbInfo.rcButton.bottom-cbInfo.rcButton.top)/2; + result = SendMessage(hCombo, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); + ok(result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", + GetLastError()); + ok(GetFocus() == hCombo, + "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", + GetFocus()); + ok(SendMessage(hComboEx, CB_GETDROPPEDSTATE, 0, 0), + "The dropdown list should have appeared after clicking the button.\n"); + idx = SendMessage(hCombo, CB_GETTOPINDEX, 0, 0); + ok(idx == 0, "For TopIndex expected %d, got %d\n", 0, idx); + + result = SendMessage(hCombo, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); + ok(result, "WM_LBUTTONUP was not processed. LastError=%d\n", + GetLastError()); + ok(GetFocus() == hCombo, + "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", + GetFocus()); + + /* Click on the 5th item in the list */ + item_height = SendMessage(hCombo, CB_GETITEMHEIGHT, 0, 0); + ok(GetClientRect(hList, &rect), "Failed to get list's client rect.\n"); + x = rect.left + (rect.right-rect.left)/2; + y = item_height/2 + item_height*4; + result = SendMessage(hList, WM_MOUSEMOVE, 0, MAKELPARAM(x, y)); + ok(!result, "WM_MOUSEMOVE was not processed. LastError=%d\n", + GetLastError()); + ok(GetFocus() == hCombo, + "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", + GetFocus()); + + result = SendMessage(hList, WM_LBUTTONDOWN, 0, MAKELPARAM(x, y)); + ok(!result, "WM_LBUTTONDOWN was not processed. LastError=%d\n", + GetLastError()); + ok(GetFocus() == hCombo, + "Focus not on ComboBoxEx's ComboBox Control, instead on %p\n", + GetFocus()); + ok(SendMessage(hComboEx, CB_GETDROPPEDSTATE, 0, 0), + "The dropdown list should still be visible.\n"); + + result = SendMessage(hList, WM_LBUTTONUP, 0, MAKELPARAM(x, y)); + ok(!result, "WM_LBUTTONUP was not processed. LastError=%d\n", + GetLastError()); + todo_wine ok(GetFocus() == hEdit, + "Focus not on ComboBoxEx's Edit Control, instead on %p\n", + GetFocus()); + ok(!SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0), + "The dropdown list should have been rolled up.\n"); + idx = SendMessage(hComboEx, CB_GETCURSEL, 0, 0); + ok(idx == 4, "Current Selection: expected %d, got %d\n", 4, idx); + + DestroyWindow(hComboEx); } static LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) @@ -217,7 +316,7 @@ static int init(void) wc.lpfnWndProc = ComboExTestWndProc; RegisterClassA(&wc); - hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW, + hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW|WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0); assert(hComboExParentWnd != NULL); @@ -244,6 +343,7 @@ START_TEST(comboex) return; test_comboboxex(); + test_WM_LBUTTONDOWN(); cleanup(); } diff --git a/rostests/winetests/comctl32/dpa.c b/rostests/winetests/comctl32/dpa.c index 552387f6fce..b2ea3d8c327 100644 --- a/rostests/winetests/comctl32/dpa.c +++ b/rostests/winetests/comctl32/dpa.c @@ -25,6 +25,7 @@ #include "windef.h" #include "winbase.h" +#include "wingdi.h" #include "winuser.h" #include "commctrl.h" #include "objidl.h" diff --git a/rostests/winetests/comctl32/listview.c b/rostests/winetests/comctl32/listview.c index 91f9d00c8d4..23b5f90e9b8 100644 --- a/rostests/winetests/comctl32/listview.c +++ b/rostests/winetests/comctl32/listview.c @@ -848,9 +848,9 @@ static void test_icon_spacing(void) { /* LVM_SETICONSPACING */ /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */ - /* note: the first test will fail if the default icon spacing is not (43,43) */ HWND hwnd; + WORD w, h; DWORD r; hwnd = create_custom_listview_control(LVS_ICON); @@ -859,17 +859,22 @@ static void test_icon_spacing(void) r = SendMessage(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, (LPARAM)NF_REQUERY); expect(NFR_ANSI, r); + r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(-1, -1)); + w = LOWORD(r); + h = LOWORD(r); + flush_sequences(sequences, NUM_MSG_SEQUENCES); trace("test icon spacing\n"); - todo_wine { - r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(20, 30)); - expect(MAKELONG(43,43), r); - } - r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(25, 35)); - expect(MAKELONG(20,30), r); - r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(-1,-1)); - expect(MAKELONG(25,35), r); + + r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(20, 30)); + expect(MAKELONG(w,h), r); + + r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(25, 35)); + expect(MAKELONG(20,30), r); + + r = SendMessage(hwnd, LVM_SETICONSPACING, 0, (LPARAM) MAKELONG(-1,-1)); + expect(MAKELONG(25,35), r); ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_icon_spacing_seq, "test icon spacing seq", FALSE); @@ -1127,6 +1132,81 @@ static void test_getorigin(void) } +static void test_multiselect(void) +{ + typedef struct t_select_task + { + const char *descr; + int initPos; + int loopVK; + int count; + int result; + } select_task; + + HWND hwnd; + DWORD r; + int i,j,item_count,selected_count; + static const int items=5; + BYTE kstate[256]; + select_task task; + + static struct t_select_task task_list[] = { + { "using VK_DOWN", 0, VK_DOWN, -1, -1 }, + { "using VK_UP", -1, VK_UP, -1, -1 }, + { "using VK_END", 0, VK_END, 1, -1 }, + { "using VK_HOME", -1, VK_HOME, 1, -1 } + }; + + + hwnd = create_listview_control(); + + for (i=0;icode == CDN_INITDONE) { PostMessage( GetParent(hDlg), WM_COMMAND, IDCANCEL, FALSE); + } else if (nmh->code == CDN_FOLDERCHANGE ) + { + char buf[1024]; + int ret; + + memset(buf, 0x66, sizeof(buf)); + ret = SendMessage( GetParent(hDlg), CDM_GETFOLDERIDLIST, 5, (LPARAM)buf); + ok(ret > 0, "CMD_GETFOLDERIDLIST not implemented\n"); + if (ret > 5) + ok(buf[0] == 0x66 && buf[1] == 0x66, "CMD_GETFOLDERIDLIST: The buffer was touched on failure\n"); } } @@ -47,6 +57,9 @@ static void test_DialogCancel(void) OPENFILENAMEA ofn; BOOL result; char szFileName[MAX_PATH] = ""; + char szInitialDir[MAX_PATH]; + + GetWindowsDirectory(szInitialDir, MAX_PATH); ZeroMemory(&ofn, sizeof(ofn)); @@ -58,6 +71,7 @@ static void test_DialogCancel(void) ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLEHOOK; ofn.lpstrDefExt = "txt"; ofn.lpfnHook = (LPOFNHOOKPROC) OFNHookProc; + ofn.lpstrInitialDir = szInitialDir; PrintDlgA(NULL); ok(CDERR_INITIALIZATION == CommDlgExtendedError(), "expected %d, got %d\n", @@ -68,21 +82,6 @@ static void test_DialogCancel(void) ok(0 == CommDlgExtendedError(), "expected %d, got %d\n", 0, CommDlgExtendedError()); - PrintDlgA(NULL); - ok(CDERR_INITIALIZATION == CommDlgExtendedError(), "expected %d, got %d\n", - CDERR_INITIALIZATION, CommDlgExtendedError()); - - SetLastError(0xdeadbeef); - result = GetOpenFileNameW((LPOPENFILENAMEW) &ofn); - if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) - skip("GetOpenFileNameW is not implemented\n"); - else - { - ok(0 == result, "expected %d, got %d\n", 0, result); - ok(0 == CommDlgExtendedError(), "expected %d, got %d\n", 0, - CommDlgExtendedError()); - } - PrintDlgA(NULL); ok(CDERR_INITIALIZATION == CommDlgExtendedError(), "expected %d, got %d\n", CDERR_INITIALIZATION, CommDlgExtendedError()); @@ -96,6 +95,28 @@ static void test_DialogCancel(void) ok(CDERR_INITIALIZATION == CommDlgExtendedError(), "expected %d, got %d\n", CDERR_INITIALIZATION, CommDlgExtendedError()); + /* Before passing the ofn to Unicode functions, remove the ANSI strings */ + ofn.lpstrFilter = NULL; + ofn.lpstrInitialDir = NULL; + ofn.lpstrDefExt = NULL; + + PrintDlgA(NULL); + ok(CDERR_INITIALIZATION == CommDlgExtendedError(), "expected %d, got %d\n", + CDERR_INITIALIZATION, CommDlgExtendedError()); + + SetLastError(0xdeadbeef); + result = GetOpenFileNameW((LPOPENFILENAMEW) &ofn); + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + skip("GetOpenFileNameW is not implemented\n"); + else + { + ok(0 == result, "expected %d, got %d\n", 0, result); + ok(0 == CommDlgExtendedError() || + CDERR_INITIALIZATION == CommDlgExtendedError(), /* win9x */ + "expected %d or %d, got %d\n", 0, CDERR_INITIALIZATION, + CommDlgExtendedError()); + } + SetLastError(0xdeadbeef); result = GetSaveFileNameW((LPOPENFILENAMEW) &ofn); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) @@ -103,7 +124,9 @@ static void test_DialogCancel(void) else { ok(0 == result, "expected %d, got %d\n", 0, result); - ok(0 == CommDlgExtendedError(), "expected %d, got %d\n", 0, + ok(0 == CommDlgExtendedError() || + CDERR_INITIALIZATION == CommDlgExtendedError(), /* win9x */ + "expected %d or %d, got %d\n", 0, CDERR_INITIALIZATION, CommDlgExtendedError()); } } diff --git a/rostests/winetests/comdlg32/printdlg.c b/rostests/winetests/comdlg32/printdlg.c index 31e57cf8ea8..fef274de27b 100644 --- a/rostests/winetests/comdlg32/printdlg.c +++ b/rostests/winetests/comdlg32/printdlg.c @@ -51,8 +51,7 @@ static LPCSTR load_functions(void) LPCSTR ptr; ptr = "comdlg32.dll"; - hcomdlg32 = LoadLibraryA(ptr); - if (!hcomdlg32) return ptr; + hcomdlg32 = GetModuleHandleA(ptr); ptr = "PrintDlgExA"; pPrintDlgExA = (void *) GetProcAddress(hcomdlg32, ptr); diff --git a/rostests/winetests/gdiplus/font.c b/rostests/winetests/gdiplus/font.c index 71e6f9a7bf2..59a8d532177 100644 --- a/rostests/winetests/gdiplus/font.c +++ b/rostests/winetests/gdiplus/font.c @@ -24,7 +24,59 @@ #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) -static WCHAR arial[] = {'A','r','i','a','l','\0'}; +static const WCHAR arial[] = {'A','r','i','a','l','\0'}; +static const WCHAR nonexistant[] = {'T','h','i','s','F','o','n','t','s','h','o','u','l','d','N','o','t','E','x','i','s','t','\0'}; +static const WCHAR MSSansSerif[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}; +static const WCHAR MicrosoftSansSerif[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f','\0'}; +static const WCHAR TimesNewRoman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'}; +static const WCHAR CourierNew[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'}; + +static const char *debugstr_w(LPCWSTR str) +{ + static char buf[1024]; + WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); + return buf; +} + + +static void test_createfont(void) +{ + GpFontFamily* fontfamily = NULL; + GpFont* font = NULL; + GpStatus stat; + Unit unit; + UINT i; + REAL size; + + stat = GdipCreateFontFamilyFromName(nonexistant, NULL, &fontfamily); + expect (FontFamilyNotFound, stat); + stat = GdipDeleteFont(font); + expect (InvalidParameter, stat); + stat = GdipCreateFontFamilyFromName(arial, NULL, &fontfamily); + expect (Ok, stat); + stat = GdipCreateFont(fontfamily, 12, FontStyleRegular, UnitPoint, &font); + expect (Ok, stat); + stat = GdipGetFontUnit (font, &unit); + expect (Ok, stat); + expect (UnitPoint, unit); + + /* Test to see if returned size is based on unit (its not) */ + GdipGetFontSize(font, &size); + ok (size == 12, "Expected 12, got %f\n", size); + GdipDeleteFont(font); + + /* Make sure everything is converted correctly for all Units */ + for (i = UnitWorld; i <=UnitMillimeter; i++) + { + if (i == UnitDisplay) continue; /* Crashes WindowsXP, wtf? */ + GdipCreateFont(fontfamily, 24, FontStyleRegular, i, &font); + GdipGetFontSize (font, &size); + ok (size == 24, "Expected 24, got %f (with unit: %d)\n", size, i); + GdipGetFontUnit (font, &unit); + expect (i, unit); + GdipDeleteFont(font); + } +} static void test_logfont(void) { @@ -94,6 +146,95 @@ static void test_logfont(void) ReleaseDC(0, hdc); } +static void test_fontfamily (void) +{ + GpFontFamily** family = NULL; + WCHAR itsName[LF_FACESIZE]; + GpStatus stat; + + /* FontFamily can not be NULL */ + stat = GdipCreateFontFamilyFromName (arial , NULL, family); + expect (InvalidParameter, stat); + + family = GdipAlloc (sizeof (GpFontFamily*)); + + /* FontFamily must be able to actually find the family. + * If it can't, any subsequent calls should fail + * + * We currently fail (meaning we don't) because we don't actually + * test to see if we can successfully get a family + */ + stat = GdipCreateFontFamilyFromName (nonexistant, NULL, family); + expect (FontFamilyNotFound, stat); + stat = GdipGetFamilyName (*family,itsName, LANG_NEUTRAL); + expect (InvalidParameter, stat); + ok ((lstrcmpiW(itsName,nonexistant) != 0), + "Expected a non-zero value for nonexistant font!\n"); + stat = GdipDeleteFontFamily(*family); + expect (InvalidParameter, stat); + + stat = GdipCreateFontFamilyFromName (arial, NULL, family); + expect (Ok, stat); + + stat = GdipGetFamilyName (*family, itsName, LANG_NEUTRAL); + expect (Ok, stat); + expect (0, lstrcmpiW(itsName,arial)); + + if (0) + { + /* Crashes on Windows XP SP2, Vista, and so Wine as well */ + stat = GdipGetFamilyName (*family, NULL, LANG_NEUTRAL); + expect (Ok, stat); + } + + stat = GdipDeleteFontFamily(*family); + expect (Ok, stat); + + GdipFree (family); +} + + +static void test_getgenerics (void) +{ + GpStatus stat; + GpFontFamily** family; + WCHAR familyName[LF_FACESIZE]; + ZeroMemory(familyName, sizeof(familyName)/sizeof(WCHAR)); + + family = GdipAlloc (sizeof (GpFontFamily*)); + + stat = GdipGetGenericFontFamilySansSerif (family); + expect (Ok, stat); + stat = GdipGetFamilyName (*family, familyName, LANG_NEUTRAL); + expect (Ok, stat); + ok ((lstrcmpiW(familyName, MicrosoftSansSerif) == 0) || + (lstrcmpiW(familyName,MSSansSerif) == 0), + "Expected Microsoft Sans Serif or MS Sans Serif, got %s\n", + debugstr_w(familyName)); + stat = GdipDeleteFontFamily (*family); + expect (Ok, stat); + + stat = GdipGetGenericFontFamilySerif (family); + expect (Ok, stat); + stat = GdipGetFamilyName (*family, familyName, LANG_NEUTRAL); + expect (Ok, stat); + ok (lstrcmpiW(familyName, TimesNewRoman) == 0, + "Expected Times New Roman, got %s\n", debugstr_w(familyName)); + stat = GdipDeleteFontFamily (*family); + expect (Ok, stat); + + stat = GdipGetGenericFontFamilyMonospace (family); + expect (Ok, stat); + stat = GdipGetFamilyName (*family, familyName, LANG_NEUTRAL); + expect (Ok, stat); + ok (lstrcmpiW(familyName, CourierNew) == 0, + "Expected Courier New, got %s\n", debugstr_w(familyName)); + stat = GdipDeleteFontFamily (*family); + expect (Ok, stat); + + GdipFree (family); +} + START_TEST(font) { struct GdiplusStartupInput gdiplusStartupInput; @@ -106,7 +247,10 @@ START_TEST(font) GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + test_createfont(); test_logfont(); + test_fontfamily(); + test_getgenerics(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/gdiplus.rbuild b/rostests/winetests/gdiplus/gdiplus.rbuild index 06a12420a88..3b295ffb5a5 100644 --- a/rostests/winetests/gdiplus/gdiplus.rbuild +++ b/rostests/winetests/gdiplus/gdiplus.rbuild @@ -1,22 +1,26 @@ + + + - . - - 0x600 - 0x501 - 0x501 - wine - gdiplus - user32 - gdi32 - kernel32 - ntdll - brush.c - font.c - graphics.c - graphicspath.c - image.c - matrix.c - pen.c - stringformat.c - testlist.c - \ No newline at end of file + . + 0x600 + 0x600 + brush.c + font.c + graphics.c + graphicspath.c + image.c + matrix.c + pathiterator.c + pen.c + region.c + stringformat.c + testlist.c + wine + gdiplus + user32 + gdi32 + kernel32 + ntdll + + diff --git a/rostests/winetests/gdiplus/graphicspath.c b/rostests/winetests/gdiplus/graphicspath.c index e797b444df4..9f9af9cd50c 100644 --- a/rostests/winetests/gdiplus/graphicspath.c +++ b/rostests/winetests/gdiplus/graphicspath.c @@ -149,6 +149,36 @@ static void test_constructor_destructor(void) expect(Ok, status); } +static void test_getpathdata(void) +{ + GpPath *path; + GpPathData data; + GpStatus status; + INT count; + + GdipCreatePath(FillModeAlternate, &path); + status = GdipAddPathLine(path, 5.0, 5.0, 100.0, 50.0); + expect(Ok, status); + + /* Prepare storage. Made by wrapper class. */ + status = GdipGetPointCount(path, &count); + expect(Ok, status); + + data.Count = 2; + data.Types = GdipAlloc(sizeof(BYTE) * count); + data.Points = GdipAlloc(sizeof(PointF) * count); + + status = GdipGetPathData(path, &data); + expect(Ok, status); + expect((data.Points[0].X == 5.0) && (data.Points[0].Y == 5.0) && + (data.Points[1].X == 100.0) && (data.Points[1].Y == 50.0), TRUE); + expect((data.Types[0] == PathPointTypeStart) && (data.Types[1] == PathPointTypeLine), TRUE); + + GdipFree(data.Points); + GdipFree(data.Types); + GdipDeletePath(path); +} + static path_test_t line2_path[] = { {0.0, 50.0, PathPointTypeStart, 0, 0}, /*0*/ {5.0, 45.0, PathPointTypeLine, 0, 0}, /*1*/ @@ -545,6 +575,55 @@ static void test_linei(void) GdipDeletePath(path); } +static path_test_t poly_path[] = { + {5.00, 5.00, PathPointTypeStart, 0, 0}, /*1*/ + {6.00, 8.00, PathPointTypeLine, 0, 0}, /*2*/ + {0.00, 0.00, PathPointTypeStart, 0, 0}, /*3*/ + {10.00, 10.00, PathPointTypeLine, 0, 0}, /*4*/ + {10.00, 20.00, PathPointTypeLine, 0, 0}, /*5*/ + {30.00, 10.00, PathPointTypeLine, 0, 0}, /*6*/ + {20.00, 0.00, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*7*/ + }; + +static void test_polygon(void) +{ + GpStatus status; + GpPath *path; + GpPointF points[5]; + + points[0].X = 0.0; + points[0].Y = 0.0; + points[1].X = 10.0; + points[1].Y = 10.0; + points[2].X = 10.0; + points[2].Y = 20.0; + points[3].X = 30.0; + points[3].Y = 10.0; + points[4].X = 20.0; + points[4].Y = 0.0; + + GdipCreatePath(FillModeAlternate, &path); + + /* NULL args */ + status = GdipAddPathPolygon(NULL, points, 5); + expect(InvalidParameter, status); + status = GdipAddPathPolygon(path, NULL, 5); + expect(InvalidParameter, status); + /* Polygon should have 3 points at least */ + status = GdipAddPathPolygon(path, points, 2); + expect(InvalidParameter, status); + + /* to test how it prolongs not empty path */ + status = GdipAddPathLine(path, 5.0, 5.0, 6.0, 8.0); + expect(Ok, status); + status = GdipAddPathPolygon(path, points, 5); + expect(Ok, status); + /* check resulting path */ + ok_path(path, poly_path, sizeof(poly_path)/sizeof(path_test_t), FALSE); + + GdipDeletePath(path); +} + static path_test_t rect_path[] = { {5.0, 5.0, PathPointTypeStart, 0, 0}, /*0*/ {105.0, 5.0, PathPointTypeLine, 0, 0}, /*1*/ @@ -561,6 +640,7 @@ static void test_rect(void) { GpStatus status; GpPath *path; + GpRectF rects[2]; GdipCreatePath(FillModeAlternate, &path); status = GdipAddPathRectangle(path, 5.0, 5.0, 100.0, 50.0); @@ -571,6 +651,49 @@ static void test_rect(void) ok_path(path, rect_path, sizeof(rect_path)/sizeof(path_test_t), FALSE); GdipDeletePath(path); + + GdipCreatePath(FillModeAlternate, &path); + + rects[0].X = 5.0; + rects[0].Y = 5.0; + rects[0].Width = 100.0; + rects[0].Height = 50.0; + rects[1].X = 100.0; + rects[1].Y = 50.0; + rects[1].Width = 120.0; + rects[1].Height = 30.0; + + status = GdipAddPathRectangles(path, (GDIPCONST GpRectF*)&rects, 2); + expect(Ok, status); + + ok_path(path, rect_path, sizeof(rect_path)/sizeof(path_test_t), FALSE); + + GdipDeletePath(path); +} + +static void test_lastpoint(void) +{ + GpStatus status; + GpPath *path; + GpPointF ptf; + + GdipCreatePath(FillModeAlternate, &path); + status = GdipAddPathRectangle(path, 5.0, 5.0, 100.0, 50.0); + expect(Ok, status); + + /* invalid args */ + status = GdipGetPathLastPoint(NULL, &ptf); + expect(InvalidParameter, status); + status = GdipGetPathLastPoint(path, NULL); + expect(InvalidParameter, status); + status = GdipGetPathLastPoint(NULL, NULL); + expect(InvalidParameter, status); + + status = GdipGetPathLastPoint(path, &ptf); + expect(Ok, status); + expect(TRUE, (ptf.X == 5.0) && (ptf.Y == 55.0)); + + GdipDeletePath(path); } START_TEST(graphicspath) @@ -586,6 +709,7 @@ START_TEST(graphicspath) GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); test_constructor_destructor(); + test_getpathdata(); test_line2(); test_arc(); test_worldbounds(); @@ -593,6 +717,8 @@ START_TEST(graphicspath) test_ellipse(); test_linei(); test_rect(); + test_polygon(); + test_lastpoint(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/image.c b/rostests/winetests/gdiplus/image.c index a3e76762f06..38a58b9c689 100644 --- a/rostests/winetests/gdiplus/image.c +++ b/rostests/winetests/gdiplus/image.c @@ -106,6 +106,32 @@ static void test_GetImageDimension(void) GdipDisposeImage((GpImage*)bm); } +static void test_GdipImageGetFrameDimensionsCount(void) +{ + GpBitmap *bm; + GpStatus stat; + const REAL WIDTH = 10.0, HEIGHT = 20.0; + UINT w; + + bm = (GpBitmap*)0xdeadbeef; + stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB,NULL, &bm); + expect(Ok,stat); + ok((GpBitmap*)0xdeadbeef != bm, "Expected bitmap to not be 0xdeadbeef\n"); + ok(NULL != bm, "Expected bitmap to not be NULL\n"); + + stat = GdipImageGetFrameDimensionsCount(NULL,&w); + expect(InvalidParameter, stat); + + stat = GdipImageGetFrameDimensionsCount((GpImage*)bm,NULL); + expect(InvalidParameter, stat); + + w = -1; + stat = GdipImageGetFrameDimensionsCount((GpImage*)bm,&w); + expect(Ok, stat); + expect(1, w); + GdipDisposeImage((GpImage*)bm); +} + static void test_LoadingImages(void) { GpStatus stat; @@ -452,6 +478,35 @@ static void test_GdipGetImageFlags(void) expect(InvalidParameter, stat); } +static void test_GdipCloneImage(void) +{ + GpStatus stat; + GpRectF rectF; + GpUnit unit; + GpBitmap *bm; + GpImage *image_src, *image_dest = NULL; + const INT WIDTH = 10, HEIGHT = 20; + + /* Create an image, clone it, delete the original, make sure the copy works */ + stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm); + expect(Ok, stat); +todo_wine +{ + image_src = ((GpImage*)bm); + stat = GdipCloneImage(image_src, &image_dest); + expect(Ok, stat); +} + stat = GdipDisposeImage((GpImage*)bm); + expect(Ok, stat); +todo_wine +{ + stat = GdipGetImageBounds(image_dest, &rectF, &unit); + expect(Ok, stat); + stat = GdipDisposeImage(image_dest); + expect(Ok, stat); +} +} + START_TEST(image) { struct GdiplusStartupInput gdiplusStartupInput; @@ -466,12 +521,14 @@ START_TEST(image) test_Scan0(); test_GetImageDimension(); + test_GdipImageGetFrameDimensionsCount(); test_LoadingImages(); test_SavingImages(); test_encoders(); test_LockBits(); test_GdipCreateBitmapFromHBITMAP(); test_GdipGetImageFlags(); + test_GdipCloneImage(); GdiplusShutdown(gdiplusToken); } diff --git a/rostests/winetests/gdiplus/pathiterator.c b/rostests/winetests/gdiplus/pathiterator.c new file mode 100644 index 00000000000..baeb22ba6f2 --- /dev/null +++ b/rostests/winetests/gdiplus/pathiterator.c @@ -0,0 +1,109 @@ +/* + * Unit test suite for pathiterator + * + * Copyright (C) 2008 Nikolay Sivov + * + * 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 "windows.h" +#include "gdiplus.h" +#include "wine/test.h" + +#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) + +static void test_constructor_destructor(void) +{ + GpPath *path; + GpPathIterator *iter; + GpStatus stat; + + GdipCreatePath(FillModeAlternate, &path); + GdipAddPathRectangle(path, 5.0, 5.0, 100.0, 50.0); + + /* NULL args */ + stat = GdipCreatePathIter(NULL, NULL); + expect(InvalidParameter, stat); + stat = GdipCreatePathIter(&iter, NULL); + expect(InvalidParameter, stat); + stat = GdipCreatePathIter(NULL, path); + expect(InvalidParameter, stat); + stat = GdipDeletePathIter(NULL); + expect(InvalidParameter, stat); + + /* valid args */ + stat = GdipCreatePathIter(&iter, path); + expect(Ok, stat); + + GdipDeletePathIter(iter); + GdipDeletePath(path); +} + +static void test_hascurve(void) +{ + GpPath *path; + GpPathIterator *iter; + GpStatus stat; + BOOL hasCurve; + + GdipCreatePath(FillModeAlternate, &path); + GdipAddPathRectangle(path, 5.0, 5.0, 100.0, 50.0); + + stat = GdipCreatePathIter(&iter, path); + expect(Ok, stat); + + /* NULL args + BOOL out argument is local in wrapper class method, + so it always has not-NULL address */ + stat = GdipPathIterHasCurve(NULL, &hasCurve); + expect(InvalidParameter, stat); + + /* valid args */ + stat = GdipPathIterHasCurve(iter, &hasCurve); + expect(Ok, stat); + expect(FALSE, hasCurve); + + GdipDeletePathIter(iter); + + GdipAddPathEllipse(path, 0.0, 0.0, 35.0, 70.0); + + stat = GdipCreatePathIter(&iter, path); + expect(Ok, stat); + + stat = GdipPathIterHasCurve(iter, &hasCurve); + expect(Ok, stat); + expect(TRUE, hasCurve); + + GdipDeletePathIter(iter); + GdipDeletePath(path); +} + +START_TEST(pathiterator) +{ + struct GdiplusStartupInput gdiplusStartupInput; + ULONG_PTR gdiplusToken; + + gdiplusStartupInput.GdiplusVersion = 1; + gdiplusStartupInput.DebugEventCallback = NULL; + gdiplusStartupInput.SuppressBackgroundThread = 0; + gdiplusStartupInput.SuppressExternalCodecs = 0; + + GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + + test_constructor_destructor(); + test_hascurve(); + + GdiplusShutdown(gdiplusToken); +} diff --git a/rostests/winetests/gdiplus/region.c b/rostests/winetests/gdiplus/region.c new file mode 100644 index 00000000000..166df2d17d9 --- /dev/null +++ b/rostests/winetests/gdiplus/region.c @@ -0,0 +1,222 @@ +/* + * Unit test suite for gdiplus regions + * + * Copyright (C) 2008 Huw Davies + * + * 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 "windows.h" +#include "gdiplus.h" +#include "wingdi.h" +#include "wine/test.h" + +static inline void expect_dword(DWORD *value, DWORD expected) +{ + ok(*value == expected, "expected %08x got %08x\n", expected, *value); +} + +static inline void expect_float(DWORD *value, FLOAT expected) +{ + FLOAT valuef = *(FLOAT*)value; + ok(valuef == expected, "expected %f got %f\n", expected, valuef); +} + +static void test_create_rgn(void) +{ + GpStatus status; + GpRegion *region, *region2; + UINT needed; + DWORD buf[100]; + GpRect rect; + + status = GdipCreateRegion(®ion); +todo_wine + ok(status == Ok, "status %08x\n", status); + + if(status != Ok) return; + + status = GdipGetRegionDataSize(region, &needed); + ok(status == Ok, "status %08x\n", status); + ok(needed == 20, "got %d\n", needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + ok(status == Ok, "status %08x\n", status); + ok(needed == 20, "got %d\n", needed); + expect_dword(buf, 12); + trace("buf[1] = %08x\n", buf[1]); + expect_dword(buf + 2, 0xdbc01001); + expect_dword(buf + 3, 0); + expect_dword(buf + 4, 0x10000003); + + status = GdipSetEmpty(region); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionDataSize(region, &needed); + ok(status == Ok, "status %08x\n", status); + ok(needed == 20, "got %d\n", needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + ok(status == Ok, "status %08x\n", status); + ok(needed == 20, "got %d\n", needed); + expect_dword(buf, 12); + trace("buf[1] = %08x\n", buf[1]); + expect_dword(buf + 2, 0xdbc01001); + expect_dword(buf + 3, 0); + expect_dword(buf + 4, 0x10000002); + + status = GdipSetInfinite(region); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionDataSize(region, &needed); + ok(status == Ok, "status %08x\n", status); + ok(needed == 20, "got %d\n", needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + ok(status == Ok, "status %08x\n", status); + ok(needed == 20, "got %d\n", needed); + expect_dword(buf, 12); + trace("buf[1] = %08x\n", buf[1]); + expect_dword(buf + 2, 0xdbc01001); + expect_dword(buf + 3, 0); + expect_dword(buf + 4, 0x10000003); + + status = GdipDeleteRegion(region); + ok(status == Ok, "status %08x\n", status); + + rect.X = 10; + rect.Y = 20; + rect.Width = 100; + rect.Height = 200; + status = GdipCreateRegionRectI(&rect, ®ion); + ok(status == Ok, "status %08x\n", status); + status = GdipGetRegionDataSize(region, &needed); + ok(status == Ok, "status %08x\n", status); + ok(needed == 36, "got %d\n", needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + ok(status == Ok, "status %08x\n", status); + ok(needed == 36, "got %d\n", needed); + expect_dword(buf, 28); + trace("buf[1] = %08x\n", buf[1]); + expect_dword(buf + 2, 0xdbc01001); + expect_dword(buf + 3, 0); + expect_dword(buf + 4, 0x10000000); + expect_float(buf + 5, 10.0); + expect_float(buf + 6, 20.0); + expect_float(buf + 7, 100.0); + expect_float(buf + 8, 200.0); + + rect.X = 50; + rect.Y = 30; + rect.Width = 10; + rect.Height = 20; + status = GdipCombineRegionRectI(region, &rect, CombineModeIntersect); + ok(status == Ok, "status %08x\n", status); + rect.X = 100; + rect.Y = 300; + rect.Width = 30; + rect.Height = 50; + status = GdipCombineRegionRectI(region, &rect, CombineModeXor); + ok(status == Ok, "status %08x\n", status); + + rect.X = 200; + rect.Y = 100; + rect.Width = 133; + rect.Height = 266; + status = GdipCreateRegionRectI(&rect, ®ion2); + ok(status == Ok, "status %08x\n", status); + rect.X = 20; + rect.Y = 10; + rect.Width = 40; + rect.Height = 66; + status = GdipCombineRegionRectI(region2, &rect, CombineModeUnion); + ok(status == Ok, "status %08x\n", status); + + status = GdipCombineRegionRegion(region, region2, CombineModeComplement); + ok(status == Ok, "status %08x\n", status); + + rect.X = 400; + rect.Y = 500; + rect.Width = 22; + rect.Height = 55; + status = GdipCombineRegionRectI(region, &rect, CombineModeExclude); + ok(status == Ok, "status %08x\n", status); + + status = GdipGetRegionDataSize(region, &needed); + ok(status == Ok, "status %08x\n", status); + ok(needed == 156, "got %d\n", needed); + status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); + ok(status == Ok, "status %08x\n", status); + ok(needed == 156, "got %d\n", needed); + expect_dword(buf, 148); + trace("buf[1] = %08x\n", buf[1]); + expect_dword(buf + 2, 0xdbc01001); + expect_dword(buf + 3, 10); + expect_dword(buf + 4, CombineModeExclude); + expect_dword(buf + 5, CombineModeComplement); + expect_dword(buf + 6, CombineModeXor); + expect_dword(buf + 7, CombineModeIntersect); + expect_dword(buf + 8, 0x10000000); + expect_float(buf + 9, 10.0); + expect_float(buf + 10, 20.0); + expect_float(buf + 11, 100.0); + expect_float(buf + 12, 200.0); + expect_dword(buf + 13, 0x10000000); + expect_float(buf + 14, 50.0); + expect_float(buf + 15, 30.0); + expect_float(buf + 16, 10.0); + expect_float(buf + 17, 20.0); + expect_dword(buf + 18, 0x10000000); + expect_float(buf + 19, 100.0); + expect_float(buf + 20, 300.0); + expect_float(buf + 21, 30.0); + expect_float(buf + 22, 50.0); + expect_dword(buf + 23, CombineModeUnion); + expect_dword(buf + 24, 0x10000000); + expect_float(buf + 25, 200.0); + expect_float(buf + 26, 100.0); + expect_float(buf + 27, 133.0); + expect_float(buf + 28, 266.0); + expect_dword(buf + 29, 0x10000000); + expect_float(buf + 30, 20.0); + expect_float(buf + 31, 10.0); + expect_float(buf + 32, 40.0); + expect_float(buf + 33, 66.0); + expect_dword(buf + 34, 0x10000000); + expect_float(buf + 35, 400.0); + expect_float(buf + 36, 500.0); + expect_float(buf + 37, 22.0); + expect_float(buf + 38, 55.0); + + + status = GdipDeleteRegion(region2); + ok(status == Ok, "status %08x\n", status); + status = GdipDeleteRegion(region); + ok(status == Ok, "status %08x\n", status); + +} + +START_TEST(region) +{ + struct GdiplusStartupInput gdiplusStartupInput; + ULONG_PTR gdiplusToken; + + gdiplusStartupInput.GdiplusVersion = 1; + gdiplusStartupInput.DebugEventCallback = NULL; + gdiplusStartupInput.SuppressBackgroundThread = 0; + gdiplusStartupInput.SuppressExternalCodecs = 0; + + GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + + test_create_rgn(); + + GdiplusShutdown(gdiplusToken); + +} diff --git a/rostests/winetests/gdiplus/testlist.c b/rostests/winetests/gdiplus/testlist.c index dfb3f46ffa4..450488199e6 100644 --- a/rostests/winetests/gdiplus/testlist.c +++ b/rostests/winetests/gdiplus/testlist.c @@ -7,23 +7,27 @@ #include "wine/test.h" extern void func_brush(void); +extern void func_font(void); extern void func_graphics(void); extern void func_graphicspath(void); extern void func_image(void); extern void func_matrix(void); +extern void func_pathiterator(void); extern void func_pen(void); +extern void func_region(void); extern void func_stringformat(void); -extern void func_font(void); const struct test winetest_testlist[] = { { "brush", func_brush }, + { "font", func_font }, { "graphics", func_graphics }, { "graphicspath", func_graphicspath }, - { "font", func_font }, { "image", func_image }, { "matrix", func_matrix }, - { "stringformat", func_stringformat }, + { "pathiterator", func_pathiterator }, { "pen", func_pen }, + { "region", func_region }, + { "stringformat", func_stringformat }, { 0, 0 } }; diff --git a/rostests/winetests/lz32/lzexpand_main.c b/rostests/winetests/lz32/lzexpand_main.c index c67883acb54..a296b28e630 100644 --- a/rostests/winetests/lz32/lzexpand_main.c +++ b/rostests/winetests/lz32/lzexpand_main.c @@ -369,7 +369,8 @@ static void test_LZOpenFileA(void) ok(file >= 0, "LZOpenFileA failed on creation\n"); ok(test.cBytes == sizeof(OFSTRUCT), "LZOpenFileA set test.cBytes to %d\n", test.cBytes); - ok(test.nErrCode == ERROR_SUCCESS, + ok(test.nErrCode == ERROR_SUCCESS || + test.nErrCode == ERROR_FILE_NOT_FOUND, /* win9x */ "LZOpenFileA set test.nErrCode to %d\n", test.nErrCode); ok(lstrcmpA(test.szPathName, expected) == 0, "LZOpenFileA returned '%s', but was expected to return '%s'\n", diff --git a/rostests/winetests/mapi32/prop.c b/rostests/winetests/mapi32/prop.c index adc1d85b91a..a2b92891934 100644 --- a/rostests/winetests/mapi32/prop.c +++ b/rostests/winetests/mapi32/prop.c @@ -824,13 +824,16 @@ static void test_ScCopyRelocProps(void) sc = pScCopyProps(1, &pvProp, buffer, &ulCount); ok(sc == S_OK, "wrong ret %d\n", sc); - ok(lpResProp->ulPropTag == pvProp.ulPropTag, "wrong tag %x\n",lpResProp->ulPropTag); - ok(lpResProp->Value.MVszA.cValues == 1, "wrong cValues %d\n", lpResProp->Value.MVszA.cValues); - ok(lpResProp->Value.MVszA.lppszA[0] == buffer + sizeof(SPropValue) + sizeof(char*), - "wrong lppszA[0] %p\n",lpResProp->Value.MVszA.lppszA[0]); - ok(ulCount == sizeof(SPropValue) + sizeof(char*) + 5, "wrong count %d\n", ulCount); - ok(!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA), - "wrong string '%s'\n", lpResProp->Value.MVszA.lppszA[0]); + if(sc == S_OK) + { + ok(lpResProp->ulPropTag == pvProp.ulPropTag, "wrong tag %x\n",lpResProp->ulPropTag); + ok(lpResProp->Value.MVszA.cValues == 1, "wrong cValues %d\n", lpResProp->Value.MVszA.cValues); + ok(lpResProp->Value.MVszA.lppszA[0] == buffer + sizeof(SPropValue) + sizeof(char*), + "wrong lppszA[0] %p\n",lpResProp->Value.MVszA.lppszA[0]); + ok(ulCount == sizeof(SPropValue) + sizeof(char*) + 5, "wrong count %d\n", ulCount); + ok(!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA), + "wrong string '%s'\n", lpResProp->Value.MVszA.lppszA[0]); + } memcpy(buffer2, buffer, sizeof(buffer)); @@ -845,18 +848,21 @@ static void test_ScCopyRelocProps(void) lpResProp = (LPSPropValue)buffer2; ok(sc == S_OK, "wrong ret %d\n", sc); - ok(lpResProp->ulPropTag == pvProp.ulPropTag, "wrong tag %x\n",lpResProp->ulPropTag); - ok(lpResProp->Value.MVszA.cValues == 1, "wrong cValues %d\n", lpResProp->Value.MVszA.cValues); - ok(lpResProp->Value.MVszA.lppszA[0] == buffer2 + sizeof(SPropValue) + sizeof(char*), - "wrong lppszA[0] %p\n",lpResProp->Value.MVszA.lppszA[0]); - /* Native has a bug whereby it calculates the size correctly when copying - * but when relocating does not (presumably it uses UlPropSize() which - * ignores multivalue pointers). Wine returns the correct value. - */ - ok(ulCount == sizeof(SPropValue) + sizeof(char*) + 5 || ulCount == sizeof(SPropValue) + 5, - "wrong count %d\n", ulCount); - ok(!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA), - "wrong string '%s'\n", lpResProp->Value.MVszA.lppszA[0]); + if(sc == S_OK) + { + ok(lpResProp->ulPropTag == pvProp.ulPropTag, "wrong tag %x\n",lpResProp->ulPropTag); + ok(lpResProp->Value.MVszA.cValues == 1, "wrong cValues %d\n", lpResProp->Value.MVszA.cValues); + ok(lpResProp->Value.MVszA.lppszA[0] == buffer2 + sizeof(SPropValue) + sizeof(char*), + "wrong lppszA[0] %p\n",lpResProp->Value.MVszA.lppszA[0]); + /* Native has a bug whereby it calculates the size correctly when copying + * but when relocating does not (presumably it uses UlPropSize() which + * ignores multivalue pointers). Wine returns the correct value. + */ + ok(ulCount == sizeof(SPropValue) + sizeof(char*) + 5 || ulCount == sizeof(SPropValue) + 5, + "wrong count %d\n", ulCount); + ok(!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA), + "wrong string '%s'\n", lpResProp->Value.MVszA.lppszA[0]); + } /* Native crashes with lpNew or lpOld set to NULL so skip testing this */ } diff --git a/rostests/winetests/mlang/mlang.c b/rostests/winetests/mlang/mlang.c index c036f7a425c..115080eb692 100644 --- a/rostests/winetests/mlang/mlang.c +++ b/rostests/winetests/mlang/mlang.c @@ -44,6 +44,17 @@ #define TRACE_2 OutputDebugStringA +static CHAR string1[MAX_PATH], string2[MAX_PATH]; + +#define ok_w2(format, szString1, szString2) \ +\ + if (lstrcmpW(szString1, szString2) != 0) \ + { \ + WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \ + WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \ + ok(0, format, string1, string2); \ + } + static BOOL (WINAPI *pGetCPInfoExA)(UINT,DWORD,LPCPINFOEXA); static void test_multibyte_to_unicode_translations(IMultiLanguage2 *iML2) @@ -255,6 +266,32 @@ static const char *dump_mime_flags(DWORD flags) } #endif +static BOOL check_convertible(IMultiLanguage2 *iML2, UINT from, UINT to) +{ + CHAR convert[MAX_PATH]; + BYTE dest[MAX_PATH]; + HRESULT hr; + UINT srcsz, destsz; + + static WCHAR strW[] = {'a','b','c',0}; + + srcsz = -1; + destsz = MAX_PATH; + hr = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, from, strW, + &srcsz, convert, &destsz); + if (hr != S_OK) + return FALSE; + + srcsz = -1; + destsz = MAX_PATH; + hr = IMultiLanguage2_ConvertString(iML2, NULL, from, to, (BYTE *)convert, + &srcsz, dest, &destsz); + if (hr != S_OK) + return FALSE; + + return TRUE; +} + static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) { IEnumCodePage *iEnumCP = NULL; @@ -313,9 +350,10 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) for (i = 0; i < n; i++) { - CPINFOEXA cpinfoex; CHARSETINFO csi; MIMECSETINFO mcsi; + BOOL convertible; + HRESULT check = S_OK; static const WCHAR autoW[] = {'_','a','u','t','o',0}; #ifdef DUMP_CP_INFO @@ -349,17 +387,7 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) else trace("TranslateCharsetInfo failed for cp %u\n", cpinfo[i].uiFamilyCodePage); - if (pGetCPInfoExA) - { - if (pGetCPInfoExA(cpinfo[i].uiCodePage, 0, &cpinfoex)) - trace("CodePage %u name: %s\n", cpinfo[i].uiCodePage, cpinfoex.CodePageName); - else - trace("GetCPInfoExA failed for cp %u\n", cpinfo[i].uiCodePage); - if (pGetCPInfoExA(cpinfo[i].uiFamilyCodePage, 0, &cpinfoex)) - trace("CodePage %u name: %s\n", cpinfo[i].uiFamilyCodePage, cpinfoex.CodePageName); - else - trace("GetCPInfoExA failed for cp %u\n", cpinfo[i].uiFamilyCodePage); - } + trace("%u: codepage %u family %u\n", i, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage); /* Win95 does not support UTF-7 */ if (cpinfo[i].uiCodePage == CP_UTF7) continue; @@ -376,12 +404,16 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) ret = IMultiLanguage2_IsConvertible(iML2, CP_UNICODE, cpinfo[i].uiCodePage); ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UNICODE -> %u) = %08x\n", cpinfo[i].uiCodePage, ret); + convertible = check_convertible(iML2, cpinfo[i].uiCodePage, CP_UTF8); + if (!convertible) + check = S_FALSE; + TRACE_2("Call IMultiLanguage2_IsConvertible\n"); ret = IMultiLanguage2_IsConvertible(iML2, cpinfo[i].uiCodePage, CP_UTF8); - ok(ret == S_OK, "IMultiLanguage2_IsConvertible(%u -> CP_UTF8) = %08x\n", cpinfo[i].uiCodePage, ret); + ok(ret == check, "IMultiLanguage2_IsConvertible(%u -> CP_UTF8) = %08x\n", cpinfo[i].uiCodePage, ret); TRACE_2("Call IMultiLanguage2_IsConvertible\n"); ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, cpinfo[i].uiCodePage); - ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UTF8 -> %u) = %08x\n", cpinfo[i].uiCodePage, ret); + ok(ret == check, "IMultiLanguage2_IsConvertible(CP_UTF8 -> %u) = %08x\n", cpinfo[i].uiCodePage, ret); } else trace("IsValidCodePage failed for cp %u\n", cpinfo[i].uiCodePage); @@ -399,7 +431,7 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) "%s != %s\n", wine_dbgstr_w(cpinfo[i].wszWebCharset), wine_dbgstr_w(mcsi.wszCharset)); #else - "wszWebCharset mismatch"); + "wszWebCharset mismatch\n"); #endif if (0) @@ -425,7 +457,7 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) "%s != %s\n", wine_dbgstr_w(cpinfo[i].wszHeaderCharset), wine_dbgstr_w(mcsi.wszCharset)); #else - "wszHeaderCharset mismatch"); + "wszHeaderCharset mismatch\n"); #endif if (0) @@ -451,7 +483,7 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) "%s != %s\n", wine_dbgstr_w(cpinfo[i].wszBodyCharset), wine_dbgstr_w(mcsi.wszCharset)); #else - "wszBodyCharset mismatch"); + "wszBodyCharset mismatch\n"); #endif if (0) @@ -463,8 +495,6 @@ static void test_EnumCodePages(IMultiLanguage2 *iML2, DWORD flags) "%u != %u || %u\n", mcsi.uiCodePage, cpinfo[i].uiCodePage, cpinfo[i].uiFamilyCodePage); } } - - trace("---\n"); } /* now IEnumCodePage_Next should fail, since pointer is at the end */ @@ -564,7 +594,6 @@ static void test_EnumScripts(IMultiLanguage2 *iML2, DWORD flags) for (i = 0; pGetCPInfoExA && i < n; i++) { - CPINFOEXA cpinfoex; #ifdef DUMP_SCRIPT_INFO trace("SCRIPTINFO #%u:\n" "ScriptId %08x\n" @@ -579,12 +608,7 @@ static void test_EnumScripts(IMultiLanguage2 *iML2, DWORD flags) wine_dbgstr_w(sinfo[i].wszFixedWidthFont), wine_dbgstr_w(sinfo[i].wszProportionalFont)); #endif - if (pGetCPInfoExA(sinfo[i].uiCodePage, 0, &cpinfoex)) - trace("CodePage %u name: %s\n", sinfo[i].uiCodePage, cpinfoex.CodePageName); - else - trace("GetCPInfoExA failed for cp %u\n", sinfo[i].uiCodePage); - - trace("---\n"); + trace("%u codepage %u\n", i, sinfo[i].uiCodePage); } /* now IEnumScript_Next should fail, since pointer is at the end */ @@ -654,12 +678,26 @@ static void IMLangFontLink_Test(IMLangFontLink* iMLFL) ok(CodePage == 1252, "Incorrect CodePage Returned (%i)\n",CodePage); } +/* copied from libs/wine/string.c */ +WCHAR *strstrW(const WCHAR *str, const WCHAR *sub) +{ + while (*str) + { + const WCHAR *p1 = str, *p2 = sub; + while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; } + if (!*p2) return (WCHAR *)str; + str++; + } + return NULL; +} + static void test_rfc1766(IMultiLanguage2 *iML2) { IEnumRfc1766 *pEnumRfc1766; RFC1766INFO info; ULONG n; HRESULT ret; + BSTR rfcstr; ret = IMultiLanguage2_EnumRfc1766(iML2, LANG_NEUTRAL, &pEnumRfc1766); ok(ret == S_OK, "IMultiLanguage2_EnumRfc1766 error %08x\n", ret); @@ -675,7 +713,17 @@ static void test_rfc1766(IMultiLanguage2 *iML2) #endif ok(n == 1, "couldn't fetch 1 RFC1766INFO structure\n"); - ok(IsValidLocale(info.lcid, LCID_SUPPORTED), "invalid lcid %04x\n", info.lcid); + + /* verify the Rfc1766 value */ + ret = IMultiLanguage2_GetRfc1766FromLcid(iML2, info.lcid, &rfcstr); + ok(ret == S_OK, "Expected S_OK, got %08x\n", ret); + + /* not an exact 1:1 correspondence between lcid and rfc1766 in the + * mlang database, e.g., nb-no -> 1044 -> no */ + ok(strstrW(info.wszRfc1766, rfcstr) != NULL, + "Expected matching locale names\n"); + + SysFreeString(rfcstr); } IEnumRfc1766_Release(pEnumRfc1766); } @@ -734,6 +782,24 @@ static void test_GetLcidFromRfc1766(IMultiLanguage2 *iML2) ok(lcid == 0x409, "got wrong lcid: %04x\n", lcid); } +static void test_GetRfc1766FromLcid(IMultiLanguage2 *iML2) +{ + HRESULT hr; + BSTR rfcstr; + LCID lcid; + + static WCHAR kok[] = {'k','o','k',0}; + + hr = IMultiLanguage2_GetLcidFromRfc1766(iML2, &lcid, kok); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + + hr = IMultiLanguage2_GetRfc1766FromLcid(iML2, lcid, &rfcstr); + ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); + ok_w2("Expected \"%s\", got \"%s\"n", kok, rfcstr); + + SysFreeString(rfcstr); +} + START_TEST(mlang) { IMultiLanguage2 *iML2 = NULL; @@ -752,6 +818,7 @@ START_TEST(mlang) test_rfc1766(iML2); test_GetLcidFromRfc1766(iML2); + test_GetRfc1766FromLcid(iML2); test_EnumCodePages(iML2, 0); test_EnumCodePages(iML2, MIMECONTF_MIME_LATEST); diff --git a/rostests/winetests/mlang/mlang.rbuild b/rostests/winetests/mlang/mlang.rbuild index 20a989a27f9..8cf5aebcc43 100644 --- a/rostests/winetests/mlang/mlang.rbuild +++ b/rostests/winetests/mlang/mlang.rbuild @@ -8,10 +8,11 @@ mlang.c testlist.c wine + uuid + oleaut32 ole32 gdi32 kernel32 - uuid ntdll diff --git a/rostests/winetests/mshtml/dom.c b/rostests/winetests/mshtml/dom.c index d041a2c67bb..4540ed405b8 100644 --- a/rostests/winetests/mshtml/dom.c +++ b/rostests/winetests/mshtml/dom.c @@ -30,6 +30,7 @@ #include "mshtmcid.h" #include "mshtmhst.h" #include "docobj.h" +#include "dispex.h" static const char doc_blank[] = ""; static const char doc_str1[] = "test"; @@ -39,11 +40,15 @@ static const char range_test2_str[] = "abc
123

def"; static const char elem_test_str[] = "test" - "link" - "" + "text test" + "link" + "" + "" "" "
" "" + "" + "" ""; static const char indent_test_str[] = "testabc
123"; @@ -56,6 +61,8 @@ static WCHAR wordW[] = {'w','o','r','d',0}; static const WCHAR text_javascriptW[] = {'t','e','x','t','/','j','a','v','a','s','c','r','i','p','t',0}; +static const WCHAR idW[] = {'i','d',0}; + typedef enum { ET_NONE, ET_HTML, @@ -73,7 +80,11 @@ typedef enum { ET_BR, ET_TABLE, ET_TBODY, - ET_SCRIPT + ET_SCRIPT, + ET_TEST, + ET_TESTG, + ET_COMMENT, + ET_IMG } elem_type_t; static REFIID const none_iids[] = { @@ -83,115 +94,186 @@ static REFIID const none_iids[] = { static REFIID const elem_iids[] = { &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static REFIID const body_iids[] = { &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLTextContainer, &IID_IHTMLBodyElement, + &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static REFIID const anchor_iids[] = { &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLAnchorElement, + &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static REFIID const input_iids[] = { &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLInputElement, &IID_IHTMLInputTextElement, + &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static REFIID const select_iids[] = { &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLSelectElement, + &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static REFIID const textarea_iids[] = { &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLTextAreaElement, + &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static REFIID const option_iids[] = { &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLOptionElement, + &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static REFIID const table_iids[] = { &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLTable, + &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static REFIID const script_iids[] = { &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLScriptElement, + &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; +static REFIID const text_iids[] = { + &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, + &IID_IHTMLDOMTextNode, + NULL +}; + static REFIID const location_iids[] = { &IID_IDispatch, &IID_IHTMLLocation, NULL }; +static REFIID const window_iids[] = { + &IID_IDispatch, + &IID_IHTMLWindow2, + &IID_IHTMLWindow3, + &IID_IDispatchEx, + NULL +}; + +static REFIID const comment_iids[] = { + &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, + &IID_IHTMLElement, + &IID_IHTMLElement2, + &IID_IHTMLCommentElement, + &IID_IDispatchEx, + &IID_IConnectionPointContainer, + NULL +}; + +static REFIID const img_iids[] = { + &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, + &IID_IHTMLElement, + &IID_IHTMLElement2, + &IID_IDispatchEx, + &IID_IHTMLImgElement, + &IID_IConnectionPointContainer, + NULL +}; + +static REFIID const generic_iids[] = { + &IID_IHTMLDOMNode, + &IID_IHTMLDOMNode2, + &IID_IHTMLElement, + &IID_IHTMLElement2, + &IID_IHTMLGenericElement, + &IID_IDispatchEx, + &IID_IConnectionPointContainer, + NULL +}; + typedef struct { const char *tag; REFIID *iids; + const IID *dispiid; } elem_type_info_t; static const elem_type_info_t elem_type_infos[] = { - {"", none_iids}, - {"HTML", elem_iids}, - {"HEAD", elem_iids}, - {"TITLE", elem_iids}, - {"BODY", body_iids}, - {"A", anchor_iids}, - {"INPUT", input_iids}, - {"SELECT", select_iids}, - {"TEXTAREA", textarea_iids}, - {"OPTION", option_iids}, - {"STYLE", elem_iids}, - {"BLOCKQUOTE",elem_iids}, - {"P", elem_iids}, - {"BR", elem_iids}, - {"TABLE", table_iids}, - {"TBODY", elem_iids}, - {"SCRIPT", script_iids} + {"", none_iids, NULL}, + {"HTML", elem_iids, NULL}, + {"HEAD", elem_iids, NULL}, + {"TITLE", elem_iids, NULL}, + {"BODY", body_iids, NULL}, + {"A", anchor_iids, NULL}, + {"INPUT", input_iids, &DIID_DispHTMLInputElement}, + {"SELECT", select_iids, &DIID_DispHTMLSelectElement}, + {"TEXTAREA", textarea_iids, NULL}, + {"OPTION", option_iids, &DIID_DispHTMLOptionElement}, + {"STYLE", elem_iids, NULL}, + {"BLOCKQUOTE",elem_iids, NULL}, + {"P", elem_iids, NULL}, + {"BR", elem_iids, NULL}, + {"TABLE", table_iids, NULL}, + {"TBODY", elem_iids, NULL}, + {"SCRIPT", script_iids, NULL}, + {"TEST", elem_iids, &DIID_DispHTMLUnknownElement}, + {"TEST", generic_iids, &DIID_DispHTMLGenericElement}, + {"!", comment_iids, &DIID_DispHTMLCommentElement}, + {"IMG", img_iids, &DIID_DispHTMLImg} }; static const char *dbgstr_w(LPCWSTR str) @@ -261,15 +343,91 @@ static void _test_ifaces(unsigned line, IUnknown *iface, REFIID *iids) } } -#define test_node_name(u,n) _test_node_name(__LINE__,u,n) -static void _test_node_name(unsigned line, IUnknown *unk, const char *exname) +#define test_disp(u,id) _test_disp(__LINE__,u,id) +static void _test_disp(unsigned line, IUnknown *unk, const IID *diid) +{ + IDispatchEx *dispex; + ITypeInfo *typeinfo; + UINT ticnt; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex); + ok_(__FILE__,line) (hres == S_OK, "Could not get IDispatch: %08x\n", hres); + if(FAILED(hres)) + return; + + ticnt = 0xdeadbeef; + hres = IDispatchEx_GetTypeInfoCount(dispex, &ticnt); + ok_(__FILE__,line) (hres == S_OK, "GetTypeInfoCount failed: %08x\n", hres); + ok_(__FILE__,line) (ticnt == 1, "ticnt=%u\n", ticnt); + + hres = IDispatchEx_GetTypeInfo(dispex, 0, 0, &typeinfo); + ok_(__FILE__,line) (hres == S_OK, "GetTypeInfo failed: %08x\n", hres); + + if(SUCCEEDED(hres)) { + TYPEATTR *type_attr; + + hres = ITypeInfo_GetTypeAttr(typeinfo, &type_attr); + ok_(__FILE__,line) (hres == S_OK, "GetTypeAttr failed: %08x\n", hres); + ok_(__FILE__,line) (IsEqualGUID(&type_attr->guid, diid), "unexpected guid %s\n", dbgstr_guid(&type_attr->guid)); + + ITypeInfo_ReleaseTypeAttr(typeinfo, type_attr); + ITypeInfo_Release(typeinfo); + } + + IDispatchEx_Release(dispex); +} + +#define get_elem_iface(u) _get_elem_iface(__LINE__,u) +static IHTMLElement *_get_elem_iface(unsigned line, IUnknown *unk) +{ + IHTMLElement *elem; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement, (void**)&elem); + ok_(__FILE__,line) (hres == S_OK, "Coule not get IHTMLElement: %08x\n", hres); + return elem; +} + +#define get_elem2_iface(u) _get_elem2_iface(__LINE__,u) +static IHTMLElement2 *_get_elem2_iface(unsigned line, IUnknown *unk) +{ + IHTMLElement2 *elem; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement2, (void**)&elem); + ok_(__FILE__,line) (hres == S_OK, "Coule not get IHTMLElement2: %08x\n", hres); + return elem; +} + +#define get_node_iface(u) _get_node_iface(__LINE__,u) +static IHTMLDOMNode *_get_node_iface(unsigned line, IUnknown *unk) { IHTMLDOMNode *node; - BSTR name; HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IHTMLDOMNode, (void**)&node); - ok_(__FILE__, line) (hres == S_OK, "QueryInterface(IID_IHTMLNode) failed: %08x\n", hres); + ok_(__FILE__,line) (hres == S_OK, "Coule not get IHTMLDOMNode: %08x\n", hres); + return node; +} + +#define get_img_iface(u) _get_img_iface(__LINE__,u) +static IHTMLImgElement *_get_img_iface(unsigned line, IUnknown *unk) +{ + IHTMLImgElement *img; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLImgElement, (void**)&img); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLImgElement: %08x\n", hres); + return img; +} + +#define test_node_name(u,n) _test_node_name(__LINE__,u,n) +static void _test_node_name(unsigned line, IUnknown *unk, const char *exname) +{ + IHTMLDOMNode *node = _get_node_iface(line, unk); + BSTR name; + HRESULT hres; hres = IHTMLDOMNode_get_nodeName(node, &name); IHTMLDOMNode_Release(node); @@ -282,13 +440,10 @@ static void _test_node_name(unsigned line, IUnknown *unk, const char *exname) #define test_elem_tag(u,n) _test_elem_tag(__LINE__,u,n) static void _test_elem_tag(unsigned line, IUnknown *unk, const char *extag) { - IHTMLElement *elem; + IHTMLElement *elem = _get_elem_iface(line, unk); BSTR tag; HRESULT hres; - hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement, (void**)&elem); - ok_(__FILE__, line) (hres == S_OK, "QueryInterface(IID_IHTMLElement) failed: %08x\n", hres); - hres = IHTMLElement_get_tagName(elem, &tag); IHTMLElement_Release(elem); ok_(__FILE__, line) (hres == S_OK, "get_tagName failed: %08x\n", hres); @@ -302,6 +457,46 @@ static void _test_elem_type(unsigned line, IUnknown *unk, elem_type_t type) { _test_elem_tag(line, unk, elem_type_infos[type].tag); _test_ifaces(line, unk, elem_type_infos[type].iids); + + if(elem_type_infos[type].dispiid) + _test_disp(line, unk, elem_type_infos[type].dispiid); +} + +#define test_elem_attr(e,n,v) _test_elem_attr(__LINE__,e,n,v) +static void _test_elem_attr(unsigned line, IHTMLElement *elem, LPCWSTR name, LPCWSTR exval) +{ + VARIANT value; + BSTR tmp; + HRESULT hres; + + VariantInit(&value); + + tmp = SysAllocString(name); + hres = IHTMLElement_getAttribute(elem, tmp, 0, &value); + SysFreeString(tmp); + ok_(__FILE__,line) (hres == S_OK, "getAttribute failed: %08x\n", hres); + + if(exval) { + ok_(__FILE__,line) (V_VT(&value) == VT_BSTR, "vt=%d\n", V_VT(&value)); + ok_(__FILE__,line) (!lstrcmpW(exval, V_BSTR(&value)), "unexpected value %s\n", dbgstr_w(V_BSTR(&value))); + }else { + ok_(__FILE__,line) (V_VT(&value) == VT_NULL, "vt=%d\n", V_VT(&value)); + } + + VariantClear(&value); +} + +#define test_elem_offset(u) _test_elem_offset(__LINE__,u) +static void _test_elem_offset(unsigned line, IUnknown *unk) +{ + IHTMLElement *elem = _get_elem_iface(line, unk); + long l; + HRESULT hres; + + hres = IHTMLElement_get_offsetTop(elem, &l); + ok_(__FILE__,line) (hres == S_OK, "get_offsetTop failed: %08x\n", hres); + + IHTMLElement_Release(elem); } static void test_doc_elem(IHTMLDocument2 *doc) @@ -459,6 +654,43 @@ static void _test_select_put_selidx(unsigned line, IHTMLSelectElement *select, l _test_select_selidx(line, select, index); } +#define test_select_value(s,v) _test_select_value(__LINE__,s,v) +static void _test_select_value(unsigned line, IHTMLSelectElement *select, const char *exval) +{ + BSTR val; + HRESULT hres; + + hres = IHTMLSelectElement_get_value(select, &val); + ok_(__FILE__,line) (hres == S_OK, "get_value failed: %08x\n", hres); + if(exval) + ok_(__FILE__,line) (!strcmp_wa(val, exval), "unexpected value %s\n", dbgstr_w(val)); + else + ok_(__FILE__,line) (val == NULL, "val=%s, expected NULL\n", dbgstr_w(val)); +} + +#define test_select_set_value(s,v) _test_select_set_value(__LINE__,s,v) +static void _test_select_set_value(unsigned line, IHTMLSelectElement *select, const char *val) +{ + BSTR bstr; + HRESULT hres; + + bstr = a2bstr(val); + hres = IHTMLSelectElement_put_value(select, bstr); + SysFreeString(bstr); + ok_(__FILE__,line) (hres == S_OK, "put_value failed: %08x\n", hres); +} + +#define test_select_type(s,t) _test_select_type(__LINE__,s,t) +static void _test_select_type(unsigned line, IHTMLSelectElement *select, const char *extype) +{ + BSTR type; + HRESULT hres; + + hres = IHTMLSelectElement_get_type(select, &type); + ok_(__FILE__,line) (hres == S_OK, "get_type failed: %08x\n", hres); + ok_(__FILE__,line) (!strcmp_wa(type, extype), "type=%s, expected %s\n", dbgstr_w(type), extype); +} + #define test_range_text(r,t) _test_range_text(__LINE__,r,t) static void _test_range_text(unsigned line, IHTMLTxtRange *range, const char *extext) { @@ -598,15 +830,21 @@ static void _test_range_parent(unsigned line, IHTMLTxtRange *range, elem_type_t } #define test_elem_collection(c,t,l) _test_elem_collection(__LINE__,c,t,l) -static void _test_elem_collection(unsigned line, IHTMLElementCollection *col, +static void _test_elem_collection(unsigned line, IUnknown *unk, const elem_type_t *elem_types, long exlen) { + IHTMLElementCollection *col; long len; DWORD i; VARIANT name, index; IDispatch *disp; HRESULT hres; + hres = IUnknown_QueryInterface(unk, &IID_IHTMLElementCollection, (void**)&col); + ok(hres == S_OK, "Could not get IHTMLElementCollection: %08x\n", hres); + + test_disp((IUnknown*)col, &DIID_DispHTMLElementCollection); + hres = IHTMLElementCollection_get_length(col, &len); ok_(__FILE__,line) (hres == S_OK, "get_length failed: %08x\n", hres); ok_(__FILE__,line) (len == exlen, "len=%ld, expected %ld\n", len, exlen); @@ -641,12 +879,463 @@ static void _test_elem_collection(unsigned line, IHTMLElementCollection *col, hres = IHTMLElementCollection_item(col, name, index, &disp); ok_(__FILE__,line) (hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres); ok_(__FILE__,line) (disp == NULL, "disp != NULL\n"); + + IHTMLElementCollection_Release(col); +} + +#define get_first_child(n) _get_first_child(__LINE__,n) +static IHTMLDOMNode *_get_first_child(unsigned line, IUnknown *unk) +{ + IHTMLDOMNode *node = _get_node_iface(line, unk); + IHTMLDOMNode *child = NULL; + HRESULT hres; + + hres = IHTMLDOMNode_get_firstChild(node, &child); + IHTMLDOMNode_Release(node); + ok_(__FILE__,line) (hres == S_OK, "get_firstChild failed: %08x\n", hres); + + return child; +} + +#define test_node_has_child(u,b) _test_node_has_child(__LINE__,u,b) +static void _test_node_has_child(unsigned line, IUnknown *unk, VARIANT_BOOL exb) +{ + IHTMLDOMNode *node = _get_node_iface(line, unk); + VARIANT_BOOL b = 0xdead; + HRESULT hres; + + hres = IHTMLDOMNode_hasChildNodes(node, &b); + ok_(__FILE__,line) (hres == S_OK, "hasChildNodes failed: %08x\n", hres); + ok_(__FILE__,line) (b == exb, "hasChildNodes=%x, expected %x\n", b, exb); + + IHTMLDOMNode_Release(node); +} + +#define test_node_get_parent(u) _test_node_get_parent(__LINE__,u) +static IHTMLDOMNode *_test_node_get_parent(unsigned line, IUnknown *unk) +{ + IHTMLDOMNode *node = _get_node_iface(line, unk); + IHTMLDOMNode *parent; + HRESULT hres; + + hres = IHTMLDOMNode_get_parentNode(node, &parent); + IHTMLDOMNode_Release(node); + ok_(__FILE__,line) (hres == S_OK, "get_parentNode failed: %08x\n", hres); + + return parent; +} + +#define get_node_type(n) _get_node_type(__LINE__,n) +static long _get_node_type(unsigned line, IUnknown *unk) +{ + IHTMLDOMNode *node = _get_node_iface(line, unk); + long type = -1; + HRESULT hres; + + hres = IHTMLDOMNode_get_nodeType(node, &type); + ok(hres == S_OK, "get_nodeType failed: %08x\n", hres); + + IHTMLDOMNode_Release(node); + + return type; +} + +#define test_img_set_src(u,s) _test_img_set_src(__LINE__,u,s) +static void _test_img_set_src(unsigned line, IUnknown *unk, const char *src) +{ + IHTMLImgElement *img = _get_img_iface(line, unk); + BSTR tmp; + HRESULT hres; + + tmp = a2bstr(src); + hres = IHTMLImgElement_put_src(img, tmp); + IHTMLImgElement_Release(img); + SysFreeString(tmp); + ok_(__FILE__,line) (hres == S_OK, "put_src failed: %08x\n", hres); +} + +#define test_img_alt(u,a) _test_img_alt(__LINE__,u,a) +static void _test_img_alt(unsigned line, IUnknown *unk, const char *exalt) +{ + IHTMLImgElement *img = _get_img_iface(line, unk); + BSTR alt; + HRESULT hres; + + hres = IHTMLImgElement_get_alt(img, &alt); + ok_(__FILE__,line) (hres == S_OK, "get_alt failed: %08x\n", hres); + if(exalt) + ok_(__FILE__,line) (!strcmp_wa(alt, exalt), "inexopected alt %s\n", dbgstr_w(alt)); + else + ok_(__FILE__,line) (!alt, "alt != NULL\n"); + SysFreeString(alt); +} + +#define test_img_set_alt(u,a) _test_img_set_alt(__LINE__,u,a) +static void _test_img_set_alt(unsigned line, IUnknown *unk, const char *alt) +{ + IHTMLImgElement *img = _get_img_iface(line, unk); + BSTR tmp; + HRESULT hres; + + tmp = a2bstr(alt); + hres = IHTMLImgElement_put_alt(img, tmp); + ok_(__FILE__,line) (hres == S_OK, "get_alt failed: %08x\n", hres); + SysFreeString(tmp); + + _test_img_alt(line, unk, alt); +} + +#define test_input_get_disabled(i,b) _test_input_get_disabled(__LINE__,i,b) +static void _test_input_get_disabled(unsigned line, IHTMLInputElement *input, VARIANT_BOOL exb) +{ + VARIANT_BOOL disabled = 100; + HRESULT hres; + + hres = IHTMLInputElement_get_disabled(input, &disabled); + ok_(__FILE__,line) (hres == S_OK, "get_disabled failed: %08x\n", hres); + ok_(__FILE__,line) (disabled == exb, "disabled=%x, expected %x\n", disabled, exb); +} + +#define test_input_set_disabled(i,b) _test_input_set_disabled(__LINE__,i,b) +static void _test_input_set_disabled(unsigned line, IHTMLInputElement *input, VARIANT_BOOL b) +{ + HRESULT hres; + + hres = IHTMLInputElement_put_disabled(input, b); + ok_(__FILE__,line) (hres == S_OK, "get_disabled failed: %08x\n", hres); + + _test_input_get_disabled(line, input, b); +} + +#define test_input_value(o,t) _test_input_value(__LINE__,o,t) +static void _test_input_value(unsigned line, IUnknown *unk, const char *exval) +{ + IHTMLInputElement *input; + BSTR bstr; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLInputElement, (void**)&input); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLInputElement: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IHTMLInputElement_get_value(input, &bstr); + ok_(__FILE__,line) (hres == S_OK, "get_value failed: %08x\n", hres); + if(exval) + ok_(__FILE__,line) (!strcmp_wa(bstr, exval), "value=%s\n", dbgstr_w(bstr)); + else + ok_(__FILE__,line) (!exval, "exval != NULL\n"); + SysFreeString(bstr); + IHTMLInputElement_Release(input); +} + +#define test_input_put_value(o,v) _test_input_put_value(__LINE__,o,v) +static void _test_input_put_value(unsigned line, IUnknown *unk, const char *val) +{ + IHTMLInputElement *input; + BSTR bstr; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IHTMLInputElement, (void**)&input); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLInputElement: %08x\n", hres); + if(FAILED(hres)) + return; + + bstr = a2bstr(val); + hres = IHTMLInputElement_get_value(input, &bstr); + ok_(__FILE__,line) (hres == S_OK, "get_value failed: %08x\n", hres); + SysFreeString(bstr); + IHTMLInputElement_Release(input); +} + +#define get_child_nodes(u) _get_child_nodes(__LINE__,u) +static IHTMLDOMChildrenCollection *_get_child_nodes(unsigned line, IUnknown *unk) +{ + IHTMLDOMNode *node = _get_node_iface(line, unk); + IHTMLDOMChildrenCollection *col = NULL; + IDispatch *disp; + HRESULT hres; + + hres = IHTMLDOMNode_get_childNodes(node, &disp); + IHTMLDOMNode_Release(node); + ok_(__FILE__,line) (hres == S_OK, "get_childNodes failed: %08x\n", hres); + if(FAILED(hres)) + return NULL; + + hres = IDispatch_QueryInterface(disp, &IID_IHTMLDOMChildrenCollection, (void**)&col); + IDispatch_Release(disp); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDOMChildrenCollection: %08x\n", hres); + + return col; +} + +#define test_elem_class(u,c) _test_elem_class(__LINE__,u,c) +static void _test_elem_class(unsigned line, IUnknown *unk, const char *exclass) +{ + IHTMLElement *elem = _get_elem_iface(line, unk); + BSTR class = (void*)0xdeadbeef; + HRESULT hres; + + hres = IHTMLElement_get_className(elem, &class); + IHTMLElement_Release(elem); + ok_(__FILE__,line) (hres == S_OK, "get_className failed: %08x\n", hres); + if(exclass) + ok_(__FILE__,line) (!strcmp_wa(class, exclass), "unexpected className %s\n", dbgstr_w(class)); + else + ok_(__FILE__,line) (!class, "class != NULL\n"); + SysFreeString(class); +} + +#define test_elem_tabindex(u,i) _test_elem_tabindex(__LINE__,u,i) +static void _test_elem_tabindex(unsigned line, IUnknown *unk, short exindex) +{ + IHTMLElement2 *elem2 = _get_elem2_iface(line, unk); + short index = -3; + HRESULT hres; + + hres = IHTMLElement2_get_tabIndex(elem2, &index); + IHTMLElement2_Release(elem2); + ok_(__FILE__,line) (hres == S_OK, "get_tabIndex failed: %08x\n", hres); + ok_(__FILE__,line) (index == exindex, "unexpected index %d\n", index); +} + +#define test_elem_set_tabindex(u,i) _test_elem_set_tabindex(__LINE__,u,i) +static void _test_elem_set_tabindex(unsigned line, IUnknown *unk, short index) +{ + IHTMLElement2 *elem2 = _get_elem2_iface(line, unk); + HRESULT hres; + + hres = IHTMLElement2_put_tabIndex(elem2, index); + IHTMLElement2_Release(elem2); + ok_(__FILE__,line) (hres == S_OK, "get_tabIndex failed: %08x\n", hres); + + _test_elem_tabindex(line, unk, index); +} + +#define test_elem_set_class(u,c) _test_elem_set_class(__LINE__,u,c) +static void _test_elem_set_class(unsigned line, IUnknown *unk, const char *class) +{ + IHTMLElement *elem = _get_elem_iface(line, unk); + BSTR tmp; + HRESULT hres; + + tmp = class ? a2bstr(class) : NULL; + hres = IHTMLElement_put_className(elem, tmp); + IHTMLElement_Release(elem); + ok_(__FILE__,line) (hres == S_OK, "put_className failed: %08x\n", hres); + SysFreeString(tmp); + + _test_elem_class(line, unk, class); +} + +#define get_child_item(c,i) _get_child_item(__LINE__,c,i) +static IHTMLDOMNode *_get_child_item(unsigned line, IHTMLDOMChildrenCollection *col, long idx) +{ + IHTMLDOMNode *node = NULL; + IDispatch *disp; + HRESULT hres; + + hres = IHTMLDOMChildrenCollection_item(col, idx, &disp); + ok(hres == S_OK, "item failed: %08x\n", hres); + + node = _get_node_iface(line, (IUnknown*)disp); + IDispatch_Release(disp); + + return node; +} + +#define test_elem_id(e,i) _test_elem_id(__LINE__,e,i) +static void _test_elem_id(unsigned line, IUnknown *unk, const char *exid) +{ + IHTMLElement *elem = _get_elem_iface(line, unk); + BSTR id = (void*)0xdeadbeef; + HRESULT hres; + + hres = IHTMLElement_get_id(elem, &id); + IHTMLElement_Release(elem); + ok_(__FILE__,line) (hres == S_OK, "get_id failed: %08x\n", hres); + + if(exid) + ok_(__FILE__,line) (!strcmp_wa(id, exid), "unexpected id %s\n", dbgstr_w(id)); + else + ok_(__FILE__,line) (!id, "id=%s\n", dbgstr_w(id)); + + SysFreeString(id); +} + +#define test_elem_put_id(u,i) _test_elem_put_id(__LINE__,u,i) +static void _test_elem_put_id(unsigned line, IUnknown *unk, const char *new_id) +{ + IHTMLElement *elem = _get_elem_iface(line, unk); + BSTR tmp = a2bstr(new_id); + HRESULT hres; + + hres = IHTMLElement_put_id(elem, tmp); + IHTMLElement_Release(elem); + SysFreeString(tmp); + ok_(__FILE__,line) (hres == S_OK, "put_id failed: %08x\n", hres); + + _test_elem_id(line, unk, new_id); +} + +#define test_elem_title(u,t) _test_elem_title(__LINE__,u,t) +static void _test_elem_title(unsigned line, IUnknown *unk, const char *extitle) +{ + IHTMLElement *elem = _get_elem_iface(line, unk); + BSTR title; + HRESULT hres; + + hres = IHTMLElement_get_title(elem, &title); + IHTMLElement_Release(elem); + ok_(__FILE__,line) (hres == S_OK, "get_title failed: %08x\n", hres); + if(extitle) + ok_(__FILE__,line) (!strcmp_wa(title, extitle), "unexpected title %s\n", dbgstr_w(title)); + else + ok_(__FILE__,line) (!title, "title=%s, expected NULL\n", dbgstr_w(title)); + + SysFreeString(title); +} + +#define test_elem_set_title(u,t) _test_elem_set_title(__LINE__,u,t) +static void _test_elem_set_title(unsigned line, IUnknown *unk, const char *title) +{ + IHTMLElement *elem = _get_elem_iface(line, unk); + BSTR tmp; + HRESULT hres; + + tmp = a2bstr(title); + hres = IHTMLElement_put_title(elem, tmp); + ok_(__FILE__,line) (hres == S_OK, "get_title failed: %08x\n", hres); + + IHTMLElement_Release(elem); + SysFreeString(tmp); +} + +#define test_node_get_value_str(u,e) _test_node_get_value_str(__LINE__,u,e) +static void _test_node_get_value_str(unsigned line, IUnknown *unk, const char *exval) +{ + IHTMLDOMNode *node = _get_node_iface(line, unk); + VARIANT var; + HRESULT hres; + + hres = IHTMLDOMNode_get_nodeValue(node, &var); + IHTMLDOMNode_Release(node); + ok_(__FILE__,line) (hres == S_OK, "get_nodeValue failed: %08x, expected VT_BSTR\n", hres); + + if(exval) { + ok_(__FILE__,line) (V_VT(&var) == VT_BSTR, "vt=%d\n", V_VT(&var)); + ok_(__FILE__,line) (!strcmp_wa(V_BSTR(&var), exval), "unexpected value %s\n", dbgstr_w(V_BSTR(&var))); + }else { + ok_(__FILE__,line) (V_VT(&var) == VT_NULL, "vt=%d, expected VT_NULL\n", V_VT(&var)); + } + + VariantClear(&var); +} + +#define test_node_put_value_str(u,v) _test_node_put_value_str(__LINE__,u,v) +static void _test_node_put_value_str(unsigned line, IUnknown *unk, const char *val) +{ + IHTMLDOMNode *node = _get_node_iface(line, unk); + VARIANT var; + HRESULT hres; + + V_VT(&var) = VT_BSTR; + V_BSTR(&var) = a2bstr(val); + + hres = IHTMLDOMNode_put_nodeValue(node, var); + ok_(__FILE__,line) (hres == S_OK, "get_nodeValue failed: %08x, expected VT_BSTR\n", hres); + IHTMLDOMNode_Release(node); + VariantClear(&var); +} + +#define test_elem_client_size(u) _test_elem_client_size(__LINE__,u) +static void _test_elem_client_size(unsigned line, IUnknown *unk) +{ + IHTMLElement2 *elem = _get_elem2_iface(line, unk); + long l; + HRESULT hres; + + hres = IHTMLElement2_get_clientWidth(elem, &l); + ok_(__FILE__,line) (hres == S_OK, "get_clientWidth failed: %08x\n", hres); + hres = IHTMLElement2_get_clientHeight(elem, &l); + ok_(__FILE__,line) (hres == S_OK, "get_clientHeight failed: %08x\n", hres); + + IHTMLElement2_Release(elem); +} + +#define test_create_elem(d,t) _test_create_elem(__LINE__,d,t) +static IHTMLElement *_test_create_elem(unsigned line, IHTMLDocument2 *doc, const char *tag) +{ + IHTMLElement *elem = NULL; + BSTR tmp; + HRESULT hres; + + tmp = a2bstr(tag); + hres = IHTMLDocument2_createElement(doc, tmp, &elem); + ok_(__FILE__,line) (hres == S_OK, "createElement failed: %08x\n", hres); + ok_(__FILE__,line) (elem != NULL, "elem == NULL\n"); + + return elem; +} + +#define test_create_text(d,t) _test_create_text(__LINE__,d,t) +static IHTMLDOMNode *_test_create_text(unsigned line, IHTMLDocument2 *doc, const char *text) +{ + IHTMLDocument3 *doc3; + IHTMLDOMNode *node = NULL; + BSTR tmp; + HRESULT hres; + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDocument3: %08x\n", hres); + + tmp = a2bstr(text); + hres = IHTMLDocument3_createTextNode(doc3, tmp, &node); + IHTMLDocument3_Release(doc3); + ok_(__FILE__,line) (hres == S_OK, "createElement failed: %08x\n", hres); + ok_(__FILE__,line) (node != NULL, "node == NULL\n"); + + return node; +} + +#define test_node_append_child(n,c) _test_node_append_child(__LINE__,n,c) +static IHTMLDOMNode *_test_node_append_child(unsigned line, IUnknown *node_unk, IUnknown *child_unk) +{ + IHTMLDOMNode *node = _get_node_iface(line, node_unk); + IHTMLDOMNode *child = _get_node_iface(line, child_unk); + IHTMLDOMNode *new_child = NULL; + HRESULT hres; + + hres = IHTMLDOMNode_appendChild(node, child, &new_child); + ok_(__FILE__,line) (hres == S_OK, "appendChild failed: %08x\n", hres); + ok_(__FILE__,line) (new_child != NULL, "new_child == NULL\n"); + /* TODO ok_(__FILE__,line) (new_child != child, "new_child == child\n"); */ + + IHTMLDOMNode_Release(node); + IHTMLDOMNode_Release(child); + + return new_child; +} + +#define test_node_remove_child(n,c) _test_node_remove_child(__LINE__,n,c) +static void _test_node_remove_child(unsigned line, IUnknown *unk, IHTMLDOMNode *child) +{ + IHTMLDOMNode *node = _get_node_iface(line, unk); + IHTMLDOMNode *new_node = NULL; + HRESULT hres; + + hres = IHTMLDOMNode_removeChild(node, child, &new_node); + ok_(__FILE__,line) (hres == S_OK, "appendChild failed: %08x\n", hres); + ok_(__FILE__,line) (new_node != NULL, "new_node == NULL\n"); + /* TODO ok_(__FILE__,line) (new_node != child, "new_node == child\n"); */ + + IHTMLDOMNode_Release(node); + IHTMLDOMNode_Release(new_node); } static void test_elem_col_item(IHTMLElementCollection *col, LPCWSTR n, const elem_type_t *elem_types, long len) { - IHTMLElementCollection *elcol; IDispatch *disp; VARIANT name, index; DWORD i; @@ -659,11 +1348,11 @@ static void test_elem_col_item(IHTMLElementCollection *col, LPCWSTR n, hres = IHTMLElementCollection_item(col, name, index, &disp); ok(hres == S_OK, "item failed: %08x\n", hres); - hres = IDispatch_QueryInterface(disp, &IID_IHTMLElementCollection, (void**)&elcol); + test_elem_collection((IUnknown*)disp, elem_types, len); IDispatch_Release(disp); ok(hres == S_OK, "Could not get IHTMLElementCollection interface: %08x\n", hres); - test_elem_collection(elcol, elem_types, len); - IHTMLElementCollection_Release(elcol); + if(hres != S_OK) + goto cleanup; V_VT(&index) = VT_I4; @@ -693,6 +1382,7 @@ static void test_elem_col_item(IHTMLElementCollection *col, LPCWSTR n, ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres); ok(disp == NULL, "disp != NULL\n"); +cleanup: SysFreeString(V_BSTR(&name)); } @@ -727,18 +1417,41 @@ static IHTMLElement *get_elem_by_id(IHTMLDocument2 *doc, LPCWSTR id, BOOL expect if(!disp) return NULL; - hres = IDispatch_QueryInterface(disp, &IID_IHTMLElement, (void**)&elem); + elem = get_elem_iface((IUnknown*)disp); IDispatch_Release(disp); - ok(hres == S_OK, "Could not get IHTMLElement interface: %08x\n", hres); + + return elem; +} + +static IHTMLElement *get_doc_elem_by_id(IHTMLDocument2 *doc, LPCWSTR id) +{ + IHTMLDocument3 *doc3; + IHTMLElement *elem; + BSTR tmp; + HRESULT hres; + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3); + ok(hres == S_OK, "Could not get IHTMLDocument3 iface: %08x\n", hres); + + tmp = SysAllocString(id); + hres = IHTMLDocument3_getElementById(doc3, tmp, &elem); + SysFreeString(tmp); + ok(hres == S_OK, "getElementById(%s) failed: %08x\n", dbgstr_w(id), hres); + + IHTMLDocument3_Release(doc3); return elem; } static void test_select_elem(IHTMLSelectElement *select) { + test_select_type(select, "select-one"); test_select_length(select, 2); test_select_selidx(select, 0); test_select_put_selidx(select, 1); + + test_select_set_value(select, "val1"); + test_select_value(select, "val1"); } static void test_create_option_elem(IHTMLDocument2 *doc) @@ -1042,6 +1755,7 @@ static void test_navigator(IHTMLDocument2 *doc) hres = IHTMLWindow2_get_navigator(window, &navigator); ok(hres == S_OK, "get_navigator failed: %08x\n", hres); ok(navigator != NULL, "navigator == NULL\n"); + test_disp((IUnknown*)navigator, &IID_IOmNavigator); hres = IHTMLWindow2_get_navigator(window, &navigator2); ok(hres == S_OK, "get_navigator failed: %08x\n", hres); @@ -1060,6 +1774,8 @@ static void test_default_style(IHTMLStyle *style) BSTR str; HRESULT hres; + test_disp((IUnknown*)style, &DIID_DispHTMLStyle); + str = (void*)0xdeadbeef; hres = IHTMLStyle_get_fontFamily(style, &str); ok(hres == S_OK, "get_fontFamily failed: %08x\n", hres); @@ -1101,6 +1817,25 @@ static void test_default_style(IHTMLStyle *style) hres = IHTMLStyle_get_textDecorationLineThrough(style, &b); ok(hres == S_OK, "get_textDecorationLineThrough failed: %08x\n", hres); ok(b == VARIANT_FALSE, "textDecorationLineThrough = %x\n", b); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLStyle_get_width(style, &v); + ok(hres == S_OK, "get_width failed: %08x\n", hres); + ok(V_VT(&v) == VT_BSTR, "V_VT(v)=%d\n", V_VT(&v)); + ok(!V_BSTR(&v), "V_BSTR(v)=%p\n", V_BSTR(&v)); + + V_VT(&v) = VT_BSTR; + V_BSTR(&v) = a2bstr("auto"); + hres = IHTMLStyle_put_width(style, v); + ok(hres == S_OK, "put_width failed: %08x\n", hres); + VariantClear(&v); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLStyle_get_width(style, &v); + ok(hres == S_OK, "get_width failed: %08x\n", hres); + ok(V_VT(&v) == VT_BSTR, "V_VT(v)=%d\n", V_VT(&v)); + ok(!strcmp_wa(V_BSTR(&v), "auto"), "V_BSTR(v)=%s\n", dbgstr_w(V_BSTR(&v))); + VariantClear(&v); } static void test_default_selection(IHTMLDocument2 *doc) @@ -1142,6 +1877,39 @@ static void test_default_body(IHTMLBodyElement *body) ok(bstr == NULL, "bstr != NULL\n"); } +static void test_window(IHTMLDocument2 *doc) +{ + IHTMLWindow2 *window, *window2, *self; + IHTMLDocument2 *doc2 = NULL; + HRESULT hres; + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentElement failed: %08x\n", hres); + test_ifaces((IUnknown*)window, window_iids); + test_disp((IUnknown*)window, &DIID_DispHTMLWindow2); + + hres = IHTMLWindow2_get_document(window, &doc2); + ok(hres == S_OK, "get_document failed: %08x\n", hres); + ok(doc2 != NULL, "doc2 == NULL\n"); + + IHTMLDocument_Release(doc2); + + hres = IHTMLWindow2_get_window(window, &window2); + ok(hres == S_OK, "get_window failed: %08x\n", hres); + ok(window2 != NULL, "window2 == NULL\n"); + + hres = IHTMLWindow2_get_self(window, &self); + ok(hres == S_OK, "get_window failed: %08x\n", hres); + ok(window2 != NULL, "self == NULL\n"); + + ok(self == window2, "self != window2\n"); + + IHTMLWindow2_Release(window2); + IHTMLWindow2_Release(self); + + IHTMLWindow2_Release(window); +} + static void test_defaults(IHTMLDocument2 *doc) { IHTMLStyleSheetsCollection *stylesheetcol; @@ -1164,6 +1932,7 @@ static void test_defaults(IHTMLDocument2 *doc) ok(hres == S_OK, "get_style failed: %08x\n", hres); test_default_style(style); + test_window(doc); test_compatmode(doc); test_location(doc); test_navigator(doc); @@ -1239,13 +2008,62 @@ static void test_stylesheets(IHTMLDocument2 *doc) IHTMLStyleSheetsCollection_Release(col); } +static void test_child_col_disp(IHTMLDOMChildrenCollection *col) +{ + IDispatchEx *dispex; + IHTMLDOMNode *node; + DISPPARAMS dp = {NULL, NULL, 0, 0}; + VARIANT var; + EXCEPINFO ei; + long type; + DISPID id; + BSTR bstr; + HRESULT hres; + + static const WCHAR w0[] = {'0',0}; + static const WCHAR w100[] = {'1','0','0',0}; + + hres = IHTMLDOMChildrenCollection_QueryInterface(col, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx: %08x\n", hres); + + bstr = SysAllocString(w0); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &id); + ok(hres == S_OK, "GetDispID failed: %08x\n", hres); + SysFreeString(bstr); + + VariantInit(&var); + hres = IDispatchEx_InvokeEx(dispex, id, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + ok(V_VT(&var) == VT_DISPATCH, "V_VT(var)=%d\n", V_VT(&var)); + ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(var) == NULL\n"); + node = get_node_iface((IUnknown*)V_DISPATCH(&var)); + type = get_node_type((IUnknown*)node); + ok(type == 3, "type=%ld\n", type); + IHTMLDOMNode_Release(node); + VariantClear(&var); + + bstr = SysAllocString(w100); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &id); + ok(hres == DISP_E_UNKNOWNNAME, "GetDispID failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres); + SysFreeString(bstr); + + IDispatchEx_Release(dispex); +} + + + static void test_elems(IHTMLDocument2 *doc) { IHTMLElementCollection *col; + IHTMLDOMChildrenCollection *child_col; IHTMLElement *elem; + IHTMLDOMNode *node, *node2; IDispatch *disp; + long type; HRESULT hres; + static const WCHAR imgidW[] = {'i','m','g','i','d',0}; + static const WCHAR inW[] = {'i','n',0}; static const WCHAR xW[] = {'x',0}; static const WCHAR sW[] = {'s',0}; static const WCHAR scW[] = {'s','c',0}; @@ -1257,6 +2075,7 @@ static void test_elems(IHTMLDocument2 *doc) ET_TITLE, ET_STYLE, ET_BODY, + ET_COMMENT, ET_A, ET_INPUT, ET_SELECT, @@ -1265,7 +2084,9 @@ static void test_elems(IHTMLDocument2 *doc) ET_TEXTAREA, ET_TABLE, ET_TBODY, - ET_SCRIPT + ET_SCRIPT, + ET_TEST, + ET_IMG }; static const elem_type_t item_types[] = { @@ -1276,7 +2097,7 @@ static void test_elems(IHTMLDocument2 *doc) hres = IHTMLDocument2_get_all(doc, &col); ok(hres == S_OK, "get_all failed: %08x\n", hres); - test_elem_collection(col, all_types, sizeof(all_types)/sizeof(all_types[0])); + test_elem_collection((IUnknown*)col, all_types, sizeof(all_types)/sizeof(all_types[0])); test_elem_col_item(col, xW, item_types, sizeof(item_types)/sizeof(item_types[0])); IHTMLElementCollection_Release(col); @@ -1289,10 +2110,45 @@ static void test_elems(IHTMLDocument2 *doc) hres = IDispatch_QueryInterface(disp, &IID_IHTMLElementCollection, (void**)&col); IDispatch_Release(disp); ok(hres == S_OK, "Could not get IHTMLElementCollection: %08x\n", hres); - test_elem_collection(col, all_types+1, sizeof(all_types)/sizeof(all_types[0])-1); + test_elem_collection((IUnknown*)col, all_types+1, sizeof(all_types)/sizeof(all_types[0])-1); IHTMLElementCollection_Release(col); get_elem_by_id(doc, xxxW, FALSE); + elem = get_doc_elem_by_id(doc, xxxW); + ok(!elem, "elem != NULL\n"); + + elem = get_doc_elem_by_id(doc, sW); + ok(elem != NULL, "elem == NULL\n"); + if(elem) { + test_elem_type((IUnknown*)elem, ET_SELECT); + test_elem_attr(elem, xxxW, NULL); + test_elem_attr(elem, idW, sW); + test_elem_class((IUnknown*)elem, NULL); + test_elem_set_class((IUnknown*)elem, "cl"); + test_elem_set_class((IUnknown*)elem, NULL); + test_elem_tabindex((IUnknown*)elem, 0); + test_elem_set_tabindex((IUnknown*)elem, 1); + + node = test_node_get_parent((IUnknown*)elem); + ok(node != NULL, "node == NULL\n"); + test_node_name((IUnknown*)node, "BODY"); + node2 = test_node_get_parent((IUnknown*)node); + IHTMLDOMNode_Release(node); + ok(node2 != NULL, "node == NULL\n"); + test_node_name((IUnknown*)node2, "HTML"); + node = test_node_get_parent((IUnknown*)node2); + IHTMLDOMNode_Release(node2); + ok(node != NULL, "node == NULL\n"); + test_node_name((IUnknown*)node, "#document"); + type = get_node_type((IUnknown*)node); + ok(type == 9, "type=%ld, expected 9\n", type); + node2 = test_node_get_parent((IUnknown*)node); + IHTMLDOMNode_Release(node); + ok(node2 == NULL, "node != NULL\n"); + + IHTMLElement_Release(elem); + } + elem = get_elem_by_id(doc, sW, TRUE); if(elem) { IHTMLSelectElement *select; @@ -1302,6 +2158,21 @@ static void test_elems(IHTMLDocument2 *doc) test_select_elem(select); + test_elem_title((IUnknown*)select, NULL); + test_elem_set_title((IUnknown*)select, "Title"); + test_elem_title((IUnknown*)select, "Title"); + test_elem_offset((IUnknown*)select); + + node = get_first_child((IUnknown*)select); + ok(node != NULL, "node == NULL\n"); + if(node) { + test_elem_type((IUnknown*)node, ET_OPTION); + IHTMLDOMNode_Release(node); + } + + type = get_node_type((IUnknown*)select); + ok(type == 1, "type=%ld\n", type); + IHTMLSelectElement_Release(select); IHTMLElement_Release(elem); } @@ -1318,12 +2189,168 @@ static void test_elems(IHTMLDocument2 *doc) ok(hres == S_OK, "get_type failed: %08x\n", hres); ok(!lstrcmpW(type, text_javascriptW), "Unexpected type %s\n", dbgstr_w(type)); SysFreeString(type); + + IHTMLScriptElement_Release(script); } + elem = get_elem_by_id(doc, inW, TRUE); + if(elem) { + IHTMLInputElement *input; + + hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLInputElement, (void**)&input); + ok(hres == S_OK, "Could not get IHTMLInputElement: %08x\n", hres); + + test_elem_id((IUnknown*)elem, "in"); + test_elem_put_id((IUnknown*)elem, "newin"); + test_input_get_disabled(input, VARIANT_FALSE); + test_input_set_disabled(input, VARIANT_TRUE); + test_input_set_disabled(input, VARIANT_FALSE); + test_elem_client_size((IUnknown*)elem); + + test_node_get_value_str((IUnknown*)elem, NULL); + test_node_put_value_str((IUnknown*)elem, "test"); + test_node_get_value_str((IUnknown*)elem, NULL); + test_input_value((IUnknown*)elem, NULL); + test_input_put_value((IUnknown*)elem, "test"); + test_input_value((IUnknown*)elem, NULL); + test_elem_class((IUnknown*)elem, "testclass"); + test_elem_tabindex((IUnknown*)elem, 2); + test_elem_set_tabindex((IUnknown*)elem, 3); + test_elem_title((IUnknown*)elem, "test title"); + + IHTMLInputElement_Release(input); + IHTMLElement_Release(elem); + } + + elem = get_elem_by_id(doc, imgidW, TRUE); + if(elem) { + test_img_set_src((IUnknown*)elem, "about:blank"); + test_img_alt((IUnknown*)elem, NULL); + test_img_set_alt((IUnknown*)elem, "alt test"); + IHTMLElement_Release(elem); + } + + hres = IHTMLDocument2_get_body(doc, &elem); + ok(hres == S_OK, "get_body failed: %08x\n", hres); + + node = get_first_child((IUnknown*)elem); + ok(node != NULL, "node == NULL\n"); + if(node) { + test_ifaces((IUnknown*)node, text_iids); + test_disp((IUnknown*)node, &DIID_DispHTMLDOMTextNode); + + node2 = get_first_child((IUnknown*)node); + ok(!node2, "node2 != NULL\n"); + + type = get_node_type((IUnknown*)node); + ok(type == 3, "type=%ld\n", type); + + test_node_get_value_str((IUnknown*)node, "text test"); + test_node_put_value_str((IUnknown*)elem, "test text"); + test_node_get_value_str((IUnknown*)node, "text test"); + + IHTMLDOMNode_Release(node); + } + + child_col = get_child_nodes((IUnknown*)elem); + ok(child_col != NULL, "child_coll == NULL\n"); + if(child_col) { + long length = 0; + + test_disp((IUnknown*)child_col, &DIID_DispDOMChildrenCollection); + + hres = IHTMLDOMChildrenCollection_get_length(child_col, &length); + ok(hres == S_OK, "get_length failed: %08x\n", hres); + ok(length, "length=0\n"); + + node = get_child_item(child_col, 0); + ok(node != NULL, "node == NULL\n"); + if(node) { + type = get_node_type((IUnknown*)node); + ok(type == 3, "type=%ld\n", type); + IHTMLDOMNode_Release(node); + } + + node = get_child_item(child_col, 1); + ok(node != NULL, "node == NULL\n"); + if(node) { + type = get_node_type((IUnknown*)node); + ok(type == 8, "type=%ld\n", type); + + test_elem_id((IUnknown*)node, NULL); + IHTMLDOMNode_Release(node); + } + + disp = (void*)0xdeadbeef; + hres = IHTMLDOMChildrenCollection_item(child_col, 6000, &disp); + ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres); + ok(disp == (void*)0xdeadbeef, "disp=%p\n", disp); + + disp = (void*)0xdeadbeef; + hres = IHTMLDOMChildrenCollection_item(child_col, length, &disp); + ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres); + ok(disp == (void*)0xdeadbeef, "disp=%p\n", disp); + + test_child_col_disp(child_col); + + IHTMLDOMChildrenCollection_Release(child_col); + } + + IHTMLElement_Release(elem); + test_stylesheets(doc); test_create_option_elem(doc); } +static void test_create_elems(IHTMLDocument2 *doc) +{ + IHTMLElement *elem, *body, *elem2; + IHTMLDOMNode *node; + IDispatch *disp; + long type; + HRESULT hres; + + static const elem_type_t types1[] = { ET_TESTG }; + + elem = test_create_elem(doc, "TEST"); + test_elem_tag((IUnknown*)elem, "TEST"); + type = get_node_type((IUnknown*)elem); + ok(type == 1, "type=%ld\n", type); + test_ifaces((IUnknown*)elem, elem_iids); + test_disp((IUnknown*)elem, &DIID_DispHTMLGenericElement); + + hres = IHTMLDocument2_get_body(doc, &body); + ok(hres == S_OK, "get_body failed: %08x\n", hres); + test_node_has_child((IUnknown*)body, VARIANT_FALSE); + + node = test_node_append_child((IUnknown*)body, (IUnknown*)elem); + test_node_has_child((IUnknown*)body, VARIANT_TRUE); + elem2 = get_elem_iface((IUnknown*)node); + IHTMLElement_Release(elem2); + + hres = IHTMLElement_get_all(body, &disp); + ok(hres == S_OK, "get_all failed: %08x\n", hres); + test_elem_collection((IUnknown*)disp, types1, sizeof(types1)/sizeof(types1[0])); + IDispatch_Release(disp); + + test_node_remove_child((IUnknown*)body, node); + + hres = IHTMLElement_get_all(body, &disp); + ok(hres == S_OK, "get_all failed: %08x\n", hres); + test_elem_collection((IUnknown*)disp, NULL, 0); + IDispatch_Release(disp); + test_node_has_child((IUnknown*)body, VARIANT_FALSE); + + IHTMLElement_Release(body); + IHTMLElement_Release(elem); + IHTMLDOMNode_Release(node); + + node = test_create_text(doc, "test"); + test_ifaces((IUnknown*)node, text_iids); + test_disp((IUnknown*)node, &DIID_DispHTMLDOMTextNode); + IHTMLDOMNode_Release(node); +} + static void test_exec(IUnknown *unk, const GUID *grpid, DWORD cmdid, VARIANT *in, VARIANT *out) { IOleCommandTarget *cmdtrg; @@ -1366,7 +2393,7 @@ static void test_indent(IHTMLDocument2 *doc) hres = IHTMLDocument2_get_all(doc, &col); ok(hres == S_OK, "get_all failed: %08x\n", hres); - test_elem_collection(col, all_types, sizeof(all_types)/sizeof(all_types[0])); + test_elem_collection((IUnknown*)col, all_types, sizeof(all_types)/sizeof(all_types[0])); IHTMLElementCollection_Release(col); range = test_create_body_range(doc); @@ -1375,7 +2402,7 @@ static void test_indent(IHTMLDocument2 *doc) hres = IHTMLDocument2_get_all(doc, &col); ok(hres == S_OK, "get_all failed: %08x\n", hres); - test_elem_collection(col, indent_types, sizeof(indent_types)/sizeof(indent_types[0])); + test_elem_collection((IUnknown*)col, indent_types, sizeof(indent_types)/sizeof(indent_types[0])); IHTMLElementCollection_Release(col); } @@ -1418,7 +2445,7 @@ static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, D if(!lstrcmpW(state, completeW)) doc_complete = TRUE; - SysFreeString(state); + SysFreeString(state); } return S_OK; @@ -1557,6 +2584,7 @@ START_TEST(dom) run_domtest(range_test_str, test_txtrange); run_domtest(range_test2_str, test_txtrange2); run_domtest(elem_test_str, test_elems); + run_domtest(doc_blank, test_create_elems); run_domtest(doc_blank, test_defaults); run_domtest(indent_test_str, test_indent); diff --git a/rostests/winetests/mshtml/htmldoc.c b/rostests/winetests/mshtml/htmldoc.c index 34a7f24372a..4de528676cd 100644 --- a/rostests/winetests/mshtml/htmldoc.c +++ b/rostests/winetests/mshtml/htmldoc.c @@ -99,10 +99,12 @@ DEFINE_EXPECT(Exec_SETDOWNLOADSTATE_0); DEFINE_EXPECT(Exec_SETDOWNLOADSTATE_1); DEFINE_EXPECT(Exec_ShellDocView_37); DEFINE_EXPECT(Exec_ShellDocView_84); +DEFINE_EXPECT(Exec_ShellDocView_103); DEFINE_EXPECT(Exec_UPDATECOMMANDS); DEFINE_EXPECT(Exec_SETTITLE); DEFINE_EXPECT(Exec_HTTPEQUIV); DEFINE_EXPECT(Exec_MSHTML_PARSECOMPLETE); +DEFINE_EXPECT(Exec_Explorer_69); DEFINE_EXPECT(Invoke_AMBIENT_USERMODE); DEFINE_EXPECT(Invoke_AMBIENT_DLCONTROL); DEFINE_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); @@ -356,7 +358,9 @@ static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, ok(bindinfo.dwBindVerb == 0, "bindinfo.dwBindVerb=%d\n", bindinfo.dwBindVerb); ok(bindinfo.szCustomVerb == 0, "bindinfo.szCustomVerb=%p\n", bindinfo.szCustomVerb); ok(bindinfo.cbstgmedData == 0, "bindinfo.cbstgmedData=%d\n", bindinfo.cbstgmedData); - ok(bindinfo.dwOptions == 0x80000, "bindinfo.dwOptions=%x\n", bindinfo.dwOptions); + ok(bindinfo.dwOptions == 0x80000 || + bindinfo.dwOptions == 0x4080000, /* win2k3 */ + "bindinfo.dwOptions=%x\n", bindinfo.dwOptions); ok(bindinfo.dwOptionsFlags == 0, "bindinfo.dwOptionsFlags=%d\n", bindinfo.dwOptionsFlags); /* TODO: test dwCodePage */ /* TODO: test securityAttributes */ @@ -2067,7 +2071,8 @@ static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, con static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) { - test_readyState(NULL); + if(!pguidCmdGroup || !IsEqualGUID(pguidCmdGroup, &CGID_Explorer)) + test_readyState(NULL); if(!pguidCmdGroup) { switch(nCmdID) { @@ -2166,12 +2171,21 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID case 84: CHECK_EXPECT2(Exec_ShellDocView_84); - ok(pvaIn == NULL, "pvaIn == NULL\n"); - ok(pvaOut != NULL, "pvaOut=%p, expected NULL\n", pvaOut); + ok(pvaIn == NULL, "pvaIn != NULL\n"); + ok(pvaOut != NULL, "pvaOut == NULL\n"); if(pvaIn) ok(V_VT(pvaOut) == VT_EMPTY, "V_VT(pvaOut)=%d\n", V_VT(pvaOut)); return E_NOTIMPL; + + case 103: + CHECK_EXPECT2(Exec_ShellDocView_103); + + ok(pvaIn == NULL, "pvaIn != NULL\n"); + ok(pvaOut == NULL, "pvaOut != NULL\n"); + + return E_NOTIMPL; + default: ok(0, "unexpected command %d\n", nCmdID); return E_FAIL; @@ -2196,13 +2210,31 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID return E_FAIL; /* TODO */ if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) { - ok(0, "unexpected cmd %d of CGID_Explorer\n", nCmdID); + ok(nCmdexecopt == 0, "nCmdexecopts=%08x\n", nCmdexecopt); + + switch(nCmdID) { + case 69: + CHECK_EXPECT2(Exec_Explorer_69); + ok(pvaIn == NULL, "pvaIn != NULL\n"); + ok(pvaOut != NULL, "pvaOut == NULL\n"); + return E_NOTIMPL; + default: + ok(0, "unexpected cmd %d of CGID_Explorer\n", nCmdID); + } return E_NOTIMPL; } if(IsEqualGUID(&CGID_DocHostCommandHandler, pguidCmdGroup)) { - ok(0, "unexpected cmd %d of CGID_DocHostCommandHandler\n", nCmdID); - return E_NOTIMPL; + switch (nCmdID) { + case OLECMDID_PAGEACTIONBLOCKED: /* win2k3 */ + SET_EXPECT(SetStatusText); + ok(pvaIn == NULL, "pvaIn != NULL\n"); + ok(pvaOut == NULL, "pvaOut != NULL\n"); + return S_OK; + default: + ok(0, "unexpected command %d\n", nCmdID); + return E_FAIL; + } } ok(0, "unexpected pguidCmdGroup: %s\n", debugstr_guid(pguidCmdGroup)); @@ -2686,10 +2718,12 @@ static void test_download(BOOL verb_done, BOOL css_dwl, BOOL css_try_dwl) SET_EXPECT(Protocol_Read); SET_EXPECT(UnlockRequest); } + SET_EXPECT(Exec_Explorer_69); SET_EXPECT(OnChanged_1005); SET_EXPECT(OnChanged_READYSTATE); SET_EXPECT(Exec_SETPROGRESSPOS); SET_EXPECT(Exec_SETDOWNLOADSTATE_0); + SET_EXPECT(Exec_ShellDocView_103); SET_EXPECT(Exec_MSHTML_PARSECOMPLETE); SET_EXPECT(Exec_HTTPEQUIV_DONE); expect_status_text = (LPWSTR)0xdeadbeef; /* TODO */ @@ -2731,10 +2765,12 @@ static void test_download(BOOL verb_done, BOOL css_dwl, BOOL css_try_dwl) nogecko = TRUE; } } + SET_CALLED(Exec_Explorer_69); CHECK_CALLED(OnChanged_1005); CHECK_CALLED(OnChanged_READYSTATE); CHECK_CALLED(Exec_SETPROGRESSPOS); CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); + SET_CALLED(Exec_ShellDocView_103); CHECK_CALLED(Exec_MSHTML_PARSECOMPLETE); CHECK_CALLED(Exec_HTTPEQUIV_DONE); @@ -3665,20 +3701,33 @@ static void test_QueryInterface(IUnknown *unk) IUnknown *qi; HRESULT hres; + static const IID IID_UndocumentedScriptIface = + {0x719c3050,0xf9d3,0x11cf,{0xa4,0x93,0x00,0x40,0x05,0x23,0xa8,0xa0}}; + qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_IRunnableObject, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "runnable=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qirunnable=%p, ezpected NULL\n", qi); qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_IHTMLDOMNode, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "runnable=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qi=%p, ezpected NULL\n", qi); qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_IHTMLDOMNode2, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "runnable=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qi=%p, ezpected NULL\n", qi); + + qi = (void*)0xdeadbeef; + hres = IUnknown_QueryInterface(unk, &IID_IPersistPropertyBag, (void**)&qi); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(qi == NULL, "qi=%p, ezpected NULL\n", qi); + + qi = (void*)0xdeadbeef; + hres = IUnknown_QueryInterface(unk, &IID_UndocumentedScriptIface, (void**)&qi); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(qi == NULL, "qi=%p, ezpected NULL\n", qi); } static void init_test(enum load_state_t ls) { diff --git a/rostests/winetests/mshtml/mshtml.rbuild b/rostests/winetests/mshtml/mshtml.rbuild index 4209fe6df7c..af12a16e8c9 100644 --- a/rostests/winetests/mshtml/mshtml.rbuild +++ b/rostests/winetests/mshtml/mshtml.rbuild @@ -12,13 +12,14 @@ script.c testlist.c wine + uuid + strmiids ole32 oleaut32 user32 urlmon advapi32 kernel32 - uuid ntdll diff --git a/rostests/winetests/mshtml/protocol.c b/rostests/winetests/mshtml/protocol.c index df3c3371510..4e8b3d0c79a 100644 --- a/rostests/winetests/mshtml/protocol.c +++ b/rostests/winetests/mshtml/protocol.c @@ -713,6 +713,7 @@ static void test_about_protocol(void) case QUERY_IS_CACHED_OR_MAPPED: case QUERY_IS_SECURE: case QUERY_IS_SAFE: + case QUERY_USES_HISTORYFOLDER: break; default: hres = IInternetProtocolInfo_QueryInfo(protocol_info, about_blank_url, i, 0, @@ -723,8 +724,9 @@ static void test_about_protocol(void) hres = IInternetProtocolInfo_QueryInfo(protocol_info, about_blank_url, QUERY_CAN_NAVIGATE, 0, buf, sizeof(buf), &size, 0); - ok(hres == INET_E_USE_DEFAULT_PROTOCOLHANDLER, - "QueryInfo returned: %08x, expected INET_E_USE_DEFAULT_PROTOCOLHANDLER\n", hres); + ok(hres == INET_E_USE_DEFAULT_PROTOCOLHANDLER || + hres == E_FAIL, /* win2k */ + "QueryInfo returned: %08x, expected INET_E_USE_DEFAULT_PROTOCOLHANDLER or E_FAIL\n", hres); size = 0xdeadbeef; memset(buf, '?', sizeof(buf)); diff --git a/rostests/winetests/mshtml/script.c b/rostests/winetests/mshtml/script.c index ac604cce06d..bbd9c3cca5f 100644 --- a/rostests/winetests/mshtml/script.c +++ b/rostests/winetests/mshtml/script.c @@ -26,8 +26,12 @@ #include "windef.h" #include "winbase.h" #include "ole2.h" +#include "dispex.h" #include "mshtml.h" #include "activscp.h" +#include "activdbg.h" +#include "objsafe.h" +#include "mshtmdid.h" #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE @@ -64,7 +68,19 @@ DEFINE_EXPECT(CreateInstance); - +DEFINE_EXPECT(GetInterfaceSafetyOptions); +DEFINE_EXPECT(SetInterfaceSafetyOptions); +DEFINE_EXPECT(InitNew); +DEFINE_EXPECT(Close); +DEFINE_EXPECT(SetProperty); +DEFINE_EXPECT(SetScriptSite); +DEFINE_EXPECT(GetScriptState); +DEFINE_EXPECT(SetScriptState_STARTED); +DEFINE_EXPECT(SetScriptState_CONNECTED); +DEFINE_EXPECT(SetScriptState_DISCONNECTED); +DEFINE_EXPECT(AddNamedItem); +DEFINE_EXPECT(ParseScriptText); +DEFINE_EXPECT(GetScriptDispatch); #define TESTSCRIPT_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80746}" @@ -72,8 +88,16 @@ static const GUID CLSID_TestScript = {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}}; static IHTMLDocument2 *notif_doc; +static IDispatchEx *window_dispex; static BOOL doc_complete; +static const char *debugstr_w(LPCWSTR str) +{ + static char buf[1024]; + WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); + return buf; +} + static const char *debugstr_guid(REFIID riid) { static char buf[50]; @@ -233,6 +257,282 @@ static IHTMLDocument2 *create_and_load_doc(const char *str) return doc; } +static IActiveScriptSite *site; +static SCRIPTSTATE state; + +static HRESULT WINAPI ObjectSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI ObjectSafety_AddRef(IObjectSafety *iface) +{ + return 2; +} + +static ULONG WINAPI ObjectSafety_Release(IObjectSafety *iface) +{ + return 1; +} + +static HRESULT WINAPI ObjectSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid, + DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions) +{ + CHECK_EXPECT(GetInterfaceSafetyOptions); + + ok(IsEqualGUID(&IID_IActiveScriptParse, riid), "unexpected riid %s\n", debugstr_guid(riid)); + ok(pdwSupportedOptions != NULL, "pdwSupportedOptions == NULL\n"); + ok(pdwEnabledOptions != NULL, "pdwEnabledOptions == NULL\n"); + + *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER; + *pdwEnabledOptions = INTERFACE_USES_DISPEX; + + return S_OK; +} + +static HRESULT WINAPI ObjectSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid, + DWORD dwOptionSetMask, DWORD dwEnabledOptions) +{ + CHECK_EXPECT(SetInterfaceSafetyOptions); + + ok(IsEqualGUID(&IID_IActiveScriptParse, riid), "unexpected riid %s\n", debugstr_guid(riid)); + + ok(dwOptionSetMask == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER), + "dwOptionSetMask=%x\n", dwOptionSetMask); + ok(dwEnabledOptions == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER), + "dwEnabledOptions=%x\n", dwOptionSetMask); + + return S_OK; +} + +static const IObjectSafetyVtbl ObjectSafetyVtbl = { + ObjectSafety_QueryInterface, + ObjectSafety_AddRef, + ObjectSafety_Release, + ObjectSafety_GetInterfaceSafetyOptions, + ObjectSafety_SetInterfaceSafetyOptions +}; + +static IObjectSafety ObjectSafety = { &ObjectSafetyVtbl }; + +static HRESULT WINAPI ActiveScriptProperty_QueryInterface(IActiveScriptProperty *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI ActiveScriptProperty_AddRef(IActiveScriptProperty *iface) +{ + return 2; +} + +static ULONG WINAPI ActiveScriptProperty_Release(IActiveScriptProperty *iface) +{ + return 1; +} + +static HRESULT WINAPI ActiveScriptProperty_GetProperty(IActiveScriptProperty *iface, DWORD dwProperty, + VARIANT *pvarIndex, VARIANT *pvarValue) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptProperty_SetProperty(IActiveScriptProperty *iface, DWORD dwProperty, + VARIANT *pvarIndex, VARIANT *pvarValue) +{ + CHECK_EXPECT(SetProperty); + + ok(dwProperty == SCRIPTPROP_HACK_TRIDENTEVENTSINK, "unexpected property %d\n", dwProperty); + ok(!pvarIndex, "pvarIndex != NULL\n"); + ok(pvarValue != NULL, "pvarValue == NULL\n"); + ok(V_VT(pvarValue) == VT_BOOL, "V_VT(pvarValue)=%d\n", V_VT(pvarValue)); + ok(V_BOOL(pvarValue) == VARIANT_TRUE, "V_BOOL(pvarValue)=%x\n", V_BOOL(pvarValue)); + + return E_NOTIMPL; +} + +static const IActiveScriptPropertyVtbl ActiveScriptPropertyVtbl = { + ActiveScriptProperty_QueryInterface, + ActiveScriptProperty_AddRef, + ActiveScriptProperty_Release, + ActiveScriptProperty_GetProperty, + ActiveScriptProperty_SetProperty +}; + +static IActiveScriptProperty ActiveScriptProperty = { &ActiveScriptPropertyVtbl }; + +static HRESULT WINAPI ActiveScriptParseProcedure_QueryInterface(IActiveScriptParseProcedure2 *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI ActiveScriptParseProcedure_AddRef(IActiveScriptParseProcedure2 *iface) +{ + return 2; +} + +static ULONG WINAPI ActiveScriptParseProcedure_Release(IActiveScriptParseProcedure2 *iface) +{ + return 1; +} + +static HRESULT WINAPI ActiveScriptParseProcedure_ParseProcedureText(IActiveScriptParseProcedure2 *iface, + LPCOLESTR pstrCode, LPCOLESTR pstrFormalParams, LPCOLESTR pstrProcedureName, + LPCOLESTR pstrItemName, IUnknown *punkContext, LPCOLESTR pstrDelimiter, + DWORD dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IActiveScriptParseProcedure2Vtbl ActiveScriptParseProcedureVtbl = { + ActiveScriptParseProcedure_QueryInterface, + ActiveScriptParseProcedure_AddRef, + ActiveScriptParseProcedure_Release, + ActiveScriptParseProcedure_ParseProcedureText +}; + +static IActiveScriptParseProcedure2 ActiveScriptParseProcedure = { &ActiveScriptParseProcedureVtbl }; + +static HRESULT WINAPI ActiveScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI ActiveScriptParse_AddRef(IActiveScriptParse *iface) +{ + return 2; +} + +static ULONG WINAPI ActiveScriptParse_Release(IActiveScriptParse *iface) +{ + return 1; +} + +static HRESULT WINAPI ActiveScriptParse_InitNew(IActiveScriptParse *iface) +{ + CHECK_EXPECT(InitNew); + return S_OK; +} + +static HRESULT WINAPI ActiveScriptParse_AddScriptlet(IActiveScriptParse *iface, + LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName, + LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter, + DWORD dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, + BSTR *pbstrName, EXCEPINFO *pexcepinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *iface, + LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext, + LPCOLESTR pstrDelimiter, DWORD dwSourceContextCookie, ULONG ulStartingLine, + DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo) +{ + IDispatchEx *document; + IUnknown *unk; + VARIANT var; + DISPPARAMS dp; + EXCEPINFO ei; + DISPID id, named_arg = DISPID_PROPERTYPUT; + BSTR tmp; + HRESULT hres; + + static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0}; + static const WCHAR testW[] = {'t','e','s','t',0}; + + CHECK_EXPECT(ParseScriptText); + + SET_EXPECT(GetScriptDispatch); + + tmp = SysAllocString(documentW); + hres = IDispatchEx_GetDispID(window_dispex, tmp, fdexNameCaseSensitive, &id); + SysFreeString(tmp); + ok(hres == S_OK, "GetDispID(document) failed: %08x\n", hres); + ok(id == DISPID_IHTMLWINDOW2_DOCUMENT, "id=%x\n", id); + + todo_wine CHECK_CALLED(GetScriptDispatch); + + VariantInit(&var); + memset(&dp, 0, sizeof(dp)); + memset(&ei, 0, sizeof(ei)); + + hres = IDispatchEx_InvokeEx(window_dispex, id, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + ok(V_VT(&var) == VT_DISPATCH, "V_VT(var)=%d\n", V_VT(&var)); + ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(&var) == NULL\n"); + + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IDispatchEx, (void**)&document); + VariantClear(&var); + ok(hres == S_OK, "Could not get DispatchEx: %08x\n", hres); + + tmp = SysAllocString(testW); + hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive, &id); + ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(document) failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres); + hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive | fdexNameImplicit, &id); + ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(document) failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres); + SysFreeString(tmp); + + id = 0; + tmp = SysAllocString(testW); + hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive|fdexNameEnsure, &id); + SysFreeString(tmp); + ok(hres == S_OK, "GetDispID(document) failed: %08x\n", hres); + ok(id, "id == 0\n"); + + dp.cArgs = 1; + dp.rgvarg = &var; + dp.cNamedArgs = 1; + dp.rgdispidNamedArgs = &named_arg; + V_VT(&var) = VT_I4; + V_I4(&var) = 100; + + hres = IDispatchEx_InvokeEx(document, id, LOCALE_NEUTRAL, INVOKE_PROPERTYPUT, &dp, NULL, &ei, NULL); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + + tmp = SysAllocString(testW); + hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive, &id); + SysFreeString(tmp); + ok(hres == S_OK, "GetDispID(document) failed: %08x\n", hres); + + VariantInit(&var); + memset(&dp, 0, sizeof(dp)); + memset(&ei, 0, sizeof(ei)); + hres = IDispatchEx_InvokeEx(document, id, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + ok(V_VT(&var) == VT_I4, "V_VT(var)=%d\n", V_VT(&var)); + ok(V_I4(&var) == 100, "V_I4(&var) == NULL\n"); + + IDispatchEx_Release(document); + + unk = (void*)0xdeadbeef; + hres = IDispatchEx_GetNameSpaceParent(window_dispex, &unk); + ok(hres == S_OK, "GetNameSpaceParent failed: %08x\n", hres); + ok(!unk, "unk=%p, expected NULL\n", unk); + + return S_OK; +} + +static const IActiveScriptParseVtbl ActiveScriptParseVtbl = { + ActiveScriptParse_QueryInterface, + ActiveScriptParse_AddRef, + ActiveScriptParse_Release, + ActiveScriptParse_InitNew, + ActiveScriptParse_AddScriptlet, + ActiveScriptParse_ParseScriptText +}; + +static IActiveScriptParse ActiveScriptParse = { &ActiveScriptParseVtbl }; + static HRESULT WINAPI ActiveScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv) { *ppv = NULL; @@ -243,8 +543,23 @@ static HRESULT WINAPI ActiveScript_QueryInterface(IActiveScript *iface, REFIID r } if(IsEqualGUID(&IID_IActiveScriptParse, riid)) { - /* TODO */ - return E_NOINTERFACE; + *ppv = &ActiveScriptParse; + return S_OK; + } + + if(IsEqualGUID(&IID_IActiveScriptParseProcedure2, riid)) { + *ppv = &ActiveScriptParseProcedure; + return S_OK; + } + + if(IsEqualGUID(&IID_IActiveScriptProperty, riid)) { + *ppv = &ActiveScriptProperty; + return S_OK; + } + + if(IsEqualGUID(&IID_IObjectSafety, riid)) { + *ppv = &ObjectSafety; + return S_OK; } ok(0, "unexpected riid %s\n", debugstr_guid(riid)); @@ -263,8 +578,34 @@ static ULONG WINAPI ActiveScript_Release(IActiveScript *iface) static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + IActiveScriptSiteInterruptPoll *poll; + IActiveScriptSiteDebug *debug; + LCID lcid; + HRESULT hres; + + CHECK_EXPECT(SetScriptSite); + + ok(pass != NULL, "pass == NULL\n"); + + hres = IActiveScriptSite_QueryInterface(pass, &IID_IActiveScriptSiteInterruptPoll, (void**)&poll); + ok(hres == S_OK, "Could not get IActiveScriptSiteInterruptPoll interface: %08x\n", hres); + if(FAILED(hres)) + IActiveScriptSiteInterruptPoll_Release(poll); + + hres = IActiveScriptSite_GetLCID(pass, &lcid); + ok(hres == S_OK, "GetLCID failed: %08x\n", hres); + + hres = IActiveScriptSite_OnStateChange(pass, (state = SCRIPTSTATE_INITIALIZED)); + ok(hres == S_OK, "OnStateChange failed: %08x\n", hres); + + hres = IActiveScriptSite_QueryInterface(pass, &IID_IActiveScriptSiteDebug, (void**)&debug); + ok(hres == S_OK, "Could not get IActiveScriptSiteDebug interface: %08x\n", hres); + if(SUCCEEDED(hres)) + IActiveScriptSiteDebug32_Release(debug); + + site = pass; + IActiveScriptSite_AddRef(site); + return S_OK; } static HRESULT WINAPI ActiveScript_GetScriptSite(IActiveScript *iface, REFIID riid, @@ -276,27 +617,76 @@ static HRESULT WINAPI ActiveScript_GetScriptSite(IActiveScript *iface, REFIID ri static HRESULT WINAPI ActiveScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + HRESULT hres; + + switch(ss) { + case SCRIPTSTATE_STARTED: + CHECK_EXPECT(SetScriptState_STARTED); + break; + case SCRIPTSTATE_CONNECTED: + CHECK_EXPECT(SetScriptState_CONNECTED); + break; + case SCRIPTSTATE_DISCONNECTED: + CHECK_EXPECT(SetScriptState_DISCONNECTED); + break; + default: + ok(0, "unexpected state %d\n", ss); + return E_NOTIMPL; + } + + hres = IActiveScriptSite_OnStateChange(site, (state = ss)); + return S_OK; } static HRESULT WINAPI ActiveScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT(GetScriptState); + + *pssState = state; + return S_OK; } static HRESULT WINAPI ActiveScript_Close(IActiveScript *iface) { - ok(0, "unexpected call\n"); + CHECK_EXPECT(Close); return E_NOTIMPL; } static HRESULT WINAPI ActiveScript_AddNamedItem(IActiveScript *iface, - LPCOLESTR pstrName, DWORD dwFlags) + LPCOLESTR pstrName, DWORD dwFlags) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + IDispatch *disp; + IUnknown *unk = NULL, *unk2; + HRESULT hres; + + static const WCHAR windowW[] = {'w','i','n','d','o','w',0}; + + static const IID unknown_iid = {0x719C3050,0xF9D3,0x11CF,{0xA4,0x93,0x00,0x40,0x05,0x23,0xA8,0xA0}}; + + CHECK_EXPECT(AddNamedItem); + + ok(!lstrcmpW(pstrName, windowW), "pstrName=%s\n", debugstr_w(pstrName)); + ok(dwFlags == (SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS), "dwFlags=%x\n", dwFlags); + + hres = IActiveScriptSite_GetItemInfo(site, windowW, SCRIPTINFO_IUNKNOWN, &unk, NULL); + ok(hres == S_OK, "GetItemInfo failed: %08x\n", hres); + ok(unk != NULL, "unk == NULL\n"); + + hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp); + ok(hres == S_OK, "Could not get IDispatch interface: %08x\n", hres); + if(SUCCEEDED(hres)) + IDispatch_Release(disp); + + hres = IUnknown_QueryInterface(unk, &unknown_iid, (void**)&unk2); + ok(hres == E_NOINTERFACE, "Got ?? interface: %p\n", unk2); + if(SUCCEEDED(hres)) + IUnknown_Release(unk2); + + hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&window_dispex); + ok(hres == S_OK, "Could not get IDispatchEx interface: %08x\n", hres); + + IUnknown_Release(unk); + return S_OK; } static HRESULT WINAPI ActiveScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib, @@ -309,7 +699,7 @@ static HRESULT WINAPI ActiveScript_AddTypeLib(IActiveScript *iface, REFGUID rgui static HRESULT WINAPI ActiveScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName, IDispatch **ppdisp) { - ok(0, "unexpected call\n"); + CHECK_EXPECT(GetScriptDispatch); return E_NOTIMPL; } @@ -432,13 +822,44 @@ static void test_simple_script(void) IHTMLDocument2 *doc; SET_EXPECT(CreateInstance); + SET_EXPECT(GetInterfaceSafetyOptions); + SET_EXPECT(SetInterfaceSafetyOptions); + SET_EXPECT(SetProperty); + SET_EXPECT(InitNew); + SET_EXPECT(SetScriptSite); + SET_EXPECT(GetScriptState); + SET_EXPECT(SetScriptState_STARTED); + SET_EXPECT(AddNamedItem); + SET_EXPECT(ParseScriptText); + SET_EXPECT(SetScriptState_CONNECTED); doc = create_and_load_doc(simple_script_str); if(!doc) return; CHECK_CALLED(CreateInstance); + CHECK_CALLED(GetInterfaceSafetyOptions); + CHECK_CALLED(SetInterfaceSafetyOptions); + CHECK_CALLED(SetProperty); + CHECK_CALLED(InitNew); + CHECK_CALLED(SetScriptSite); + CHECK_CALLED(GetScriptState); + CHECK_CALLED(SetScriptState_STARTED); + CHECK_CALLED(AddNamedItem); + CHECK_CALLED(ParseScriptText); + CHECK_CALLED(SetScriptState_CONNECTED); + + if(site) + IActiveScriptSite_Release(site); + if(window_dispex) + IDispatchEx_Release(window_dispex); + + SET_EXPECT(SetScriptState_DISCONNECTED); + SET_EXPECT(Close); IHTMLDocument2_Release(doc); + + CHECK_CALLED(SetScriptState_DISCONNECTED); + CHECK_CALLED(Close); } static BOOL init_key(const char *key_name, const char *def_value, BOOL init) diff --git a/rostests/winetests/msi/automation.c b/rostests/winetests/msi/automation.c index f2e5c13abe4..68b0f75c25c 100644 --- a/rostests/winetests/msi/automation.c +++ b/rostests/winetests/msi/automation.c @@ -554,16 +554,6 @@ static void test_dispid(void) } 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"); @@ -583,20 +573,28 @@ static void test_dispid(void) dispid = get_dispid(pInstaller, "FileSignatureInfo"); ok(dispid == 48, "Expected 48, got %d\n", dispid); } - - /* MSDN claims the following functions exist but IDispatch->GetIDsOfNames disagrees */ + 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); 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); + ok(dispid == 59 || dispid == -1, "Expected 59 or -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); + ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid); + dispid = get_dispid( pInstaller, "ProductInfoFromScript" ); + ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid); dispid = get_dispid( pInstaller, "AdvertiseProduct" ); - ok(dispid == -1, "Expected -1, got %d\n", dispid); + ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid); + dispid = get_dispid( pInstaller, "CreateAdvertiseScript" ); + ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid); dispid = get_dispid( pInstaller, "PatchFiles" ); - ok(dispid == -1, "Expected -1, got %d\n", dispid); + ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid); } /* Test basic IDispatch functions */ @@ -2011,9 +2009,12 @@ static void test_Installer_Products(BOOL bProductInstalled) } } - ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n", - bProductInstalled ? "be" : "not be", - bProductFound ? "found" : "not found"); + if (bProductInstalled) todo_wine + { + ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n", + bProductInstalled ? "be" : "not be", + bProductFound ? "found" : "not found"); + } if (pEnum) { @@ -2305,7 +2306,7 @@ static void test_Installer_InstallProduct(void) RegCloseKey(hkey); res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203"); - todo_wine ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_SUCCESS, got %d\n", res); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); /* Delete installation files we installed */ delete_test_files(); diff --git a/rostests/winetests/msi/db.c b/rostests/winetests/msi/db.c index 3a627c0ea8b..5d5eb08f3c8 100644 --- a/rostests/winetests/msi/db.c +++ b/rostests/winetests/msi/db.c @@ -3248,6 +3248,9 @@ static void test_temporary_table(void) ok( cond == MSICONDITION_NONE, "wrong return condition\n"); } + cond = MsiDatabaseIsTablePersistent(hdb, "_Storages"); + ok( cond == MSICONDITION_NONE, "wrong return condition\n"); + cond = MsiDatabaseIsTablePersistent(hdb, "_Streams"); ok( cond == MSICONDITION_NONE, "wrong return condition\n"); @@ -3963,6 +3966,11 @@ static void test_special_tables(void) r = run_query(hdb, 0, query); ok(r == ERROR_SUCCESS, "failed to create table\n"); + query = "CREATE TABLE `_Storages` ( " + "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)"; + r = run_query(hdb, 0, query); + todo_wine ok(r == ERROR_BAD_QUERY_SYNTAX, "created _Streams table\n"); + query = "CREATE TABLE `_Streams` ( " "`foo` INT NOT NULL, `bar` INT LOCALIZABLE PRIMARY KEY `foo`)"; r = run_query(hdb, 0, query); @@ -5988,6 +5996,124 @@ static void test_where_viewmodify(void) MsiCloseHandle(hdb); } +static void test_storages_table(void) +{ + MSIHANDLE hdb, hview, hrec; + char file[MAX_PATH]; + char buf[MAX_PATH]; + DWORD size; + UINT r; + + hdb = create_db(); + ok(hdb, "failed to create db\n"); + + r = MsiDatabaseCommit(hdb); + ok(r == ERROR_SUCCESS , "Failed to commit database\n"); + + MsiCloseHandle(hdb); + + r = MsiOpenDatabase(msifile, MSIDBOPEN_TRANSACT, &hdb); + ok(r == ERROR_SUCCESS , "Failed to open database\n"); + + /* check the column types */ + hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_TYPES); + ok(hrec, "failed to get column info hrecord\n"); + todo_wine + { + ok(check_record(hrec, 1, "s62"), "wrong hrecord type\n"); + ok(check_record(hrec, 2, "V0"), "wrong hrecord type\n"); + } + + MsiCloseHandle(hrec); + + /* now try the names */ + hrec = get_column_info(hdb, "SELECT * FROM `_Storages`", MSICOLINFO_NAMES); + ok(hrec, "failed to get column info hrecord\n"); + todo_wine + { + ok(check_record(hrec, 1, "Name"), "wrong hrecord type\n"); + ok(check_record(hrec, 2, "Data"), "wrong hrecord type\n"); + } + + MsiCloseHandle(hrec); + + /* insert a file into the _Storages table */ + create_file("test.txt"); + + hrec = MsiCreateRecord(2); + MsiRecordSetString(hrec, 1, "data"); + + r = MsiRecordSetStream(hrec, 2, "test.txt"); + ok(r == ERROR_SUCCESS, "Failed to add stream data to the hrecord: %d\n", r); + + DeleteFile("test.txt"); + + r = MsiDatabaseOpenView(hdb, + "INSERT INTO `_Storages` (`Name`, `Data`) VALUES (?, ?)", &hview); + todo_wine + { + ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r); + } + + r = MsiViewExecute(hview, hrec); + todo_wine + { + ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r); + } + + MsiCloseHandle(hrec); + MsiCloseHandle(hview); + + r = MsiDatabaseOpenView(hdb, + "SELECT `Name`, `Data` FROM `_Storages`", &hview); + todo_wine + { + ok(r == ERROR_SUCCESS, "Failed to open database hview: %d\n", r); + } + + r = MsiViewExecute(hview, 0); + todo_wine + { + ok(r == ERROR_SUCCESS, "Failed to execute hview: %d\n", r); + } + + r = MsiViewFetch(hview, &hrec); + todo_wine + { + ok(r == ERROR_SUCCESS, "Failed to fetch hrecord: %d\n", r); + } + + size = MAX_PATH; + r = MsiRecordGetString(hrec, 1, file, &size); + todo_wine + { + ok(r == ERROR_SUCCESS, "Failed to get string: %d\n", r); + ok(!lstrcmp(file, "data"), "Expected 'data', got %s\n", file); + } + + size = MAX_PATH; + lstrcpyA(buf, "apple"); + r = MsiRecordReadStream(hrec, 2, buf, &size); + ok(!lstrcmp(buf, "apple"), "Expected buf to be unchanged, got %s\n", buf); + todo_wine + { + ok(r == ERROR_SUCCESS, "Failed to get stream: %d\n", r); + ok(size == 0, "Expected 0, got %d\n", size); + } + + MsiCloseHandle(hrec); + + r = MsiViewFetch(hview, &hrec); + todo_wine + { + ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r); + } + + MsiCloseHandle(hview); + MsiCloseHandle(hdb); + DeleteFile(msifile); +} + START_TEST(db) { test_msidatabase(); @@ -6025,4 +6151,5 @@ START_TEST(db) test_forcecodepage(); test_viewmodify_refresh(); test_where_viewmodify(); + test_storages_table(); } diff --git a/rostests/winetests/msi/install.c b/rostests/winetests/msi/install.c index c9575308c7d..8fa729a0833 100644 --- a/rostests/winetests/msi/install.c +++ b/rostests/winetests/msi/install.c @@ -630,6 +630,67 @@ static const CHAR ca51_custom_action_dat[] = "Action\tType\tSource\tTarget\n" "GoodSetProperty\t51\tMYPROP\t42\n" "BadSetProperty\t51\t\tMYPROP\n"; +static const CHAR is_feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n" + "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n" + "Feature\tFeature\n" + "one\t\t\t\t2\t1\t\t0\n" /* favorLocal */ + "two\t\t\t\t2\t1\t\t1\n" /* favorSource */ + "three\t\t\t\t2\t1\t\t4\n" /* favorAdvertise */ + "four\t\t\t\t2\t0\t\t0"; /* disabled */ + +static const CHAR is_component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" + "s72\tS38\ts72\ti2\tS255\tS72\n" + "Component\tComponent\n" + "alpha\t\tMSITESTDIR\t0\t\talpha_file\n" /* favorLocal:Local */ + "beta\t\tMSITESTDIR\t1\t\tbeta_file\n" /* favorLocal:Source */ + "gamma\t\tMSITESTDIR\t2\t\tgamma_file\n" /* favorLocal:Optional */ + "theta\t\tMSITESTDIR\t0\t\ttheta_file\n" /* favorSource:Local */ + "delta\t\tMSITESTDIR\t1\t\tdelta_file\n" /* favorSource:Source */ + "epsilon\t\tMSITESTDIR\t2\t\tepsilon_file\n" /* favorSource:Optional */ + "zeta\t\tMSITESTDIR\t0\t\tzeta_file\n" /* favorAdvertise:Local */ + "iota\t\tMSITESTDIR\t1\t\tiota_file\n" /* favorAdvertise:Source */ + "eta\t\tMSITESTDIR\t2\t\teta_file\n" /* favorAdvertise:Optional */ + "kappa\t\tMSITESTDIR\t0\t\tkappa_file\n" /* disabled:Local */ + "lambda\t\tMSITESTDIR\t1\t\tlambda_file\n" /* disabled:Source */ + "mu\t\tMSITESTDIR\t2\t\tmu_file\n"; /* disabled:Optional */ + +static const CHAR is_feature_comp_dat[] = "Feature_\tComponent_\n" + "s38\ts72\n" + "FeatureComponents\tFeature_\tComponent_\n" + "one\talpha\n" + "one\tbeta\n" + "one\tgamma\n" + "two\ttheta\n" + "two\tdelta\n" + "two\tepsilon\n" + "three\tzeta\n" + "three\tiota\n" + "three\teta\n" + "four\tkappa\n" + "four\tlambda\n" + "four\tmu"; + +static const CHAR is_file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n" + "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n" + "File\tFile\n" + "alpha_file\talpha\talpha\t500\t\t\t8192\t1\n" + "beta_file\tbeta\tbeta\t500\t\t\t8291\t2\n" + "gamma_file\tgamma\tgamma\t500\t\t\t8192\t3\n" + "theta_file\ttheta\ttheta\t500\t\t\t8192\t4\n" + "delta_file\tdelta\tdelta\t500\t\t\t8192\t5\n" + "epsilon_file\tepsilon\tepsilon\t500\t\t\t8192\t6\n" + "zeta_file\tzeta\tzeta\t500\t\t\t8192\t7\n" + "iota_file\tiota\tiota\t500\t\t\t8192\t8\n" + "eta_file\teta\teta\t500\t\t\t8192\t9\n" + "kappa_file\tkappa\tkappa\t500\t\t\t8192\t10\n" + "lambda_file\tlambda\tlambda\t500\t\t\t8192\t11\n" + "mu_file\tmu\tmu\t500\t\t\t8192\t12"; + +static const CHAR is_media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n" + "i2\ti4\tL64\tS255\tS32\tS72\n" + "Media\tDiskId\n" + "1\t12\t\t\tDISK1\t\n"; + typedef struct _msi_table { const CHAR *filename; @@ -968,6 +1029,18 @@ static const msi_table ca51_tables[] = ADD_TABLE(ca51_custom_action), }; +static const msi_table is_tables[] = +{ + ADD_TABLE(is_component), + ADD_TABLE(directory), + ADD_TABLE(is_feature), + ADD_TABLE(is_feature_comp), + ADD_TABLE(is_file), + ADD_TABLE(install_exec_seq), + ADD_TABLE(is_media), + ADD_TABLE(property), +}; + /* cabinet definitions */ /* make the max size large so there is only one cab file */ @@ -1094,6 +1167,27 @@ static void init_functionpointers(void) #undef GET_PROC } +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 BOOL check_record(MSIHANDLE rec, UINT field, LPCSTR val) { CHAR buffer[0x20]; @@ -2060,7 +2154,8 @@ static void check_reg_str(HKEY prodkey, LPCSTR name, LPCSTR expected, BOOL bcase val[0] = '\0'; res = RegQueryValueExA(prodkey, name, NULL, &type, (LPBYTE)val, &size); - if (res != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) + if (res != ERROR_SUCCESS || + (type != REG_SZ && type != REG_EXPAND_SZ && type != REG_MULTI_SZ)) { ok_(__FILE__, line)(FALSE, "Key doesn't exist or wrong type\n"); return; @@ -2097,12 +2192,24 @@ static void check_reg_dword(HKEY prodkey, LPCSTR name, DWORD expected, DWORD lin #define CHECK_REG_STR(prodkey, name, expected) \ check_reg_str(prodkey, name, expected, TRUE, __LINE__); +#define CHECK_DEL_REG_STR(prodkey, name, expected) \ + check_reg_str(prodkey, name, expected, TRUE, __LINE__); \ + RegDeleteValueA(prodkey, name); + #define CHECK_REG_ISTR(prodkey, name, expected) \ check_reg_str(prodkey, name, expected, FALSE, __LINE__); +#define CHECK_DEL_REG_ISTR(prodkey, name, expected) \ + check_reg_str(prodkey, name, expected, FALSE, __LINE__); \ + RegDeleteValueA(prodkey, name); + #define CHECK_REG_DWORD(prodkey, name, expected) \ check_reg_dword(prodkey, name, expected, __LINE__); +#define CHECK_DEL_REG_DWORD(prodkey, name, expected) \ + check_reg_dword(prodkey, name, expected, __LINE__); \ + RegDeleteValueA(prodkey, name); + static void get_date_str(LPSTR date) { SYSTEMTIME systime; @@ -2116,552 +2223,21 @@ static void test_publish_registerproduct(void) { UINT r; LONG res; - HKEY uninstall, prodkey; - INSTALLSTATE state; - CHAR prodcode[] = "{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"; + HKEY hkey; + HKEY props, usage; + LPSTR usersid; char date[MAX_PATH]; char temp[MAX_PATH]; - - 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); - - 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); - - /* RegisterProduct */ - r = MsiInstallProductA(msifile, "REGISTER_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_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_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); - - 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); - - /* 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); - } - ok(pf_exists("msitest\\maximus"), "File deleted\n"); - ok(pf_exists("msitest"), "File deleted\n"); - - state = MsiQueryProductState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); - todo_wine - { - 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); - todo_wine - { - 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); - todo_wine - { - ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); - } - - todo_wine - { - 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); - CHECK_REG_DWORD(prodkey, "EstimatedSize", 12); - } - - RegCloseKey(prodkey); - - /* 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_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_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); - - 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 - { - 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"); - - /* 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}"); - todo_wine - { - 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; - } + char keypath[MAX_PATH]; + + static const CHAR uninstall[] = "Software\\Microsoft\\Windows\\CurrentVersion" + "\\Uninstall\\{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"; + static const CHAR userdata[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Installer" + "\\UserData\\%s\\Products\\84A88FD7F6998CE40A22FB59F6B9C2BB"; + static const CHAR ugkey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Installer" + "\\UpgradeCodes\\51AAE0C44620A5E4788506E91F249BD2"; + static const CHAR userugkey[] = "Software\\Microsoft\\Installer\\UpgradeCodes" + "\\51AAE0C44620A5E4788506E91F249BD2"; get_user_sid(&usersid); if (!usersid) @@ -2670,8 +2246,8 @@ static void test_publish_processcomponents(void) return; } - res = RegOpenKeyA(HKEY_LOCAL_MACHINE, subkey, &uninstall); - ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + get_date_str(date); + GetTempPath(MAX_PATH, temp); CreateDirectoryA("msitest", NULL); create_file("msitest\\maximus", 500); @@ -2680,154 +2256,741 @@ static void test_publish_processcomponents(void) 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"); + /* RegisterProduct */ + r = MsiInstallProductA(msifile, "REGISTER_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"); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "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); + res = RegOpenKeyA(HKEY_CURRENT_USER, userugkey, &hkey); 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"); + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, uninstall, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(hkey, "DisplayName", "MSITEST"); + CHECK_DEL_REG_STR(hkey, "DisplayVersion", "1.1.1"); + CHECK_DEL_REG_STR(hkey, "InstallDate", date); + CHECK_DEL_REG_STR(hkey, "InstallSource", temp); + CHECK_DEL_REG_ISTR(hkey, "ModifyPath", "MsiExec.exe /I{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + CHECK_DEL_REG_STR(hkey, "Publisher", "Wine"); + CHECK_DEL_REG_STR(hkey, "UninstallString", "MsiExec.exe /I{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + CHECK_DEL_REG_STR(hkey, "AuthorizedCDFPrefix", NULL); + CHECK_DEL_REG_STR(hkey, "Comments", NULL); + CHECK_DEL_REG_STR(hkey, "Contact", NULL); + CHECK_DEL_REG_STR(hkey, "HelpLink", NULL); + CHECK_DEL_REG_STR(hkey, "HelpTelephone", NULL); + CHECK_DEL_REG_STR(hkey, "InstallLocation", NULL); + CHECK_DEL_REG_STR(hkey, "Readme", NULL); + CHECK_DEL_REG_STR(hkey, "Size", NULL); + CHECK_DEL_REG_STR(hkey, "URLInfoAbout", NULL); + CHECK_DEL_REG_STR(hkey, "URLUpdateInfo", NULL); + CHECK_DEL_REG_DWORD(hkey, "Language", 1033); + CHECK_DEL_REG_DWORD(hkey, "Version", 0x1010001); + CHECK_DEL_REG_DWORD(hkey, "VersionMajor", 1); + CHECK_DEL_REG_DWORD(hkey, "VersionMinor", 1); + CHECK_DEL_REG_DWORD(hkey, "WindowsInstaller", 1); todo_wine { - ok(r == ERROR_UNKNOWN_PRODUCT, "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); + CHECK_DEL_REG_DWORD(hkey, "EstimatedSize", 12); } - 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); + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); - state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "feature"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + sprintf(keypath, userdata, usersid); + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); - state = MsiQueryFeatureState("{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}", "montecristo"); - ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + res = RegOpenKeyA(hkey, "InstallProperties", &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); - 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); + RegDeleteValueA(props, "LocalPackage"); /* LocalPackage is nondeterministic */ + CHECK_DEL_REG_STR(props, "DisplayName", "MSITEST"); + CHECK_DEL_REG_STR(props, "DisplayVersion", "1.1.1"); + CHECK_DEL_REG_STR(props, "InstallDate", date); + CHECK_DEL_REG_STR(props, "InstallSource", temp); + CHECK_DEL_REG_ISTR(props, "ModifyPath", "MsiExec.exe /I{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + CHECK_DEL_REG_STR(props, "Publisher", "Wine"); + CHECK_DEL_REG_STR(props, "UninstallString", "MsiExec.exe /I{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + CHECK_DEL_REG_STR(props, "AuthorizedCDFPrefix", NULL); + CHECK_DEL_REG_STR(props, "Comments", NULL); + CHECK_DEL_REG_STR(props, "Contact", NULL); + CHECK_DEL_REG_STR(props, "HelpLink", NULL); + CHECK_DEL_REG_STR(props, "HelpTelephone", NULL); + CHECK_DEL_REG_STR(props, "InstallLocation", NULL); + CHECK_DEL_REG_STR(props, "Readme", NULL); + CHECK_DEL_REG_STR(props, "Size", NULL); + CHECK_DEL_REG_STR(props, "URLInfoAbout", NULL); + CHECK_DEL_REG_STR(props, "URLUpdateInfo", NULL); + CHECK_DEL_REG_DWORD(props, "Language", 1033); + CHECK_DEL_REG_DWORD(props, "Version", 0x1010001); + CHECK_DEL_REG_DWORD(props, "VersionMajor", 1); + CHECK_DEL_REG_DWORD(props, "VersionMinor", 1); + CHECK_DEL_REG_DWORD(props, "WindowsInstaller", 1); + todo_wine + { + CHECK_DEL_REG_DWORD(props, "EstimatedSize", 12); + } - res = RegOpenKeyA(uninstall, prodcode, &prodkey); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + + res = RegOpenKeyA(hkey, "Usage", &usage); + todo_wine + { + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + } + + RegDeleteKeyA(usage, ""); + RegCloseKey(usage); + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, ugkey, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(hkey, "84A88FD7F6998CE40A22FB59F6B9C2BB", NULL); + + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + /* RegisterProduct, machine */ + r = MsiInstallProductA(msifile, "REGISTER_PRODUCT=1 ALLUSERS=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, userugkey, &hkey); 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"); + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, uninstall, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); - 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); - - /* 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}"); - 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); - - 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); - - /* uninstall */ - r = MsiInstallProductA(msifile, "FULL=1 REMOVE=ALL"); - 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) + CHECK_DEL_REG_STR(hkey, "DisplayName", "MSITEST"); + CHECK_DEL_REG_STR(hkey, "DisplayVersion", "1.1.1"); + CHECK_DEL_REG_STR(hkey, "InstallDate", date); + CHECK_DEL_REG_STR(hkey, "InstallSource", temp); + CHECK_DEL_REG_ISTR(hkey, "ModifyPath", "MsiExec.exe /I{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + CHECK_DEL_REG_STR(hkey, "Publisher", "Wine"); + CHECK_DEL_REG_STR(hkey, "UninstallString", "MsiExec.exe /I{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + CHECK_DEL_REG_STR(hkey, "AuthorizedCDFPrefix", NULL); + CHECK_DEL_REG_STR(hkey, "Comments", NULL); + CHECK_DEL_REG_STR(hkey, "Contact", NULL); + CHECK_DEL_REG_STR(hkey, "HelpLink", NULL); + CHECK_DEL_REG_STR(hkey, "HelpTelephone", NULL); + CHECK_DEL_REG_STR(hkey, "InstallLocation", NULL); + CHECK_DEL_REG_STR(hkey, "Readme", NULL); + CHECK_DEL_REG_STR(hkey, "Size", NULL); + CHECK_DEL_REG_STR(hkey, "URLInfoAbout", NULL); + CHECK_DEL_REG_STR(hkey, "URLUpdateInfo", NULL); + CHECK_DEL_REG_DWORD(hkey, "Language", 1033); + CHECK_DEL_REG_DWORD(hkey, "Version", 0x1010001); + CHECK_DEL_REG_DWORD(hkey, "VersionMajor", 1); + CHECK_DEL_REG_DWORD(hkey, "VersionMinor", 1); + CHECK_DEL_REG_DWORD(hkey, "WindowsInstaller", 1); + todo_wine { - RegDeleteKeyA(comp, ""); - RegCloseKey(comp); + CHECK_DEL_REG_DWORD(hkey, "EstimatedSize", 12); } - RegCloseKey(uninstall); + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + sprintf(keypath, userdata, "S-1-5-18"); + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegOpenKeyA(hkey, "InstallProperties", &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + RegDeleteValueA(props, "LocalPackage"); /* LocalPackage is nondeterministic */ + CHECK_DEL_REG_STR(props, "DisplayName", "MSITEST"); + CHECK_DEL_REG_STR(props, "DisplayVersion", "1.1.1"); + CHECK_DEL_REG_STR(props, "InstallDate", date); + CHECK_DEL_REG_STR(props, "InstallSource", temp); + CHECK_DEL_REG_ISTR(props, "ModifyPath", "MsiExec.exe /I{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + CHECK_DEL_REG_STR(props, "Publisher", "Wine"); + CHECK_DEL_REG_STR(props, "UninstallString", "MsiExec.exe /I{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}"); + CHECK_DEL_REG_STR(props, "AuthorizedCDFPrefix", NULL); + CHECK_DEL_REG_STR(props, "Comments", NULL); + CHECK_DEL_REG_STR(props, "Contact", NULL); + CHECK_DEL_REG_STR(props, "HelpLink", NULL); + CHECK_DEL_REG_STR(props, "HelpTelephone", NULL); + CHECK_DEL_REG_STR(props, "InstallLocation", NULL); + CHECK_DEL_REG_STR(props, "Readme", NULL); + CHECK_DEL_REG_STR(props, "Size", NULL); + CHECK_DEL_REG_STR(props, "URLInfoAbout", NULL); + CHECK_DEL_REG_STR(props, "URLUpdateInfo", NULL); + CHECK_DEL_REG_DWORD(props, "Language", 1033); + CHECK_DEL_REG_DWORD(props, "Version", 0x1010001); + CHECK_DEL_REG_DWORD(props, "VersionMajor", 1); + CHECK_DEL_REG_DWORD(props, "VersionMinor", 1); + CHECK_DEL_REG_DWORD(props, "WindowsInstaller", 1); + todo_wine + { + CHECK_DEL_REG_DWORD(props, "EstimatedSize", 12); + } + + RegDeleteKeyA(props, ""); + RegCloseKey(props); + + res = RegOpenKeyA(hkey, "Usage", &usage); + todo_wine + { + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + } + + RegDeleteKeyA(usage, ""); + RegCloseKey(usage); + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, ugkey, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(hkey, "84A88FD7F6998CE40A22FB59F6B9C2BB", NULL); + + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + DeleteFile(msifile); + DeleteFile("msitest\\maximus"); + RemoveDirectory("msitest"); + HeapFree(GetProcessHeap(), 0, usersid); +} + +static void test_publish_publishproduct(void) +{ + UINT r; + LONG res; + LPSTR usersid; + HKEY sourcelist, net, props; + HKEY hkey, patches, media; + CHAR keypath[MAX_PATH]; + CHAR temp[MAX_PATH]; + CHAR path[MAX_PATH]; + + static const CHAR prodpath[] = "Software\\Microsoft\\Windows\\CurrentVersion" + "\\Installer\\UserData\\%s\\Products" + "\\84A88FD7F6998CE40A22FB59F6B9C2BB"; + static const CHAR cuprodpath[] = "Software\\Microsoft\\Installer\\Products" + "\\84A88FD7F6998CE40A22FB59F6B9C2BB"; + static const CHAR cuupgrades[] = "Software\\Microsoft\\Installer\\UpgradeCodes" + "\\51AAE0C44620A5E4788506E91F249BD2"; + static const CHAR badprod[] = "Software\\Microsoft\\Windows\\CurrentVersion" + "\\Installer\\Products" + "\\84A88FD7F6998CE40A22FB59F6B9C2BB"; + static const CHAR machprod[] = "Installer\\Products\\84A88FD7F6998CE40A22FB59F6B9C2BB"; + static const CHAR machup[] = "Installer\\UpgradeCodes\\51AAE0C44620A5E4788506E91F249BD2"; + + get_user_sid(&usersid); + if (!usersid) + { + skip("ConvertSidToStringSidA is not available\n"); + return; + } + + GetTempPath(MAX_PATH, temp); + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\maximus", 500); + + create_database(msifile, pp_tables, sizeof(pp_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL); + + /* PublishProduct, current user */ + r = MsiInstallProductA(msifile, "PUBLISH_PRODUCT=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, badprod, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + sprintf(keypath, prodpath, usersid); + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegOpenKeyA(hkey, "InstallProperties", &props); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + res = RegOpenKeyA(hkey, "Patches", &patches); + todo_wine + { + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(patches, "AllPatches", NULL); + } + + RegDeleteKeyA(patches, ""); + RegCloseKey(patches); + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + res = RegOpenKeyA(HKEY_CURRENT_USER, cuprodpath, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(hkey, "ProductName", "MSITEST"); + CHECK_DEL_REG_STR(hkey, "PackageCode", "AC75740029052c94DA02821EECD05F2F"); + CHECK_DEL_REG_DWORD(hkey, "Language", 1033); + CHECK_DEL_REG_DWORD(hkey, "Version", 0x1010001); + CHECK_DEL_REG_DWORD(hkey, "AuthorizedLUAApp", 0); + CHECK_DEL_REG_DWORD(hkey, "Assignment", 0); + CHECK_DEL_REG_DWORD(hkey, "AdvertiseFlags", 0x184); + CHECK_DEL_REG_DWORD(hkey, "InstanceType", 0); + CHECK_DEL_REG_STR(hkey, "Clients", ":"); + + res = RegOpenKeyA(hkey, "SourceList", &sourcelist); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + lstrcpyA(path, "n;1;"); + lstrcatA(path, temp); + CHECK_DEL_REG_STR(sourcelist, "LastUsedSource", path); + CHECK_DEL_REG_STR(sourcelist, "PackageName", "msitest.msi"); + + res = RegOpenKeyA(sourcelist, "Net", &net); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(net, "1", temp); + + RegDeleteKeyA(net, ""); + RegCloseKey(net); + + res = RegOpenKeyA(sourcelist, "Media", &media); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(media, "1", "DISK1;"); + + RegDeleteKeyA(media, ""); + RegCloseKey(media); + RegDeleteKeyA(sourcelist, ""); + RegCloseKey(sourcelist); + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + res = RegOpenKeyA(HKEY_CURRENT_USER, cuupgrades, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(hkey, "84A88FD7F6998CE40A22FB59F6B9C2BB", NULL); + + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + /* PublishProduct, machine */ + r = MsiInstallProductA(msifile, "PUBLISH_PRODUCT=1 ALLUSERS=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, badprod, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + sprintf(keypath, prodpath, "S-1-5-18"); + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegOpenKeyA(hkey, "InstallProperties", &props); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + res = RegOpenKeyA(hkey, "Patches", &patches); + todo_wine + { + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(patches, "AllPatches", NULL); + } + + RegDeleteKeyA(patches, ""); + RegCloseKey(patches); + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + res = RegOpenKeyA(HKEY_CLASSES_ROOT, machprod, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(hkey, "ProductName", "MSITEST"); + CHECK_DEL_REG_STR(hkey, "PackageCode", "AC75740029052c94DA02821EECD05F2F"); + CHECK_DEL_REG_DWORD(hkey, "Language", 1033); + CHECK_DEL_REG_DWORD(hkey, "Version", 0x1010001); + CHECK_DEL_REG_DWORD(hkey, "AuthorizedLUAApp", 0); + todo_wine CHECK_DEL_REG_DWORD(hkey, "Assignment", 1); + CHECK_DEL_REG_DWORD(hkey, "AdvertiseFlags", 0x184); + CHECK_DEL_REG_DWORD(hkey, "InstanceType", 0); + CHECK_DEL_REG_STR(hkey, "Clients", ":"); + + res = RegOpenKeyA(hkey, "SourceList", &sourcelist); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + lstrcpyA(path, "n;1;"); + lstrcatA(path, temp); + CHECK_DEL_REG_STR(sourcelist, "LastUsedSource", path); + CHECK_DEL_REG_STR(sourcelist, "PackageName", "msitest.msi"); + + res = RegOpenKeyA(sourcelist, "Net", &net); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(net, "1", temp); + + RegDeleteKeyA(net, ""); + RegCloseKey(net); + + res = RegOpenKeyA(sourcelist, "Media", &media); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(media, "1", "DISK1;"); + + RegDeleteKeyA(media, ""); + RegCloseKey(media); + RegDeleteKeyA(sourcelist, ""); + RegCloseKey(sourcelist); + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + res = RegOpenKeyA(HKEY_CLASSES_ROOT, machup, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_DEL_REG_STR(hkey, "84A88FD7F6998CE40A22FB59F6B9C2BB", NULL); + + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + DeleteFile(msifile); + DeleteFile("msitest\\maximus"); + RemoveDirectory("msitest"); + HeapFree(GetProcessHeap(), 0, usersid); +} + +static void test_publish_publishfeatures(void) +{ + UINT r; + LONG res; + HKEY hkey; + LPSTR usersid; + CHAR keypath[MAX_PATH]; + + static const CHAR cupath[] = "Software\\Microsoft\\Installer\\Features" + "\\84A88FD7F6998CE40A22FB59F6B9C2BB"; + static const CHAR udpath[] = "Software\\Microsoft\\Windows\\CurrentVersion" + "\\Installer\\UserData\\%s\\Products" + "\\84A88FD7F6998CE40A22FB59F6B9C2BB\\Features"; + static const CHAR featkey[] = "Software\\Microsoft\\Windows\\CurrentVersion" + "\\Installer\\Features"; + static const CHAR classfeat[] = "Software\\Classes\\Installer\\Features" + "\\84A88FD7F6998CE40A22FB59F6B9C2BB"; + + get_user_sid(&usersid); + if (!usersid) + { + skip("ConvertSidToStringSidA is not available\n"); + return; + } + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\maximus", 500); + + create_database(msifile, pp_tables, sizeof(pp_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL); + + /* PublishFeatures, current user */ + r = MsiInstallProductA(msifile, "PUBLISH_FEATURES=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, featkey, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, classfeat, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + res = RegOpenKeyA(HKEY_CURRENT_USER, cupath, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(hkey, "feature", ""); + CHECK_REG_STR(hkey, "montecristo", ""); + + RegDeleteValueA(hkey, "feature"); + RegDeleteValueA(hkey, "montecristo"); + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + sprintf(keypath, udpath, usersid); + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(hkey, "feature", "VGtfp^p+,?82@JU1j_KE"); + CHECK_REG_STR(hkey, "montecristo", "VGtfp^p+,?82@JU1j_KE"); + + RegDeleteValueA(hkey, "feature"); + RegDeleteValueA(hkey, "montecristo"); + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + /* PublishFeatures, machine */ + r = MsiInstallProductA(msifile, "PUBLISH_FEATURES=1 ALLUSERS=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, featkey, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + res = RegOpenKeyA(HKEY_CURRENT_USER, cupath, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, classfeat, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(hkey, "feature", ""); + CHECK_REG_STR(hkey, "montecristo", ""); + + RegDeleteValueA(hkey, "feature"); + RegDeleteValueA(hkey, "montecristo"); + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + sprintf(keypath, udpath, "S-1-5-18"); + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &hkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(hkey, "feature", "VGtfp^p+,?82@JU1j_KE"); + CHECK_REG_STR(hkey, "montecristo", "VGtfp^p+,?82@JU1j_KE"); + + RegDeleteValueA(hkey, "feature"); + RegDeleteValueA(hkey, "montecristo"); + RegDeleteKeyA(hkey, ""); + RegCloseKey(hkey); + + DeleteFile(msifile); + DeleteFile("msitest\\maximus"); + RemoveDirectory("msitest"); + HeapFree(GetProcessHeap(), 0, usersid); +} + +static LPSTR reg_get_val_str(HKEY hkey, LPCSTR name) +{ + DWORD len = 0; + LPSTR val; + LONG r; + + r = RegQueryValueExA(hkey, name, NULL, NULL, NULL, &len); + if (r != ERROR_SUCCESS) + return NULL; + + len += sizeof (WCHAR); + val = HeapAlloc(GetProcessHeap(), 0, len); + if (!val) return NULL; + val[0] = 0; + RegQueryValueExA(hkey, name, NULL, NULL, (LPBYTE)val, &len); + return val; +} + +static void get_owner_company(LPSTR *owner, LPSTR *company) +{ + LONG res; + HKEY hkey; + + *owner = *company = NULL; + + res = RegOpenKeyA(HKEY_CURRENT_USER, + "Software\\Microsoft\\MS Setup (ACME)\\User Info", &hkey); + if (res == ERROR_SUCCESS) + { + *owner = reg_get_val_str(hkey, "DefName"); + *company = reg_get_val_str(hkey, "DefCompany"); + RegCloseKey(hkey); + } + + if (!*owner || !*company) + { + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion", &hkey); + if (res == ERROR_SUCCESS) + { + *owner = reg_get_val_str(hkey, "RegisteredOwner"); + *company = reg_get_val_str(hkey, "RegisteredOrganization"); + RegCloseKey(hkey); + } + } + + if (!*owner || !*company) + { + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows NT\\CurrentVersion", &hkey); + if (res == ERROR_SUCCESS) + { + *owner = reg_get_val_str(hkey, "RegisteredOwner"); + *company = reg_get_val_str(hkey, "RegisteredOrganization"); + RegCloseKey(hkey); + } + } +} + +static void test_publish_registeruser(void) +{ + UINT r; + LONG res; + HKEY props; + LPSTR usersid; + LPSTR owner, company; + CHAR keypath[MAX_PATH]; + + static const CHAR keyfmt[] = + "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\" + "UserData\\%s\\Products\\84A88FD7F6998CE40A22FB59F6B9C2BB\\InstallProperties"; + + get_user_sid(&usersid); + if (!usersid) + { + skip("ConvertSidToStringSidA is not available\n"); + return; + } + + get_owner_company(&owner, &company); + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\maximus", 500); + + create_database(msifile, pp_tables, sizeof(pp_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL); + + /* RegisterUser, per-user */ + r = MsiInstallProductA(msifile, "REGISTER_USER=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + sprintf(keypath, keyfmt, usersid); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(props, "ProductID", "none"); + CHECK_REG_STR(props, "RegCompany", company); + CHECK_REG_STR(props, "RegOwner", owner); + + RegDeleteValueA(props, "ProductID"); + RegDeleteValueA(props, "RegCompany"); + RegDeleteValueA(props, "RegOwner"); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + + /* RegisterUser, machine */ + r = MsiInstallProductA(msifile, "REGISTER_USER=1 ALLUSERS=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + sprintf(keypath, keyfmt, "S-1-5-18"); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + CHECK_REG_STR(props, "ProductID", "none"); + CHECK_REG_STR(props, "RegCompany", company); + CHECK_REG_STR(props, "RegOwner", owner); + + RegDeleteValueA(props, "ProductID"); + RegDeleteValueA(props, "RegCompany"); + RegDeleteValueA(props, "RegOwner"); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + + HeapFree(GetProcessHeap(), 0, company); + HeapFree(GetProcessHeap(), 0, owner); + + DeleteFile(msifile); + DeleteFile("msitest\\maximus"); + RemoveDirectory("msitest"); +} + +static void test_publish_processcomponents(void) +{ + UINT r; + LONG res; + DWORD size; + HKEY comp, hkey; + LPSTR usersid; + CHAR val[MAX_PATH]; + CHAR keypath[MAX_PATH]; + + static const CHAR keyfmt[] = + "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\" + "UserData\\%s\\Components\\CBABC2FDCCB35E749A8944D8C1C098B5"; + static const CHAR compkey[] = + "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Components"; + + get_user_sid(&usersid); + if (!usersid) + { + skip("ConvertSidToStringSidA is not available\n"); + return; + } + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\maximus", 500); + + create_database(msifile, pp_tables, sizeof(pp_tables) / sizeof(msi_table)); + + MsiSetInternalUI(INSTALLUILEVEL_FULL, NULL); + + /* ProcessComponents, per-user */ + r = MsiInstallProductA(msifile, "PROCESS_COMPONENTS=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + sprintf(keypath, keyfmt, usersid); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &comp); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + size = MAX_PATH; + res = RegQueryValueExA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB", + NULL, NULL, (LPBYTE)val, &size); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(!lstrcmpA(val, "C:\\Program Files\\msitest\\maximus"), + "Expected \"%s\", got \"%s\"\n", "C:\\Program Files\\msitest\\maximus", val); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, compkey, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + RegDeleteValueA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB"); + RegDeleteKeyA(comp, ""); + RegCloseKey(comp); + + /* ProcessComponents, machine */ + r = MsiInstallProductA(msifile, "PROCESS_COMPONENTS=1 ALLUSERS=1"); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(delete_pf("msitest\\maximus", TRUE), "File not installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + sprintf(keypath, keyfmt, "S-1-5-18"); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, keypath, &comp); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + size = MAX_PATH; + res = RegQueryValueExA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB", + NULL, NULL, (LPBYTE)val, &size); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + ok(!lstrcmpA(val, "C:\\Program Files\\msitest\\maximus"), + "Expected \"%s\", got \"%s\"\n", "C:\\Program Files\\msitest\\maximus", val); + + res = RegOpenKeyA(HKEY_LOCAL_MACHINE, compkey, &hkey); + ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); + + RegDeleteValueA(comp, "84A88FD7F6998CE40A22FB59F6B9C2BB"); + RegDeleteKeyA(comp, ""); + RegCloseKey(comp); + DeleteFile(msifile); DeleteFile("msitest\\maximus"); RemoveDirectory("msitest"); - delete_pfmsitest_files(); } static void test_publish(void) @@ -4231,6 +4394,9 @@ static void test_writeregistryvalues(void) DeleteFile(msifile); DeleteFile("msitest\\augustus"); RemoveDirectory("msitest"); + + RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest"); + RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine"); } static void test_sourcefolder(void) @@ -4289,6 +4455,108 @@ static void test_customaction51(void) RemoveDirectory("msitest"); } +static void test_installstate(void) +{ + UINT r; + + CreateDirectoryA("msitest", NULL); + create_file("msitest\\alpha", 500); + create_file("msitest\\beta", 500); + create_file("msitest\\gamma", 500); + create_file("msitest\\theta", 500); + create_file("msitest\\delta", 500); + create_file("msitest\\epsilon", 500); + create_file("msitest\\zeta", 500); + create_file("msitest\\iota", 500); + create_file("msitest\\eta", 500); + create_file("msitest\\kappa", 500); + create_file("msitest\\lambda", 500); + create_file("msitest\\mu", 500); + + create_database(msifile, is_tables, sizeof(is_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\\alpha", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\beta", TRUE), "File installed\n"); + ok(delete_pf("msitest\\gamma", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\theta", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\delta", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\epsilon", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\zeta", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\iota", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\eta", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\kappa", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\lambda", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\mu", TRUE), "File installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + r = MsiInstallProductA(msifile, "ADDLOCAL=\"one,two,three,four\""); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(delete_pf("msitest\\alpha", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\beta", TRUE), "File installed\n"); + ok(delete_pf("msitest\\gamma", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\theta", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\delta", TRUE), "File installed\n"); + ok(delete_pf("msitest\\epsilon", TRUE), "File not installed\n"); + ok(delete_pf("msitest\\zeta", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\iota", TRUE), "File installed\n"); + ok(delete_pf("msitest\\eta", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\kappa", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\lambda", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\mu", TRUE), "File installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + r = MsiInstallProductA(msifile, "ADDSOURCE=\"one,two,three,four\""); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(delete_pf("msitest\\alpha", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\beta", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\gamma", TRUE), "File installed\n"); + ok(delete_pf("msitest\\theta", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\delta", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\epsilon", TRUE), "File installed\n"); + ok(delete_pf("msitest\\zeta", TRUE), "File not installed\n"); + ok(!delete_pf("msitest\\iota", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\eta", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\kappa", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\lambda", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\mu", TRUE), "File installed\n"); + ok(delete_pf("msitest", FALSE), "File not installed\n"); + + r = MsiInstallProductA(msifile, "REMOVE=\"one,two,three,four\""); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); + ok(!delete_pf("msitest\\alpha", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\beta", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\gamma", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\theta", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\delta", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\epsilon", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\zeta", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\iota", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\eta", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\kappa", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\lambda", TRUE), "File installed\n"); + ok(!delete_pf("msitest\\mu", TRUE), "File installed\n"); + ok(!delete_pf("msitest", FALSE), "File installed\n"); + + DeleteFile(msifile); + DeleteFile("msitest\\alpha"); + DeleteFile("msitest\\beta"); + DeleteFile("msitest\\gamma"); + DeleteFile("msitest\\theta"); + DeleteFile("msitest\\delta"); + DeleteFile("msitest\\epsilon"); + DeleteFile("msitest\\zeta"); + DeleteFile("msitest\\iota"); + DeleteFile("msitest\\eta"); + DeleteFile("msitest\\kappa"); + DeleteFile("msitest\\lambda"); + DeleteFile("msitest\\mu"); + RemoveDirectory("msitest"); +} + START_TEST(install) { DWORD len; @@ -4339,6 +4607,7 @@ START_TEST(install) test_writeregistryvalues(); test_sourcefolder(); test_customaction51(); + test_installstate(); SetCurrentDirectoryA(prev_path); } diff --git a/rostests/winetests/msi/msi.c b/rostests/winetests/msi/msi.c index b704d2b13b8..52cfd74564e 100644 --- a/rostests/winetests/msi/msi.c +++ b/rostests/winetests/msi/msi.c @@ -735,6 +735,8 @@ static void test_MsiQueryFeatureState(void) state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + /* MSIINSTALLCONTEXT_USERUNMANAGED */ + lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Features\\"); lstrcatA(keypath, prod_squashed); @@ -748,6 +750,7 @@ static void test_MsiQueryFeatureState(void) res = RegSetValueExA(userkey, "feature", 0, REG_SZ, (const BYTE *)"", 2); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + /* feature value exists */ state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); @@ -760,6 +763,7 @@ static void test_MsiQueryFeatureState(void) res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey); ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + /* userdata features key exists */ state = MsiQueryFeatureStateA(prodcode, "feature"); ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); @@ -811,7 +815,183 @@ static void test_MsiQueryFeatureState(void) ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); RegDeleteValueA(compkey, prod_squashed); - RegDeleteValueA(compkey, ""); + RegDeleteKeyA(compkey, ""); + RegDeleteValueA(localkey, "feature"); + RegDeleteValueA(userkey, "feature"); + RegDeleteKeyA(userkey, ""); + RegCloseKey(compkey); + RegCloseKey(localkey); + RegCloseKey(userkey); + + /* MSIINSTALLCONTEXT_USERMANAGED */ + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\Managed\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Installer\\Features\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* feature key exists */ + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + res = RegSetValueExA(userkey, "feature", 0, REG_SZ, (const BYTE *)"", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* feature value exists */ + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + lstrcatA(keypath, "\\Features"); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* userdata features key exists */ + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)"aaaaaaaaaaaaaaaaaaa", 20); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_BADCONFIG, "Expected INSTALLSTATE_BADCONFIG, got %d\n", state); + + res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)"aaaaaaaaaaaaaaaaaaaa", 21); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)"aaaaaaaaaaaaaaaaaaaaa", 22); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)comp_base85, 21); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Components\\"); + lstrcatA(keypath, comp_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &compkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"", 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"apple", 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + RegDeleteValueA(compkey, prod_squashed); + RegDeleteKeyA(compkey, ""); + RegDeleteValueA(localkey, "feature"); + RegDeleteValueA(userkey, "feature"); + RegDeleteKeyA(userkey, ""); + RegCloseKey(compkey); + RegCloseKey(localkey); + RegCloseKey(userkey); + + /* MSIINSTALLCONTEXT_MACHINE */ + + lstrcpyA(keypath, "Software\\Classes\\Installer\\Features\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* feature key exists */ + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state); + + res = RegSetValueExA(userkey, "feature", 0, REG_SZ, (const BYTE *)"", 2); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* feature value exists */ + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, "S-1-5-18\\Products\\"); + lstrcatA(keypath, prod_squashed); + lstrcatA(keypath, "\\Features"); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* userdata features key exists */ + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)"aaaaaaaaaaaaaaaaaaa", 20); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_BADCONFIG, "Expected INSTALLSTATE_BADCONFIG, got %d\n", state); + + res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)"aaaaaaaaaaaaaaaaaaaa", 21); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)"aaaaaaaaaaaaaaaaaaaaa", 22); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)comp_base85, 21); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\"); + lstrcatA(keypath, "S-1-5-18\\Components\\"); + lstrcatA(keypath, comp_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &compkey); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state); + + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"", 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"apple", 1); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + state = MsiQueryFeatureStateA(prodcode, "feature"); + ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state); + + RegDeleteValueA(compkey, prod_squashed); + RegDeleteKeyA(compkey, ""); RegDeleteValueA(localkey, "feature"); RegDeleteValueA(userkey, "feature"); RegDeleteKeyA(userkey, ""); @@ -2110,6 +2290,10 @@ static void test_MsiGetFileVersion(void) ok(!lstrcmpA(lang, langcheck), "Expected %s, got %s\n", langcheck, lang); ok(langsz == langchecksz, "Expected %d, got %d\n", langchecksz, langsz); + /* check neither version nor language */ + r = MsiGetFileVersionA(path, NULL, NULL, NULL, NULL); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + /* get pcchVersionBuf */ versz = MAX_PATH; r = MsiGetFileVersionA(path, NULL, &versz, NULL, NULL); @@ -6138,6 +6322,585 @@ static void test_MsiGetProductInfoEx(void) RegCloseKey(prodkey); } +#define INIT_USERINFO() \ + lstrcpyA(user, "apple"); \ + lstrcpyA(org, "orange"); \ + lstrcpyA(serial, "banana"); \ + usersz = orgsz = serialsz = MAX_PATH; + +static void test_MsiGetUserInfo(void) +{ + USERINFOSTATE state; + CHAR user[MAX_PATH]; + CHAR org[MAX_PATH]; + CHAR serial[MAX_PATH]; + DWORD usersz, orgsz, serialsz; + CHAR keypath[MAX_PATH * 2]; + CHAR prodcode[MAX_PATH]; + CHAR prod_squashed[MAX_PATH]; + HKEY prodkey, userprod, props; + LPSTR usersid; + LONG res; + + create_test_guid(prodcode, prod_squashed); + get_user_sid(&usersid); + + /* NULL szProduct */ + INIT_USERINFO(); + state = MsiGetUserInfoA(NULL, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_INVALIDARG, + "Expected USERINFOSTATE_INVALIDARG, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* empty szProductCode */ + INIT_USERINFO(); + state = MsiGetUserInfoA("", user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_INVALIDARG, + "Expected USERINFOSTATE_INVALIDARG, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* garbage szProductCode */ + INIT_USERINFO(); + state = MsiGetUserInfoA("garbage", user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_INVALIDARG, + "Expected USERINFOSTATE_INVALIDARG, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* guid without brackets */ + INIT_USERINFO(); + state = MsiGetUserInfoA("6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D", + user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_INVALIDARG, + "Expected USERINFOSTATE_INVALIDARG, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* guid with brackets */ + INIT_USERINFO(); + state = MsiGetUserInfoA("{6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D}", + user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_UNKNOWN, + "Expected USERINFOSTATE_UNKNOWN, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* NULL lpUserNameBuf */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, NULL, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_UNKNOWN, + "Expected USERINFOSTATE_UNKNOWN, got %d\n", state); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* NULL pcchUserNameBuf */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, NULL, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_INVALIDARG, + "Expected USERINFOSTATE_INVALIDARG, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* both lpUserNameBuf and pcchUserNameBuf NULL */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, NULL, NULL, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_UNKNOWN, + "Expected USERINFOSTATE_UNKNOWN, got %d\n", state); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* NULL lpOrgNameBuf */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, NULL, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_UNKNOWN, + "Expected USERINFOSTATE_UNKNOWN, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* NULL pcchOrgNameBuf */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, NULL, serial, &serialsz); + ok(state == USERINFOSTATE_INVALIDARG, + "Expected USERINFOSTATE_INVALIDARG, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* both lpOrgNameBuf and pcchOrgNameBuf NULL */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, NULL, NULL, serial, &serialsz); + ok(state == USERINFOSTATE_UNKNOWN, + "Expected USERINFOSTATE_UNKNOWN, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* NULL lpSerialBuf */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, NULL, &serialsz); + ok(state == USERINFOSTATE_UNKNOWN, + "Expected USERINFOSTATE_UNKNOWN, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* NULL pcchSerialBuf */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, NULL); + ok(state == USERINFOSTATE_INVALIDARG, + "Expected USERINFOSTATE_INVALIDARG, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + + /* both lpSerialBuf and pcchSerialBuf NULL */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, NULL, NULL); + ok(state == USERINFOSTATE_UNKNOWN, + "Expected USERINFOSTATE_UNKNOWN, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + + /* MSIINSTALLCONTEXT_USERMANAGED */ + + /* create local system product key */ + 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 key exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\"); + lstrcatA(keypath, "Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userprod); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegCreateKeyA(userprod, "InstallProperties", &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* RegOwner doesn't exist, lpUserNameBuf and pcchUserNameBuf are NULL */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, NULL, NULL, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(org, ""), "Expected empty string, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(orgsz == 0, "Expected 0, got %d\n", orgsz); + ok(serialsz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", serialsz); + + /* RegOwner, RegCompany don't exist, out params are NULL */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, NULL, NULL, NULL, NULL, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(serialsz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", serialsz); + + res = RegSetValueExA(props, "RegOwner", 0, REG_SZ, (LPBYTE)"owner", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegOwner value exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(user, "owner"), "Expected \"owner\", got \"%s\"\n", user); + ok(!lstrcmpA(org, ""), "Expected empty string, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == 5, "Expected 5, got %d\n", usersz); + ok(orgsz == 0, "Expected 0, got %d\n", orgsz); + ok(serialsz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", serialsz); + + res = RegSetValueExA(props, "RegCompany", 0, REG_SZ, (LPBYTE)"company", 8); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegCompany value exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(user, "owner"), "Expected \"owner\", got \"%s\"\n", user); + ok(!lstrcmpA(org, "company"), "Expected \"company\", got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == 5, "Expected 5, got %d\n", usersz); + ok(orgsz == 7, "Expected 7, got %d\n", orgsz); + ok(serialsz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", serialsz); + + res = RegSetValueExA(props, "ProductID", 0, REG_SZ, (LPBYTE)"ID", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductID value exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_PRESENT, + "Expected USERINFOSTATE_PRESENT, got %d\n", state); + ok(!lstrcmpA(user, "owner"), "Expected \"owner\", got \"%s\"\n", user); + ok(!lstrcmpA(org, "company"), "Expected \"company\", got \"%s\"\n", org); + ok(!lstrcmpA(serial, "ID"), "Expected \"ID\", got \"%s\"\n", serial); + ok(usersz == 5, "Expected 5, got %d\n", usersz); + ok(orgsz == 7, "Expected 7, got %d\n", orgsz); + ok(serialsz == 2, "Expected 2, got %d\n", serialsz); + + /* pcchUserNameBuf is too small */ + INIT_USERINFO(); + usersz = 0; + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_MOREDATA, + "Expected USERINFOSTATE_MOREDATA, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == 5, "Expected 5, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* pcchUserNameBuf has no room for NULL terminator */ + INIT_USERINFO(); + usersz = 5; + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_MOREDATA, + "Expected USERINFOSTATE_MOREDATA, got %d\n", state); + todo_wine + { + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + } + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == 5, "Expected 5, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* pcchUserNameBuf is too small, lpUserNameBuf is NULL */ + INIT_USERINFO(); + usersz = 0; + state = MsiGetUserInfoA(prodcode, NULL, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_PRESENT, + "Expected USERINFOSTATE_PRESENT, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "company"), "Expected \"company\", got \"%s\"\n", org); + ok(!lstrcmpA(serial, "ID"), "Expected \"ID\", got \"%s\"\n", serial); + ok(usersz == 5, "Expected 5, got %d\n", usersz); + ok(orgsz == 7, "Expected 7, got %d\n", orgsz); + ok(serialsz == 2, "Expected 2, got %d\n", serialsz); + + RegDeleteValueA(props, "ProductID"); + RegDeleteValueA(props, "RegCompany"); + RegDeleteValueA(props, "RegOwner"); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + RegDeleteKeyA(userprod, ""); + RegCloseKey(userprod); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + /* MSIINSTALLCONTEXT_USERUNMANAGED */ + + /* create local system product key */ + 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); + + /* product key exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\"); + lstrcatA(keypath, "Installer\\UserData\\"); + lstrcatA(keypath, usersid); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userprod); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegCreateKeyA(userprod, "InstallProperties", &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* RegOwner doesn't exist, lpUserNameBuf and pcchUserNameBuf are NULL */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, NULL, NULL, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(org, ""), "Expected empty string, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(orgsz == 0, "Expected 0, got %d\n", orgsz); + ok(serialsz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", serialsz); + + /* RegOwner, RegCompany don't exist, out params are NULL */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, NULL, NULL, NULL, NULL, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(serialsz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", serialsz); + + res = RegSetValueExA(props, "RegOwner", 0, REG_SZ, (LPBYTE)"owner", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegOwner value exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(user, "owner"), "Expected \"owner\", got \"%s\"\n", user); + ok(!lstrcmpA(org, ""), "Expected empty string, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == 5, "Expected 5, got %d\n", usersz); + ok(orgsz == 0, "Expected 0, got %d\n", orgsz); + ok(serialsz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", serialsz); + + res = RegSetValueExA(props, "RegCompany", 0, REG_SZ, (LPBYTE)"company", 8); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegCompany value exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(user, "owner"), "Expected \"owner\", got \"%s\"\n", user); + ok(!lstrcmpA(org, "company"), "Expected \"company\", got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == 5, "Expected 5, got %d\n", usersz); + ok(orgsz == 7, "Expected 7, got %d\n", orgsz); + ok(serialsz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", serialsz); + + res = RegSetValueExA(props, "ProductID", 0, REG_SZ, (LPBYTE)"ID", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductID value exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_PRESENT, + "Expected USERINFOSTATE_PRESENT, got %d\n", state); + ok(!lstrcmpA(user, "owner"), "Expected \"owner\", got \"%s\"\n", user); + ok(!lstrcmpA(org, "company"), "Expected \"company\", got \"%s\"\n", org); + ok(!lstrcmpA(serial, "ID"), "Expected \"ID\", got \"%s\"\n", serial); + ok(usersz == 5, "Expected 5, got %d\n", usersz); + ok(orgsz == 7, "Expected 7, got %d\n", orgsz); + ok(serialsz == 2, "Expected 2, got %d\n", serialsz); + + RegDeleteValueA(props, "ProductID"); + RegDeleteValueA(props, "RegCompany"); + RegDeleteValueA(props, "RegOwner"); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + RegDeleteKeyA(userprod, ""); + RegCloseKey(userprod); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); + + /* MSIINSTALLCONTEXT_MACHINE */ + + /* create local system product key */ + 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); + + /* product key exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH, "Expected MAX_PATH, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\"); + lstrcatA(keypath, "Installer\\UserData\\S-1-5-18"); + lstrcatA(keypath, "\\Products\\"); + lstrcatA(keypath, prod_squashed); + + res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &userprod); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + res = RegCreateKeyA(userprod, "InstallProperties", &props); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* InstallProperties key exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(user, "apple"), "Expected user to be unchanged, got \"%s\"\n", user); + ok(!lstrcmpA(org, "orange"), "Expected org to be unchanged, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", usersz); + ok(orgsz == MAX_PATH, "Expected MAX_PATH, got %d\n", orgsz); + ok(serialsz == MAX_PATH, "Expected MAX_PATH, got %d\n", serialsz); + + /* RegOwner doesn't exist, lpUserNameBuf and pcchUserNameBuf are NULL */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, NULL, NULL, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(org, ""), "Expected empty string, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(orgsz == 0, "Expected 0, got %d\n", orgsz); + ok(serialsz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", serialsz); + + /* RegOwner, RegCompany don't exist, out params are NULL */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, NULL, NULL, NULL, NULL, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(serialsz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", serialsz); + + res = RegSetValueExA(props, "RegOwner", 0, REG_SZ, (LPBYTE)"owner", 6); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegOwner value exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(user, "owner"), "Expected \"owner\", got \"%s\"\n", user); + ok(!lstrcmpA(org, ""), "Expected empty string, got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == 5, "Expected 5, got %d\n", usersz); + ok(orgsz == 0, "Expected 0, got %d\n", orgsz); + ok(serialsz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", serialsz); + + res = RegSetValueExA(props, "RegCompany", 0, REG_SZ, (LPBYTE)"company", 8); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* RegCompany value exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_ABSENT, + "Expected USERINFOSTATE_ABSENT, got %d\n", state); + ok(!lstrcmpA(user, "owner"), "Expected \"owner\", got \"%s\"\n", user); + ok(!lstrcmpA(org, "company"), "Expected \"company\", got \"%s\"\n", org); + ok(!lstrcmpA(serial, "banana"), "Expected serial to be unchanged, got \"%s\"\n", serial); + ok(usersz == 5, "Expected 5, got %d\n", usersz); + ok(orgsz == 7, "Expected 7, got %d\n", orgsz); + ok(serialsz == MAX_PATH - 1, "Expected MAX_PATH - 1, got %d\n", serialsz); + + res = RegSetValueExA(props, "ProductID", 0, REG_SZ, (LPBYTE)"ID", 3); + ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); + + /* ProductID value exists */ + INIT_USERINFO(); + state = MsiGetUserInfoA(prodcode, user, &usersz, org, &orgsz, serial, &serialsz); + ok(state == USERINFOSTATE_PRESENT, + "Expected USERINFOSTATE_PRESENT, got %d\n", state); + ok(!lstrcmpA(user, "owner"), "Expected \"owner\", got \"%s\"\n", user); + ok(!lstrcmpA(org, "company"), "Expected \"company\", got \"%s\"\n", org); + ok(!lstrcmpA(serial, "ID"), "Expected \"ID\", got \"%s\"\n", serial); + ok(usersz == 5, "Expected 5, got %d\n", usersz); + ok(orgsz == 7, "Expected 7, got %d\n", orgsz); + ok(serialsz == 2, "Expected 2, got %d\n", serialsz); + + RegDeleteValueA(props, "ProductID"); + RegDeleteValueA(props, "RegCompany"); + RegDeleteValueA(props, "RegOwner"); + RegDeleteKeyA(props, ""); + RegCloseKey(props); + RegDeleteKeyA(userprod, ""); + RegCloseKey(userprod); + RegDeleteKeyA(prodkey, ""); + RegCloseKey(prodkey); +} + START_TEST(msi) { init_functionpointers(); @@ -6160,6 +6923,7 @@ START_TEST(msi) test_MsiEnumClients(); test_MsiGetProductInfo(); test_MsiGetProductInfoEx(); + test_MsiGetUserInfo(); } test_MsiGetFileVersion(); diff --git a/rostests/winetests/msi/source.c b/rostests/winetests/msi/source.c index 4d2cbbdd628..148ea40382c 100644 --- a/rostests/winetests/msi/source.c +++ b/rostests/winetests/msi/source.c @@ -2319,6 +2319,8 @@ static void test_MsiSourceListEnumMediaDisks(void) /* GetLastError is not set by the function */ /* NULL szProductCodeOrPatchCode */ + labelsz = sizeof(label); + promptsz = sizeof(prompt); r = pMsiSourceListEnumMediaDisksA(NULL, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, 0, &id, label, &labelsz, prompt, &promptsz); @@ -2326,6 +2328,8 @@ static void test_MsiSourceListEnumMediaDisks(void) "Expected ERROR_INVALID_PARAMETER, got %d\n", r); /* empty szProductCodeOrPatchCode */ + labelsz = sizeof(label); + promptsz = sizeof(prompt); r = pMsiSourceListEnumMediaDisksA("", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, 0, &id, label, &labelsz, prompt, &promptsz); @@ -2333,6 +2337,8 @@ static void test_MsiSourceListEnumMediaDisks(void) "Expected ERROR_INVALID_PARAMETER, got %d\n", r); /* garbage szProductCodeOrPatchCode */ + labelsz = sizeof(label); + promptsz = sizeof(prompt); r = pMsiSourceListEnumMediaDisksA("garbage", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, 0, &id, label, &labelsz, prompt, &promptsz); @@ -2340,6 +2346,8 @@ static void test_MsiSourceListEnumMediaDisks(void) "Expected ERROR_INVALID_PARAMETER, got %d\n", r); /* guid without brackets */ + labelsz = sizeof(label); + promptsz = sizeof(prompt); r = pMsiSourceListEnumMediaDisksA("51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, 0, &id, label, &labelsz, @@ -2348,6 +2356,8 @@ static void test_MsiSourceListEnumMediaDisks(void) "Expected ERROR_INVALID_PARAMETER, got %d\n", r); /* guid with brackets */ + labelsz = sizeof(label); + promptsz = sizeof(prompt); r = pMsiSourceListEnumMediaDisksA("{51CD2AD5-0482-4C46-8DDD-0ED1022AA1AA}", usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, 0, &id, label, &labelsz, @@ -2356,6 +2366,8 @@ static void test_MsiSourceListEnumMediaDisks(void) "Expected ERROR_UNKNOWN_PRODUCT, got %d\n", r); /* dwOptions has MSISOURCETYPE_NETWORK */ + labelsz = sizeof(label); + promptsz = sizeof(prompt); r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT | MSISOURCETYPE_NETWORK, 0, &id, label, &labelsz, @@ -2364,6 +2376,8 @@ static void test_MsiSourceListEnumMediaDisks(void) "Expected ERROR_INVALID_PARAMETER, got %d\n", r); /* dwOptions has MSISOURCETYPE_URL */ + labelsz = sizeof(label); + promptsz = sizeof(prompt); r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT | MSISOURCETYPE_URL, 0, &id, label, &labelsz, @@ -2372,6 +2386,8 @@ static void test_MsiSourceListEnumMediaDisks(void) "Expected ERROR_INVALID_PARAMETER, got %d\n", r); /* dwIndex is non-zero */ + labelsz = sizeof(label); + promptsz = sizeof(prompt); r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, 1, &id, label, &labelsz, prompt, &promptsz); @@ -2387,6 +2403,8 @@ static void test_MsiSourceListEnumMediaDisks(void) ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); /* user product key exists */ + labelsz = sizeof(label); + promptsz = sizeof(prompt); r = pMsiSourceListEnumMediaDisksA(prodcode, usersid, MSIINSTALLCONTEXT_USERUNMANAGED, MSICODE_PRODUCT, 0, &id, label, &labelsz, prompt, &promptsz); diff --git a/rostests/winetests/netapi32/access.c b/rostests/winetests/netapi32/access.c index b1036a9d787..f46cb7faf00 100644 --- a/rostests/winetests/netapi32/access.c +++ b/rostests/winetests/netapi32/access.c @@ -51,7 +51,6 @@ static WCHAR sTooLongPassword[] = {'a','b','c','d','e','f','g','h','a','b','c',' static WCHAR sTestUserName[] = {'t', 'e', 's', 't', 'u', 's', 'e', 'r', 0}; static WCHAR sTestUserOldPass[] = {'O', 'l', 'd', 'P', 'a', 's', 's', 'W', '0', 'r', 'd', 'S', 'e', 't', '!', '~', 0}; -static WCHAR sTestUserNewPass[] = {'N', 'e', 'w', 'P', 'a', 's', 's', 'W', '0', 'r', 'd', 'S', 'e', 't', '!', '~', 0}; static const WCHAR sBadNetPath[] = {'\\','\\','B','a',' ',' ','p','a','t','h',0}; static const WCHAR sInvalidName[] = {'\\',0}; static const WCHAR sInvalidName2[] = {'\\','\\',0}; @@ -63,7 +62,6 @@ static NET_API_STATUS (WINAPI *pNetQueryDisplayInformation)(LPWSTR,DWORD,DWORD,D static NET_API_STATUS (WINAPI *pNetUserGetInfo)(LPCWSTR,LPCWSTR,DWORD,LPBYTE*)=NULL; static NET_API_STATUS (WINAPI *pNetUserModalsGet)(LPCWSTR,DWORD,LPBYTE*)=NULL; static NET_API_STATUS (WINAPI *pNetUserAdd)(LPCWSTR,DWORD,LPBYTE,LPDWORD)=NULL; -static NET_API_STATUS (WINAPI *pNetUserChangePassword)(LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR)=NULL; static NET_API_STATUS (WINAPI *pNetUserDel)(LPCWSTR,LPCWSTR)=NULL; static int init_access_tests(void) @@ -144,6 +142,11 @@ static void run_usergetinfo_tests(void) pNetApiBufferFree(ui0); pNetApiBufferFree(ui10); + /* NetUserGetInfo should always work for the current user. */ + rc=pNetUserGetInfo(NULL, user_name, 0, (LPBYTE*)&ui0); + ok(rc == NERR_Success, "NetUsetGetInfo for current user failed: 0x%08x.\n", rc); + pNetApiBufferFree(ui0); + /* errors handling */ rc=pNetUserGetInfo(NULL, sTestUserName, 10000, (LPBYTE *)&ui0); ok(rc == ERROR_INVALID_LEVEL,"Invalid Level: rc=%d\n",rc); @@ -294,32 +297,13 @@ static void run_userhandling_tests(void) if(ret != NERR_Success) return; - ret = pNetUserChangePassword(NULL, sNonexistentUser, sTestUserOldPass, - sTestUserNewPass); - ok(ret == NERR_UserNotFound || ret == ERROR_INVALID_PASSWORD, - "Changing password for nonexistent user returned 0x%08x.\n", ret); - - ret = pNetUserChangePassword(NULL, sTestUserName, sTestUserOldPass, - sTestUserOldPass); - /* Apparently NERR_PasswordTooShort can be returned on windows xp if a - * strict password policy is enforced + /* On Windows XP (and newer), calling NetUserChangePassword with a NULL + * domainname parameter creates a user home directory, iff the machine is + * not member of a domain. + * Using \\127.0.0.1 as domain name does not work on standalone machines + * either, unless the ForceGuest option in the registry is turned off. + * So let's not test NetUserChangePassword for now. */ - ok(ret == NERR_Success || ret == NERR_PasswordTooShort, - "Changing old password to old password returned 0x%08x.\n", ret); - - ret = pNetUserChangePassword(NULL, sTestUserName, sTestUserNewPass, - sTestUserOldPass); - ok(ret == ERROR_INVALID_PASSWORD, - "Trying to change password giving an invalid password returned 0x%08x.\n", ret); - - ret = pNetUserChangePassword(NULL, sTestUserName, sTestUserOldPass, - sTooLongPassword); - ok(ret == ERROR_PASSWORD_RESTRICTION, - "Changing to a password that's too long returned 0x%08x.\n", ret); - - ret = pNetUserChangePassword(NULL, sTestUserName, sTestUserOldPass, - sTestUserNewPass); - ok(ret == NERR_Success, "Changing the password correctly returned 0x%08x.\n", ret); ret = pNetUserDel(NULL, sTestUserName); ok(ret == NERR_Success, "Deleting the user failed.\n"); @@ -338,7 +322,6 @@ START_TEST(access) pNetUserGetInfo=(void*)GetProcAddress(hnetapi32,"NetUserGetInfo"); pNetUserModalsGet=(void*)GetProcAddress(hnetapi32,"NetUserModalsGet"); pNetUserAdd=(void*)GetProcAddress(hnetapi32, "NetUserAdd"); - pNetUserChangePassword=(void*)GetProcAddress(hnetapi32, "NetUserChangePassword"); pNetUserDel=(void*)GetProcAddress(hnetapi32, "NetUserDel"); /* These functions were introduced with NT. It's safe to assume that diff --git a/rostests/winetests/netapi32/apibuf.c b/rostests/winetests/netapi32/apibuf.c index 920be6ae05e..5589c1819d6 100644 --- a/rostests/winetests/netapi32/apibuf.c +++ b/rostests/winetests/netapi32/apibuf.c @@ -54,9 +54,6 @@ static void run_apibuf_tests(void) ok(pNetApiBufferFree(p) == NERR_Success, "Freed\n"); - /* test errors handling */ - ok(pNetApiBufferFree(p) == NERR_Success, "Freed\n"); - ok(pNetApiBufferSize(p, &dwSize) == NERR_Success, "Got size\n"); ok(pNetApiBufferSize(NULL, &dwSize) == ERROR_INVALID_PARAMETER, "Error for NULL pointer\n"); diff --git a/rostests/winetests/netapi32/ds.c b/rostests/winetests/netapi32/ds.c index 91119155046..277a589b8ca 100644 --- a/rostests/winetests/netapi32/ds.c +++ b/rostests/winetests/netapi32/ds.c @@ -60,17 +60,17 @@ static void test_get(void) SetLastError(0xdeadbeef); ret = pDsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *)&dpdi); ok( ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got (%d)\n", ret); - pDsRoleFreeMemory(&dpdi); + pDsRoleFreeMemory(dpdi); SetLastError(0xdeadbeef); ret = pDsRoleGetPrimaryDomainInformation(NULL, DsRoleUpgradeStatus, (PBYTE *)&dusi); todo_wine { ok( ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got (%d)\n", ret); } - pDsRoleFreeMemory(&dusi); + pDsRoleFreeMemory(dusi); SetLastError(0xdeadbeef); ret = pDsRoleGetPrimaryDomainInformation(NULL, DsRoleOperationState, (PBYTE *)&dosi); todo_wine { ok( ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got (%d)\n", ret); } - pDsRoleFreeMemory(&dosi); + pDsRoleFreeMemory(dosi); } diff --git a/rostests/winetests/netapi32/wksta.c b/rostests/winetests/netapi32/wksta.c index 01d0d6f7f38..b4994f8a2d3 100644 --- a/rostests/winetests/netapi32/wksta.c +++ b/rostests/winetests/netapi32/wksta.c @@ -83,7 +83,7 @@ static void run_wkstausergetinfo_tests(void) "NetWkstaUserGetInfo is unsuccessful\n"); ok(ui0 != NULL, "ui0 is NULL\n"); - /* This failure occured when I ran sshd as service and didn't authenticate + /* This failure occurred when I ran sshd as service and didn't authenticate * Since the test dereferences ui0, the rest of this test is worthless */ if (!ui0) diff --git a/rostests/winetests/ole32/clipboard.c b/rostests/winetests/ole32/clipboard.c index e365ee8fc69..26278b6417c 100644 --- a/rostests/winetests/ole32/clipboard.c +++ b/rostests/winetests/ole32/clipboard.c @@ -436,7 +436,10 @@ static void test_set_clipboard(void) CoInitialize(NULL); hr = OleSetClipboard(data1); todo_wine - ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr); + ok(hr == CO_E_NOTINITIALIZED || + hr == CLIPBRD_E_CANT_SET, /* win9x */ + "OleSetClipboard should have failed with " + "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr); CoUninitialize(); hr = OleInitialize(NULL); diff --git a/rostests/winetests/ole32/compobj.c b/rostests/winetests/ole32/compobj.c index 89cf9b9d891..b2aaa226eb5 100644 --- a/rostests/winetests/ole32/compobj.c +++ b/rostests/winetests/ole32/compobj.c @@ -197,6 +197,27 @@ static void test_CLSIDFromString(void) ok(IsEqualCLSID(&clsid, &CLSID_NULL), "clsid wasn't equal to CLSID_NULL\n"); } +static void test_StringFromGUID2(void) +{ + WCHAR str[50]; + int len; + /* Test corner cases for buffer size */ + len = StringFromGUID2(&CLSID_CDeviceMoniker,str,50); + ok(len == 39, "len: %d (expected 39)\n", len); + ok(!lstrcmpiW(str, wszCLSID_CDeviceMoniker),"string wan't equal for CLSID_CDeviceMoniker\n"); + + memset(str,0,sizeof str); + len = StringFromGUID2(&CLSID_CDeviceMoniker,str,39); + ok(len == 39, "len: %d (expected 39)\n", len); + ok(!lstrcmpiW(str, wszCLSID_CDeviceMoniker),"string wan't equal for CLSID_CDeviceMoniker\n"); + + len = StringFromGUID2(&CLSID_CDeviceMoniker,str,38); + ok(len == 0, "len: %d (expected 0)\n", len); + + len = StringFromGUID2(&CLSID_CDeviceMoniker,str,30); + ok(len == 0, "len: %d (expected 0)\n", len); +} + static void test_CoCreateInstance(void) { REFCLSID rclsid = &CLSID_MyComputer; @@ -208,7 +229,7 @@ static void test_CoCreateInstance(void) OleInitialize(NULL); hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk); ok_ole_success(hr, "CoCreateInstance"); - IUnknown_Release(pUnk); + if(pUnk) IUnknown_Release(pUnk); OleUninitialize(); hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk); @@ -923,7 +944,9 @@ static void test_CoFreeUnusedLibraries(void) ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n"); - IUnknown_Release(pUnk); + ok(pUnk != NULL, "Expected a valid pointer\n"); + if (pUnk) + IUnknown_Release(pUnk); ok(is_module_loaded("urlmon.dll"), "urlmon.dll should be loaded\n"); @@ -1008,6 +1031,7 @@ START_TEST(compobj) test_ProgIDFromCLSID(); test_CLSIDFromProgID(); test_CLSIDFromString(); + test_StringFromGUID2(); test_CoCreateInstance(); test_ole_menu(); test_CoGetClassObject(); diff --git a/rostests/winetests/ole32/ole2.c b/rostests/winetests/ole32/ole2.c index 88b58e7c50a..8d72b153317 100644 --- a/rostests/winetests/ole32/ole2.c +++ b/rostests/winetests/ole32/ole2.c @@ -783,7 +783,8 @@ static void test_OleCreate(IStorage *pStorage) trace("OleCreate with OLERENDER_FORMAT:\n"); hr = OleCreate(&CLSID_Equation3, &IID_IOleObject, OLERENDER_FORMAT, &formatetc, (IOleClientSite *)0xdeadbeef, pStorage, (void **)&pObject); ok_ole_success(hr, "OleCreate"); - IOleObject_Release(pObject); + if (pObject) + IOleObject_Release(pObject); ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); expected_method_list = methods_olerender_asis; @@ -839,7 +840,8 @@ static void test_OleLoad(IStorage *pStorage) trace("OleLoad:\n"); hr = OleLoad(pStorage, &IID_IOleObject, (IOleClientSite *)0xdeadbeef, (void **)&pObject); ok_ole_success(hr, "OleLoad"); - IOleObject_Release(pObject); + if (pObject) + IOleObject_Release(pObject); ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); } @@ -1128,11 +1130,19 @@ static void test_data_cache(void) hr = IOleCache_Uncache(pOleCache, 0xdeadbeef); ok(hr == OLE_E_NOCONNECTION, "IOleCache_Uncache with invalid value should return OLE_E_NOCONNECTION instead of 0x%x\n", hr); - hr = IOleCache_Cache(pOleCache, NULL, 0, &dwConnection); - ok(hr == E_INVALIDARG, "IOleCache_Cache with NULL fmtetc should have returned E_INVALIDARG instead of 0x%08x\n", hr); + /* Both tests crash on NT4 and below. StgCreatePropSetStg is only available on w2k and above. */ + if (GetProcAddress(GetModuleHandleA("ole32.dll"), "StgCreatePropSetStg")) + { + hr = IOleCache_Cache(pOleCache, NULL, 0, &dwConnection); + ok(hr == E_INVALIDARG, "IOleCache_Cache with NULL fmtetc should have returned E_INVALIDARG instead of 0x%08x\n", hr); - hr = IOleCache_Cache(pOleCache, NULL, 0, NULL); - ok(hr == E_INVALIDARG, "IOleCache_Cache with NULL pdwConnection should have returned E_INVALIDARG instead of 0x%08x\n", hr); + hr = IOleCache_Cache(pOleCache, NULL, 0, NULL); + ok(hr == E_INVALIDARG, "IOleCache_Cache with NULL pdwConnection should have returned E_INVALIDARG instead of 0x%08x\n", hr); + } + else + { + skip("tests with NULL parameters will crash on NT4 and below\n"); + } for (fmtetc.cfFormat = CF_TEXT; fmtetc.cfFormat < CF_MAX; fmtetc.cfFormat++) { diff --git a/rostests/winetests/oleaut32/oleaut32.rbuild b/rostests/winetests/oleaut32/oleaut32.rbuild index fa9161f2521..f03c556d3c4 100644 --- a/rostests/winetests/oleaut32/oleaut32.rbuild +++ b/rostests/winetests/oleaut32/oleaut32.rbuild @@ -1,7 +1,7 @@ - + . 0x600 0x600 diff --git a/rostests/winetests/rsaenh/rsaenh.c b/rostests/winetests/rsaenh/rsaenh.c index 0119f287a57..479b4286d46 100644 --- a/rostests/winetests/rsaenh/rsaenh.c +++ b/rostests/winetests/rsaenh/rsaenh.c @@ -1775,12 +1775,12 @@ static void test_null_provider(void) ok(!result && GetLastError() == NTE_BAD_PROV_TYPE, "Expected NTE_BAD_PROV_TYPE, got %08x\n", GetLastError()); result = CryptAcquireContext(NULL, szContainer, NULL, PROV_RSA_FULL, 0); - ok(!result && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + ok(!result && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == NTE_BAD_KEYSET), + "Expected ERROR_INVALID_PARAMETER or NTE_BAD_KEYSET, got %08x\n", GetLastError()); result = CryptAcquireContext(NULL, szContainer, NULL, PROV_RSA_FULL, CRYPT_DELETEKEYSET); - ok(!result && GetLastError() == ERROR_INVALID_PARAMETER, - "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError()); + ok(!result && ( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == NTE_BAD_KEYSET), + "Expected ERROR_INVALID_PARAMETER or NTE_BAD_KEYSET, got %08x\n", GetLastError()); result = CryptAcquireContext(&prov, szContainer, NULL, PROV_RSA_FULL, CRYPT_DELETEKEYSET); ok(!result && GetLastError() == NTE_BAD_KEYSET,