static void test_customdraw(void) { static struct { LRESULT FirstReturnValue; int ExpectedCalls; } expectedResults[] = { /* Valid notification responses */ {CDRF_DODEFAULT, TEST_CDDS_PREPAINT}, {CDRF_SKIPDEFAULT, TEST_CDDS_PREPAINT}, {CDRF_NOTIFYPOSTPAINT, TEST_CDDS_PREPAINT | TEST_CDDS_POSTPAINT}, /* Invalid notification responses */ {CDRF_NOTIFYITEMDRAW, TEST_CDDS_PREPAINT}, {CDRF_NOTIFYPOSTERASE, TEST_CDDS_PREPAINT}, {CDRF_NEWFONT, TEST_CDDS_PREPAINT} }; DWORD iterationNumber; WNDCLASSA wc; LRESULT lResult; /* Create a class to use the custom draw wndproc */ wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = GetModuleHandleA(NULL); wc.hIcon = NULL; wc.hCursor = LoadCursorA(NULL, IDC_ARROW); wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); wc.lpszMenuName = NULL; wc.lpszClassName = "CustomDrawClass"; wc.lpfnWndProc = CustomDrawWndProc; RegisterClass(&wc); for (iterationNumber = 0; iterationNumber < sizeof(expectedResults)/sizeof(expectedResults[0]); iterationNumber++) { HWND parent, hwndTip; RECT rect; TOOLINFO toolInfo = { 0 }; /* Create a main window */ parent = CreateWindowEx(0, "CustomDrawClass", NULL, WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE, 50, 50, 300, 300, NULL, NULL, NULL, 0); ok(parent != NULL, "Creation of main window failed\n"); /* Make it show */ ShowWindow(parent, SW_SHOWNORMAL); flush_events(100); /* Create Tooltip */ hwndTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, parent, NULL, GetModuleHandleA(NULL), 0); ok(hwndTip != NULL, "Creation of tooltip window failed\n"); /* Set up parms for the wndproc to handle */ CD_Stages = 0; CD_Result = expectedResults[iterationNumber].FirstReturnValue; g_hwnd = hwndTip; /* Make it topmost, as per the MSDN */ SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); /* Create a tool */ toolInfo.cbSize = TTTOOLINFO_V1_SIZE; toolInfo.hwnd = parent; toolInfo.hinst = GetModuleHandleA(NULL); toolInfo.uFlags = TTF_SUBCLASS; toolInfo.uId = 0x1234ABCD; toolInfo.lpszText = (LPSTR)"This is a test tooltip"; toolInfo.lParam = 0xdeadbeef; GetClientRect (parent, &toolInfo.rect); lResult = SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); ok(lResult, "Adding the tool to the tooltip failed\n"); /* Make tooltip appear quickly */ SendMessage(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0)); /* Put cursor inside window, tooltip will appear immediately */ GetWindowRect( parent, &rect ); SetCursorPos( (rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2 ); flush_events(200); if (CD_Stages) { /* Check CustomDraw results */ ok(CD_Stages == expectedResults[iterationNumber].ExpectedCalls || broken(CD_Stages == (expectedResults[iterationNumber].ExpectedCalls & ~TEST_CDDS_POSTPAINT)), /* nt4 */ "CustomDraw run %d stages %x, expected %x\n", iterationNumber, CD_Stages, expectedResults[iterationNumber].ExpectedCalls); } /* Clean up */ DestroyWindow(hwndTip); DestroyWindow(parent); } }
static void test_PSM_ADDPAGE(void) { HPROPSHEETPAGE hpsp[5]; PROPSHEETPAGEA psp; PROPSHEETHEADERA psh; HWND hdlg, tab; BOOL ret; DWORD r; memset(&psp, 0, sizeof(psp)); psp.dwSize = sizeof(psp); psp.dwFlags = 0; psp.hInstance = GetModuleHandleA(NULL); U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST); U2(psp).pszIcon = NULL; psp.pfnDlgProc = page_dlg_proc_messages; psp.lParam = 0; /* two page with the same data */ hpsp[0] = CreatePropertySheetPageA(&psp); hpsp[1] = CreatePropertySheetPageA(&psp); hpsp[2] = CreatePropertySheetPageA(&psp); U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR); hpsp[3] = CreatePropertySheetPageA(&psp); psp.dwFlags = PSP_PREMATURE; hpsp[4] = CreatePropertySheetPageA(&psp); memset(&psh, 0, sizeof(psh)); psh.dwSize = PROPSHEETHEADERA_V1_SIZE; psh.dwFlags = PSH_MODELESS; psh.pszCaption = "test caption"; psh.nPages = 1; psh.hwndParent = GetDesktopWindow(); U3(psh).phpage = hpsp; hdlg = (HWND)PropertySheetA(&psh); ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg); /* add pages one by one */ ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[1]); ok(ret == TRUE, "got %d\n", ret); /* try with null and invalid value */ ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, 0); ok(ret == FALSE, "got %d\n", ret); if (0) { /* crashes on native */ ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE); } /* check item count */ tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0); r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); ok(r == 2, "got %d\n", r); ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[2]); ok(ret == TRUE, "got %d\n", ret); r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); ok(r == 3, "got %d\n", r); /* add property sheet page that can't be created */ ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[3]); ok(ret == TRUE, "got %d\n", ret); r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); ok(r == 4, "got %d\n", r); /* select page that can't be created */ ret = SendMessageA(hdlg, PSM_SETCURSEL, 3, 1); ok(ret == TRUE, "got %d\n", ret); r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); ok(r == 3, "got %d\n", r); /* test PSP_PREMATURE flag with incorrect property sheet page */ ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[4]); ok(ret == FALSE, "got %d\n", ret); r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); ok(r == 3, "got %d\n", r); DestroyPropertySheetPage(hpsp[4]); DestroyWindow(hdlg); }
static void test_custom_default_button(void) { HWND hdlg, page; PROPSHEETPAGEA psp[1]; PROPSHEETHEADERA psh; MSG msg; LRESULT result; psp[0].dwSize = sizeof (PROPSHEETPAGEA); psp[0].dwFlags = PSP_USETITLE; psp[0].hInstance = GetModuleHandleA(NULL); U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON); U2(psp[0]).pszIcon = NULL; psp[0].pfnDlgProc = page_with_custom_default_button_dlg_proc; psp[0].pszTitle = "Page1"; psp[0].lParam = 0; psh.dwSize = PROPSHEETHEADERA_V1_SIZE; psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS; psh.hwndParent = GetDesktopWindow(); psh.hInstance = GetModuleHandleA(NULL); U(psh).pszIcon = NULL; psh.pszCaption = "PropertySheet1"; psh.nPages = 1; U3(psh).ppsp = psp; U2(psh).nStartPage = 0; /* The goal of the test is to make sure that the Add button is pressed * when the ENTER key is pressed and a different control, a combobox, * has the keyboard focus. */ add_button_has_been_pressed = FALSE; /* Create the modeless property sheet. */ hdlg = (HWND)PropertySheetA(&psh); ok(hdlg != INVALID_HANDLE_VALUE, "Cannot create the property sheet\n"); /* Set the Add button as the default button. */ SendMessageA(hdlg, DM_SETDEFID, (WPARAM)IDC_PS_PUSHBUTTON1, 0); /* Make sure the default button is the Add button. */ result = SendMessageA(hdlg, DM_GETDEFID, 0, 0); ok(DC_HASDEFID == HIWORD(result), "The property sheet does not have a default button\n"); ok(IDC_PS_PUSHBUTTON1 == LOWORD(result), "The default button is not the Add button\n"); /* At this point, the combobox should have keyboard focus, so we press ENTER. * Pull the lever, Kronk! */ page = (HWND)SendMessageW(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0); PostMessageW(GetDlgItem(page, IDC_PS_COMBO1), WM_KEYDOWN, VK_RETURN, 0); /* Process all the messages in the queue for this thread. */ while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) { /* (!PropSheet_IsDialogMessage(hdlg, &msg)) */ if (!((BOOL)SendMessageA(hdlg, PSM_ISDIALOGMESSAGE, 0, (LPARAM)&msg))) { TranslateMessage(&msg); DispatchMessageA(&msg); } } ok(add_button_has_been_pressed, "The Add button has not been pressed!\n"); DestroyWindow(hdlg); }
static void test_wiznavigation(void) { HPROPSHEETPAGE hpsp[4]; PROPSHEETPAGEA psp[4]; PROPSHEETHEADERA psh; HWND hdlg, control; LONG_PTR controlID; DWORD style; LRESULT defidres; BOOL hwndtoindex_supported = TRUE; const INT nextID = 12324; const INT backID = 12323; HHOOK hook; /* set up a hook proc in order to subclass the main dialog early on */ hook = SetWindowsHookExW( WH_CBT, hook_proc, NULL, GetCurrentThreadId() ); /* create the property sheet pages */ memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4); psp[0].dwSize = sizeof(PROPSHEETPAGEA); psp[0].hInstance = GetModuleHandleA(NULL); U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO); psp[0].pfnDlgProc = nav_page_proc; hpsp[0] = CreatePropertySheetPageA(&psp[0]); psp[1].dwSize = sizeof(PROPSHEETPAGEA); psp[1].hInstance = GetModuleHandleA(NULL); U(psp[1]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT); psp[1].pfnDlgProc = nav_page_proc; hpsp[1] = CreatePropertySheetPageA(&psp[1]); psp[2].dwSize = sizeof(PROPSHEETPAGEA); psp[2].hInstance = GetModuleHandleA(NULL); U(psp[2]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO); psp[2].pfnDlgProc = nav_page_proc; hpsp[2] = CreatePropertySheetPageA(&psp[2]); psp[3].dwSize = sizeof(PROPSHEETPAGEA); psp[3].hInstance = GetModuleHandleA(NULL); U(psp[3]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT); psp[3].pfnDlgProc = nav_page_proc; hpsp[3] = CreatePropertySheetPageA(&psp[3]); /* set up the property sheet dialog */ memset(&psh, 0, sizeof(psh)); psh.dwSize = PROPSHEETHEADERA_V1_SIZE; psh.dwFlags = PSH_MODELESS | PSH_WIZARD; psh.pszCaption = "A Wizard"; psh.nPages = 4; psh.hwndParent = GetDesktopWindow(); U3(psh).phpage = hpsp; hdlg = (HWND)PropertySheetA(&psh); ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg); ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page); style = GetWindowLongA(hdlg, GWL_STYLE) & ~(DS_CONTEXTHELP|WS_SYSMENU); ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION| DS_MODALFRAME|DS_SETFONT|DS_3DLOOK), "got unexpected style: %x\n", style); control = GetFocus(); controlID = GetWindowLongPtrA(control, GWLP_ID); ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID); /* simulate pressing the Next button */ SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); if (!active_page) hwndtoindex_supported = FALSE; if (hwndtoindex_supported) ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page); control = GetFocus(); controlID = GetWindowLongPtrA(control, GWLP_ID); ok(controlID == IDC_PS_EDIT1, "Focus should be set to the first item on the second page. Expected: %d, Found: %ld\n", IDC_PS_EDIT1, controlID); defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0); ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres)); /* set the focus to the second edit box on this page */ SetFocus(GetNextDlgTabItem(hdlg, control, FALSE)); /* press next again */ SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); if (hwndtoindex_supported) ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page); control = GetFocus(); controlID = GetWindowLongPtrA(control, GWLP_ID); ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID); /* back button */ SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0); if (hwndtoindex_supported) ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page); control = GetFocus(); controlID = GetWindowLongPtrA(control, GWLP_ID); ok(controlID == IDC_PS_EDIT1, "Focus should have been set to the first item on second page. Expected: %d, Found %ld\n", IDC_PS_EDIT1, controlID); defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0); ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres)); /* press next twice */ SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); if (hwndtoindex_supported) ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page); SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); if (hwndtoindex_supported) ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page); else active_page = 3; control = GetFocus(); controlID = GetWindowLongPtrA(control, GWLP_ID); ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID); /* try to navigate away, but shouldn't be able to */ SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0); ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page); defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0); ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres)); DestroyWindow(hdlg); UnhookWindowsHookEx( hook ); }
int Inject(HANDLE hProcess, const char *dll_dir, const char *dll_fn, const char *func_name, const void *param, const size_t param_size) { // String constants const char *injectError1Format = "Could not inject %s.\n" "\n" "If you're running Windows Vista or 7, make sure that you have installed the KB2533623 update:\n" "\n" "\thttp://support.microsoft.com/kb/2533623/"; const char *injectError2Format = "Could not load the function: %s"; //------------------------------------------// // Function variables. // //------------------------------------------// // Main DLL we will need to load HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); // Main functions we will need to import. // If [dll_fn] is absolute, LoadLibraryEx() with the LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR // flag is used to guarantee that the injected DLL and its dependencies really // are only loaded from the given directory. Otherwise, LoadLibrary() may load // a possible other DLL with the same name from the directory of [hProcess]. FARPROC getcurrentdirectory = GetProcAddress(kernel32, "GetCurrentDirectoryW"); FARPROC setcurrentdirectory = GetProcAddress(kernel32, "SetCurrentDirectoryW"); FARPROC loadlibrary = GetProcAddress(kernel32, "LoadLibraryW"); FARPROC loadlibraryex = GetProcAddress(kernel32, "LoadLibraryExW"); FARPROC getprocaddress = GetProcAddress(kernel32, "GetProcAddress"); FARPROC exitthread = GetProcAddress(kernel32, "ExitThread"); FARPROC freelibraryandexitthread = GetProcAddress(kernel32, "FreeLibraryAndExitThread"); int have_kb2269637 = GetProcAddress(kernel32, "SetDefaultDllDirectories") != 0; // The workspace we will build the codecave on locally. // workspaceSize gets incremented with the final length of the error strings. size_t workspaceSize = 2048; LPBYTE workspace = NULL; LPBYTE p = NULL; // The memory in the process we write to LPBYTE codecaveAddress = NULL; // Strings we have to write into the process size_t injectError1_len = _scprintf(injectError1Format, dll_fn) + 1; size_t injectError2_len = _scprintf(injectError2Format, func_name) + 1; char *injectError0 = "Error"; VLA(char, injectError1, injectError1_len); VLA(char, injectError2, injectError2_len); char *user32Name = "user32.dll"; char *msgboxName = "MessageBoxW"; // Placeholder addresses to use the strings LPBYTE user32NameAddr = 0; LPBYTE user32Addr = 0; LPBYTE msgboxNameAddr = 0; LPBYTE msgboxAddr = 0; LPBYTE dllAddr = 0; LPBYTE dllDirAddr = 0; LPBYTE dllNameAddr = 0; LPBYTE funcNameAddr = 0; LPBYTE funcParamAddr = 0; LPBYTE error0Addr = 0; LPBYTE error1Addr = 0; LPBYTE error2Addr = 0; // Where the codecave execution should begin at LPTHREAD_START_ROUTINE codecaveExecAddr = 0; // Handle to the thread we create in the process HANDLE hThread = NULL; // Old protection on page we are writing to in the process and the bytes written DWORD oldProtect = 0; DWORD byte_ret = 0; // Return code of injection function DWORD injRet; //------------------------------------------// // Variable initialization. // //------------------------------------------// // This section will cause compiler warnings on VS8, // you can upgrade the functions or ignore them // Build error messages sprintf(injectError1, injectError1Format, dll_fn); sprintf(injectError2, injectError2Format, func_name); workspaceSize += ( strlen(dll_dir) + 1 + strlen(dll_fn) + 1 + strlen(func_name) + 1 + param_size + strlen(injectError1) + 1 + strlen(injectError2) + 1 ) * sizeof(wchar_t); // Create the workspace workspace = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, workspaceSize); p = workspace; // Allocate space for the codecave in the process codecaveAddress = (LPBYTE)VirtualAllocEx(hProcess, 0, workspaceSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // Note there is no error checking done above for any functions that return a pointer/handle. // I could have added them, but it'd just add more messiness to the code and not provide any real // benefit. It's up to you though in your final code if you want it there or not. //------------------------------------------// // Data and string writing. // //------------------------------------------// // Reserve space for the user32 dll address, the MessageBox address, // and the address of the injected DLL's module. user32Addr = (p - workspace) + codecaveAddress; p += sizeof(LPBYTE); msgboxAddr = (p - workspace) + codecaveAddress; p += sizeof(LPBYTE); dllAddr = (p - workspace) + codecaveAddress; p += sizeof(LPBYTE); // User32 Dll Name user32NameAddr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, user32Name); // MessageBox name msgboxNameAddr = (p - workspace) + codecaveAddress; p = memcpy_advance_dst(p, msgboxName, strlen(msgboxName) + 1); // Directory name if(dll_dir) { dllDirAddr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, dll_dir); } // Dll Name dllNameAddr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, dll_fn); // Function Name funcNameAddr = (p - workspace) + codecaveAddress; p = memcpy_advance_dst(p, func_name, strlen(func_name) + 1); // Function Parameter funcParamAddr = (p - workspace) + codecaveAddress; p = memcpy_advance_dst(p, param, param_size); // Error Message 1 error0Addr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, injectError0); // Error Message 2 error1Addr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, injectError1); // Error Message 3 error2Addr = (p - workspace) + codecaveAddress; p = StringToUTF16_advance_dst(p, injectError2); // Pad a few INT3s after string data is written for seperation *p++ = 0xCC; *p++ = 0xCC; *p++ = 0xCC; // Store where the codecave execution should begin codecaveExecAddr = (LPTHREAD_START_ROUTINE)((p - workspace) + codecaveAddress); // For debugging - infinite loop, attach onto process and step over //*p++ = 0xEB; //*p++ = 0xFE; //------------------------------------------// // User32.dll loading. // //------------------------------------------// // User32 DLL Loading // PUSH 0x00000000 - Push the address of the DLL name to use in LoadLibrary *p++ = 0x68; p = ptrcpy_advance_dst(p, user32NameAddr); // MOV EAX, ADDRESS - Move the address of LoadLibrary into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, loadlibrary); // CALL EAX - Call LoadLibrary *p++ = 0xFF; *p++ = 0xD0; // MessageBox Loading // PUSH 0x000000 - Push the address of the function name to load *p++ = 0x68; p = ptrcpy_advance_dst(p, msgboxNameAddr); // Push EAX, module to use in GetProcAddress *p++ = 0x50; // MOV EAX, ADDRESS - Move the address of GetProcAddress into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, getprocaddress); // CALL EAX - Call GetProcAddress *p++ = 0xFF; *p++ = 0xD0; // MOV [ADDRESS], EAX - Save the address to our variable *p++ = 0xA3; p = ptrcpy_advance_dst(p, msgboxAddr); //------------------------------------------// // Injected dll loading. // //------------------------------------------// /* // This is the way the following assembly code would look like in C/C++ // In case the injected DLL depends on other DLLs, // we need to change the current directory to the one given as parameter if(dll_dir) { size_t cur_dir_len = GetCurrentDirectory(0, NULL) + 1; VLA(wchar_t, cur_dir, cur_dir_len); GetCurrentDirectory(cur_dir, cur_dir_len); SetCurrentDirectory(dll_dir); } // Load the injected DLL into this process HMODULE h = LoadLibraryEx(dll_fn, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); if(!h) { MessageBox(0, injectError1, "Error", MB_ICONERROR); ExitThread(1); } if(dll_dir) { SetCurrentDirectory(cur_dir); } // Get the address of the export function FARPROC p = GetProcAddress(h, func_name); if(!p) { MessageBox(0, injectError2, "Error", MB_ICONERROR); FreeLibraryAndExitThread(h, 2); } // So we do not need a function pointer interface __asm call p // Exit the thread so the loader continues ExitThread(0); */ // DLL Loading if(dllDirAddr) { // Registers: // ebp: Base stack frame // esi: GetCurrentDirectory / SetCurrentDirectory // ebx: Current directory of process (on stack) // ecx: byte length of string at ebx // mov ebp, esp - Save stack frame *p++ = 0x89; *p++ = 0xe5; // Get length for current directory // push 0 // push 0 *p++ = 0x6a; *p++ = 0x00; *p++ = 0x6a; *p++ = 0x00; // mov esi, GetCurrentDirectory *p++ = 0xbe; p = ptrcpy_advance_dst(p, getcurrentdirectory); // call esi *p++ = 0xFF; *p++ = 0xD6; /// Calculate byte size of directory buffer. /// Also do some poor man's DWORD boundary alignment /// in order to not f**k up the stack // mov ecx, eax // shl ecx, 1 // and ecx, fffffff8 // add ecx, 4 *p++ = 0x89; *p++ = 0xc1; *p++ = 0xd1; *p++ = 0xe1; *p++ = 0x83; *p++ = 0xe1; *p++ = 0xf8; *p++ = 0x83; *p++ = 0xc1; *p++ = 0x04; /// "Allocate" ecx bytes on stack and store buffer pointer to ebx // sub esp, ecx // mov ebx, esp *p++ = 0x29; *p++ = 0xcc; *p++ = 0x89; *p++ = 0xe3; /// Call GetCurrentDirectory // push ebx // push eax // call esi *p++ = 0x53; *p++ = 0x50; *p++ = 0xff; *p++ = 0xd6; /// PUSH 0x00000000 - Push the address of our directory *p++ = 0x68; p = ptrcpy_advance_dst(p, dllDirAddr); // mov esi, SetCurrentDirectory *p++ = 0xbe; p = ptrcpy_advance_dst(p, setcurrentdirectory); // call esi *p++ = 0xFF; *p++ = 0xD6; } if(PathIsRelativeA(dll_fn) || !have_kb2269637) { // PUSH 0x00 (dwFlags = 0) *p++ = 0x6a; *p++ = 0x00; } else { // PUSH 0x00000900 (dwFlags = LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32) *p++ = 0x68; *p++ = 0x00; *p++ = 0x09; *p++ = 0x00; *p++ = 0x00; } // PUSH 0x00 (hFile = NULL) *p++ = 0x6a; *p++ = 0x00; // PUSH 0x00000000 - Push the address of the DLL name to use in LoadLibraryEx *p++ = 0x68; p = ptrcpy_advance_dst(p, dllNameAddr); // MOV EAX, ADDRESS - Move the address of LoadLibraryEx into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, loadlibraryex); // CALL EAX - Call LoadLibraryEx *p++ = 0xFF; *p++ = 0xD0; // mov edi, eax - Save return value *p++ = 0x89; *p++ = 0xc7; if(dllDirAddr) { /// Reset directory to the original one of the process // push ebx // call esi *p++ = 0x53; *p++ = 0xFF; *p++ = 0xD6; /// Reset stack frame // mov esp, ebp *p++ = 0x89; *p++ = 0xec; } // Error Checking // CMP EDI, 0 *p++ = 0x83; *p++ = 0xFF; *p++ = 0x00; // JNZ EIP + 0x1E to skip over eror code *p++ = 0x75; *p++ = 0x1E; // Error Code 1 // MessageBox // PUSH 0x10 (MB_ICONHAND) *p++ = 0x6A; *p++ = 0x10; // PUSH 0x000000 - Push the address of the MessageBox title *p++ = 0x68; p = ptrcpy_advance_dst(p, error0Addr); // PUSH 0x000000 - Push the address of the MessageBox message *p++ = 0x68; p = ptrcpy_advance_dst(p, error1Addr); // Push 0 *p++ = 0x6A; *p++ = 0x00; // MOV EAX, [ADDRESS] - Move the address of MessageBox into EAX *p++ = 0xA1; p = ptrcpy_advance_dst(p, msgboxAddr); // CALL EAX - Call MessageBoxW *p++ = 0xFF; *p++ = 0xD0; // ExitThread // PUSH 1 *p++ = 0x6A; *p++ = 0x01; // MOV EAX, ADDRESS - Move the address of ExitThread into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, exitthread); // CALL EAX - Call ExitThread *p++ = 0xFF; *p++ = 0xD0; // Now we have the address of the injected DLL, so save the handle // MOV [ADDRESS], EAX - Save the address to our variable *p++ = 0x89; *p++ = 0x3D; p = ptrcpy_advance_dst(p, dllAddr); // Load the initilize function from it // PUSH 0x000000 - Push the address of the function name to load *p++ = 0x68; p = ptrcpy_advance_dst(p, funcNameAddr); // Push EDI - module to use in GetProcAddress *p++ = 0x57; // MOV EAX, ADDRESS - Move the address of GetProcAddress into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, getprocaddress); // CALL EAX - Call GetProcAddress *p++ = 0xFF; *p++ = 0xD0; // Error Checking // CMP EAX, 0 *p++ = 0x83; *p++ = 0xF8; *p++ = 0x00; // JNZ EIP + 0x23 to skip eror code *p++ = 0x75; *p++ = 0x23; // Error Code 2 // MessageBox // PUSH 0x10 (MB_ICONHAND) *p++ = 0x6A; *p++ = 0x10; // PUSH 0x000000 - Push the address of the MessageBox title *p++ = 0x68; p = ptrcpy_advance_dst(p, error0Addr); // PUSH 0x000000 - Push the address of the MessageBox message *p++ = 0x68; p = ptrcpy_advance_dst(p, error2Addr); // Push 0 *p++ = 0x6A; *p++ = 0x00; // MOV EAX, ADDRESS - Move the address of MessageBox into EAX *p++ = 0xA1; p = ptrcpy_advance_dst(p, msgboxAddr); // CALL EAX - Call MessageBoxA *p++ = 0xFF; *p++ = 0xD0; // FreeLibraryAndExitThread // PUSH 2 *p++ = 0x6A; *p++ = 0x02; // PUSH 0x000000 - Push the injected DLL's module handle *p++ = 0x68; p = ptrcpy_advance_dst(p, dllAddr); // MOV EAX, ADDRESS - Move the address of FreeLibraryAndExitThread into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, freelibraryandexitthread); // CALL EAX - Call ExitThread function *p++ = 0xFF; *p++ = 0xD0; // PUSH 0x000000 - Push the address of the function parameter *p++ = 0x68; p = ptrcpy_advance_dst(p, funcParamAddr); // CALL EAX - Call [func_name] *p++ = 0xFF; *p++ = 0xD0; // If we get here, [func_name] has been called, // so it's time to close this thread and optionally unload the DLL. //------------------------------------------// // Exiting from the injected dll. // //------------------------------------------// // Call ExitThread to leave the DLL loaded #if 1 // PUSH 0 (exit code) *p++ = 0x6A; *p++ = 0x00; // MOV EAX, ADDRESS - Move the address of ExitThread into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, exitthread); // CALL EAX - Call ExitThread *p++ = 0xFF; *p++ = 0xD0; #endif // Call FreeLibraryAndExitThread to unload DLL #if 0 // Push 0 (exit code) *p++ = 0x6A; *p++ = 0x00; // PUSH [0x000000] - Push the address of the DLL module to unload *p++ = 0xFF; *p++ = 0x35; p = ptrcpy_advance_dst(p, dllAddr); // MOV EAX, ADDRESS - Move the address of FreeLibraryAndExitThread into EAX *p++ = 0xB8; p = ptrcpy_advance_dst(p, freelibraryandexitthread); // CALL EAX - Call FreeLibraryAndExitThread *p++ = 0xFF; *p++ = 0xD0; #endif //------------------------------------------// // Code injection and cleanup. // //------------------------------------------// // Change page protection so we can write executable code VirtualProtectEx(hProcess, codecaveAddress, p - workspace, PAGE_EXECUTE_READWRITE, &oldProtect); // Write out the patch WriteProcessMemory(hProcess, codecaveAddress, workspace, p - workspace, &byte_ret); // Restore page protection VirtualProtectEx(hProcess, codecaveAddress, p - workspace, oldProtect, &oldProtect); // Make sure our changes are written right away FlushInstructionCache(hProcess, codecaveAddress, p - workspace); // Free the workspace memory HeapFree(GetProcessHeap(), 0, workspace); // Execute the thread now and wait for it to exit, note we execute where the code starts, and not the codecave start // (since we wrote strings at the start of the codecave) hThread = CreateRemoteThread(hProcess, NULL, 0, codecaveExecAddr, 0, 0, NULL); WaitForSingleObject(hThread, INFINITE); GetExitCodeThread(hThread, &injRet); CloseHandle(hThread); // Free the memory in the process that we allocated VirtualFreeEx(hProcess, codecaveAddress, 0, MEM_RELEASE); VLA_FREE(injectError1); VLA_FREE(injectError2); return injRet; }
inline void *get_module_handle(const char *name) { return GetModuleHandleA(name); }
HWND myGetConsoleWindow() { HWND hConWnd = NULL; // If we are in ConEmuHk than gfGetRealConsoleWindow may be set if (gfGetRealConsoleWindow) { hConWnd = gfGetRealConsoleWindow(); // If the function pointer was set - it must be proper function _ASSERTEX(hConWnd==NULL || isConsoleWindow(hConWnd)); return hConWnd; } _ASSERTE(ghWorkingModule != 0); HMODULE hOurModule = (HMODULE)(DWORD_PTR)ghWorkingModule; if (!hConWnd) { if (!hkFunc.isConEmuHk()) { // Must be already called, but JIC hkFunc.Init(L"Unknown", hOurModule); } hConWnd = GetConsoleWindow(); // Current process may be GUI and have no console at all if (!hConWnd) return NULL; // RealConsole handle is stored in the Window DATA if (!hkFunc.isConEmuHk()) { #ifdef _DEBUG wchar_t sClass[64] = L""; GetClassName(hConWnd, sClass, countof(sClass)); #endif // Regardless of GetClassName result, it may be VirtualConsoleClass HWND h = (HWND)GetWindowLongPtr(hConWnd, 0); if (h && IsWindow(h) && isConsoleWindow(h)) { hConWnd = h; } } } return hConWnd; #if 0 // Смысла звать GetProcAddress для "GetConsoleWindow" мало, все равно хукается typedef HWND (APIENTRY *FGetConsoleWindow)(); static FGetConsoleWindow fGetConsoleWindow = NULL; if (!fGetConsoleWindow) { HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); if (hKernel32) { fGetConsoleWindow = (FGetConsoleWindow)GetProcAddress(hKernel32, "GetConsoleWindow"); } } if (fGetConsoleWindow) hConWnd = fGetConsoleWindow(); return hConWnd; #endif }
static void test_ttm_gettoolinfo(void) { TTTOOLINFOA ti; TTTOOLINFOW tiW; HWND hwnd; DWORD r; hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0, 10, 10, 300, 100, NULL, NULL, NULL, 0); ti.cbSize = TTTOOLINFOA_V2_SIZE; ti.hwnd = NULL; ti.hinst = GetModuleHandleA(NULL); ti.uFlags = 0; ti.uId = 0x1234ABCD; ti.lpszText = NULL; ti.lParam = 0x1abe11ed; GetClientRect(hwnd, &ti.rect); r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti); ok(r, "Adding the tool to the tooltip failed\n"); ti.cbSize = TTTOOLINFOA_V2_SIZE; ti.lParam = 0xaaaaaaaa; r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti); ok(r, "Getting tooltip info failed\n"); ok(0x1abe11ed == ti.lParam || broken(0x1abe11ed != ti.lParam), /* comctl32 < 5.81 */ "Expected 0x1abe11ed, got %lx\n", ti.lParam); tiW.cbSize = TTTOOLINFOW_V2_SIZE; tiW.hwnd = NULL; tiW.uId = 0x1234ABCD; tiW.lParam = 0xaaaaaaaa; r = SendMessageA(hwnd, TTM_GETTOOLINFOW, 0, (LPARAM)&tiW); ok(r, "Getting tooltip info failed\n"); ok(0x1abe11ed == tiW.lParam || broken(0x1abe11ed != tiW.lParam), /* comctl32 < 5.81 */ "Expected 0x1abe11ed, got %lx\n", tiW.lParam); ti.cbSize = TTTOOLINFOA_V2_SIZE; ti.uId = 0x1234ABCD; ti.lParam = 0x55555555; SendMessageA(hwnd, TTM_SETTOOLINFOA, 0, (LPARAM)&ti); ti.cbSize = TTTOOLINFOA_V2_SIZE; ti.lParam = 0xdeadbeef; r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti); ok(r, "Getting tooltip info failed\n"); ok(0x55555555 == ti.lParam || broken(0x55555555 != ti.lParam), /* comctl32 < 5.81 */ "Expected 0x55555555, got %lx\n", ti.lParam); DestroyWindow(hwnd); /* 1. test size parameter validation rules (ansi messages) */ hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0, 10, 10, 300, 100, NULL, NULL, NULL, 0); ti.cbSize = TTTOOLINFOA_V1_SIZE - 1; ti.hwnd = NULL; ti.hinst = GetModuleHandleA(NULL); ti.uFlags = 0; ti.uId = 0x1234ABCD; ti.lpszText = NULL; ti.lParam = 0xdeadbeef; GetClientRect(hwnd, &ti.rect); r = SendMessage(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti); ok(r, "Adding the tool to the tooltip failed\n"); r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(1, r); ti.cbSize = TTTOOLINFOA_V1_SIZE - 1; ti.hwnd = NULL; ti.uId = 0x1234ABCD; SendMessage(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti); r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(0, r); ti.cbSize = TTTOOLINFOA_V2_SIZE - 1; ti.hwnd = NULL; ti.hinst = GetModuleHandleA(NULL); ti.uFlags = 0; ti.uId = 0x1234ABCD; ti.lpszText = NULL; ti.lParam = 0xdeadbeef; GetClientRect(hwnd, &ti.rect); r = SendMessage(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti); ok(r, "Adding the tool to the tooltip failed\n"); r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(1, r); ti.cbSize = TTTOOLINFOA_V2_SIZE - 1; ti.hwnd = NULL; ti.uId = 0x1234ABCD; SendMessage(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti); r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(0, r); ti.cbSize = TTTOOLINFOA_V2_SIZE + 1; ti.hwnd = NULL; ti.hinst = GetModuleHandleA(NULL); ti.uFlags = 0; ti.uId = 0x1234ABCD; ti.lpszText = NULL; ti.lParam = 0xdeadbeef; GetClientRect(hwnd, &ti.rect); r = SendMessage(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti); ok(r, "Adding the tool to the tooltip failed\n"); r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(1, r); ti.cbSize = TTTOOLINFOA_V2_SIZE + 1; ti.hwnd = NULL; ti.uId = 0x1234ABCD; SendMessage(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti); r = SendMessage(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(0, r); DestroyWindow(hwnd); /* 2. test size parameter validation rules (w-messages) */ hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0, 10, 10, 300, 100, NULL, NULL, NULL, 0); if(!hwnd) { win_skip("CreateWindowExW() not supported. Skipping.\n"); return; } tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1; tiW.hwnd = NULL; tiW.hinst = GetModuleHandleA(NULL); tiW.uFlags = 0; tiW.uId = 0x1234ABCD; tiW.lpszText = NULL; tiW.lParam = 0xdeadbeef; GetClientRect(hwnd, &tiW.rect); r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW); ok(r, "Adding the tool to the tooltip failed\n"); r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(1, r); tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1; tiW.hwnd = NULL; tiW.uId = 0x1234ABCD; SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW); r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(0, r); tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1; tiW.hwnd = NULL; tiW.hinst = GetModuleHandleA(NULL); tiW.uFlags = 0; tiW.uId = 0x1234ABCD; tiW.lpszText = NULL; tiW.lParam = 0xdeadbeef; GetClientRect(hwnd, &tiW.rect); r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW); ok(r, "Adding the tool to the tooltip failed\n"); r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(1, r); tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1; tiW.hwnd = NULL; tiW.uId = 0x1234ABCD; SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW); r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(0, r); tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1; tiW.hwnd = NULL; tiW.hinst = GetModuleHandleA(NULL); tiW.uFlags = 0; tiW.uId = 0x1234ABCD; tiW.lpszText = NULL; tiW.lParam = 0xdeadbeef; GetClientRect(hwnd, &tiW.rect); r = SendMessageW(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&tiW); ok(r, "Adding the tool to the tooltip failed\n"); r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(1, r); /* looks like TTM_DELTOOLW doesn't work with invalid size */ tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1; tiW.hwnd = NULL; tiW.uId = 0x1234ABCD; SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW); r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(1, r); tiW.cbSize = TTTOOLINFOW_V2_SIZE; tiW.hwnd = NULL; tiW.uId = 0x1234ABCD; SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW); r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0); expect(0, r); DestroyWindow(hwnd); }
static void test_gettext(void) { HWND hwnd, notify; TTTOOLINFOA toolinfoA; TTTOOLINFOW toolinfoW; LRESULT r; CHAR bufA[10] = ""; WCHAR bufW[10] = { 0 }; static const CHAR testtipA[] = "testtip"; notify = create_parent_window(); ok(notify != NULL, "Expected notification window to be created\n"); /* For bug 14790 - lpszText is NULL */ hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0, 10, 10, 300, 100, NULL, NULL, NULL, 0); assert(hwnd); /* use sizeof(TTTOOLINFOA) instead of TTTOOLINFOA_V1_SIZE so that adding it fails on Win9x */ /* otherwise it crashes on the NULL lpszText */ toolinfoA.cbSize = sizeof(TTTOOLINFOA); toolinfoA.hwnd = NULL; toolinfoA.hinst = GetModuleHandleA(NULL); toolinfoA.uFlags = 0; toolinfoA.uId = 0x1234ABCD; toolinfoA.lpszText = NULL; toolinfoA.lParam = 0xdeadbeef; GetClientRect(hwnd, &toolinfoA.rect); r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA); if (r) { toolinfoA.hwnd = NULL; toolinfoA.uId = 0x1234ABCD; toolinfoA.lpszText = bufA; SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA); ok(strcmp(toolinfoA.lpszText, "") == 0, "lpszText should be an empty string\n"); } else { win_skip( "Old comctl32, not testing NULL text\n" ); DestroyWindow( hwnd ); return; } /* add another tool with text */ toolinfoA.cbSize = sizeof(TTTOOLINFOA); toolinfoA.hwnd = NULL; toolinfoA.hinst = GetModuleHandleA(NULL); toolinfoA.uFlags = 0; toolinfoA.uId = 0x1235ABCD; strcpy(bufA, testtipA); toolinfoA.lpszText = bufA; toolinfoA.lParam = 0xdeadbeef; GetClientRect(hwnd, &toolinfoA.rect); r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA); ok(r, "Adding the tool to the tooltip failed\n"); if (r) { DWORD length; length = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0); ok(length == 0, "Expected 0, got %d\n", length); toolinfoA.hwnd = NULL; toolinfoA.uId = 0x1235ABCD; toolinfoA.lpszText = bufA; SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA); ok(strcmp(toolinfoA.lpszText, testtipA) == 0, "lpszText should be an empty string\n"); length = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0); ok(length == 0, "Expected 0, got %d\n", length); } /* add another with callback text */ toolinfoA.cbSize = sizeof(TTTOOLINFOA); toolinfoA.hwnd = notify; toolinfoA.hinst = GetModuleHandleA(NULL); toolinfoA.uFlags = 0; toolinfoA.uId = 0x1236ABCD; toolinfoA.lpszText = LPSTR_TEXTCALLBACKA; toolinfoA.lParam = 0xdeadbeef; GetClientRect(hwnd, &toolinfoA.rect); r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA); ok(r, "Adding the tool to the tooltip failed\n"); if (r) { toolinfoA.hwnd = notify; toolinfoA.uId = 0x1236ABCD; toolinfoA.lpszText = bufA; SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA); ok(strcmp(toolinfoA.lpszText, testcallbackA) == 0, "lpszText should be an (%s) string\n", testcallbackA); } DestroyWindow(hwnd); DestroyWindow(notify); SetLastError(0xdeadbeef); hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0, 10, 10, 300, 100, NULL, NULL, NULL, 0); if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { win_skip("CreateWindowExW is not implemented\n"); return; } assert(hwnd); toolinfoW.cbSize = sizeof(TTTOOLINFOW); toolinfoW.hwnd = NULL; toolinfoW.hinst = GetModuleHandleA(NULL); toolinfoW.uFlags = 0; toolinfoW.uId = 0x1234ABCD; toolinfoW.lpszText = NULL; toolinfoW.lParam = 0xdeadbeef; GetClientRect(hwnd, &toolinfoW.rect); r = SendMessageW(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoW); ok(r, "Adding the tool to the tooltip failed\n"); if (0) /* crashes on NT4 */ { toolinfoW.hwnd = NULL; toolinfoW.uId = 0x1234ABCD; toolinfoW.lpszText = bufW; SendMessageW(hwnd, TTM_GETTEXTW, 0, (LPARAM)&toolinfoW); ok(toolinfoW.lpszText[0] == 0, "lpszText should be an empty string\n"); } DestroyWindow(hwnd); }
static void test_updown_create(void) { CHAR text[MAX_PATH]; HWND updown; RECT r; flush_sequences(sequences, NUM_MSG_SEQUENCES); updown = create_updown_control(UDS_ALIGNRIGHT, g_edit); ok(updown != NULL, "Failed to create updown control\n"); ok_sequence(sequences, PARENT_SEQ_INDEX, add_updown_to_parent_seq, "add updown control to parent", TRUE); ok_sequence(sequences, EDIT_SEQ_INDEX, add_updown_with_edit_seq, "add updown control with edit", FALSE); flush_sequences(sequences, NUM_MSG_SEQUENCES); GetWindowTextA(g_edit, text, MAX_PATH); ok(lstrlenA(text) == 0, "Expected empty string\n"); ok_sequence(sequences, EDIT_SEQ_INDEX, get_edit_text_seq, "get edit text", FALSE); DestroyWindow(updown); /* create with zero width */ updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 0, parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); ok(updown != NULL, "Failed to create updown control\n"); r.right = 0; GetClientRect(updown, &r); ok(r.right > 0, "Expected default width, got %d\n", r.right); DestroyWindow(updown); /* create with really small width */ updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 2, 0, parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); ok(updown != NULL, "Failed to create updown control\n"); r.right = 0; GetClientRect(updown, &r); ok(r.right != 2 && r.right > 0, "Expected default width, got %d\n", r.right); DestroyWindow(updown); /* create with width greater than default */ updown = CreateWindowA (UPDOWN_CLASSA, 0, WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 100, 0, parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); ok(updown != NULL, "Failed to create updown control\n"); r.right = 0; GetClientRect(updown, &r); ok(r.right < 100 && r.right > 0, "Expected default width, got %d\n", r.right); DestroyWindow(updown); /* create with zero height, UDS_HORZ */ updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 0, parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); ok(updown != NULL, "Failed to create updown control\n"); r.bottom = 0; GetClientRect(updown, &r); ok(r.bottom == 0, "Expected zero height, got %d\n", r.bottom); DestroyWindow(updown); /* create with really small height, UDS_HORZ */ updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 2, parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); ok(updown != NULL, "Failed to create updown control\n"); r.bottom = 0; GetClientRect(updown, &r); ok(r.bottom == 0, "Expected zero height, got %d\n", r.bottom); DestroyWindow(updown); /* create with height greater than default, UDS_HORZ */ updown = CreateWindowA (UPDOWN_CLASSA, 0, UDS_HORZ | WS_CHILD | WS_BORDER | WS_VISIBLE, 0, 0, 0, 100, parent_wnd, (HMENU)(DWORD_PTR)1, GetModuleHandleA(NULL), 0); ok(updown != NULL, "Failed to create updown control\n"); r.bottom = 0; GetClientRect(updown, &r); ok(r.bottom < 100 && r.bottom > 0, "Expected default height, got %d\n", r.bottom); DestroyWindow(updown); }
void* getUser32Function (const char* functionName) { HMODULE module = GetModuleHandleA ("user32.dll"); jassert (module != 0); return (void*) GetProcAddress (module, functionName); }
static void test_WM_LBUTTONDOWN(void) { HWND hComboEx, hCombo, hEdit, hList; COMBOBOXINFO cbInfo; UINT x, y, item_height; LRESULT result; UINT i; int 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'}; BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO); pGetComboBoxInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo"); if (!pGetComboBoxInfo){ win_skip("GetComboBoxInfo is not available\n"); return; } 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 = pGetComboBoxInfo(hCombo, &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 || broken(GetFocus() != hCombo), /* win98 */ "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 || broken(GetFocus() != hCombo), /* win98 */ "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 || broken(GetFocus() != hCombo), /* win98 */ "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 || broken(GetFocus() != hCombo), /* win98 */ "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 || broken(GetFocus() == hCombo), /* win98 */ "Focus not on ComboBoxEx's Edit Control, instead on %p\n", GetFocus()); result = SendMessage(hCombo, CB_GETDROPPEDSTATE, 0, 0); ok(!result || broken(result != 0), /* win98 */ "The dropdown list should have been rolled up.\n"); idx = SendMessage(hComboEx, CB_GETCURSEL, 0, 0); ok(idx == 4 || broken(idx == -1), /* win98 */ "Current Selection: expected %d, got %d\n", 4, idx); ok(received_end_edit, "Expected to receive a CBEN_ENDEDIT message\n"); SetFocus( hComboExParentWnd ); ok( GetFocus() == hComboExParentWnd, "got %p\n", GetFocus() ); SetFocus( hComboEx ); ok( GetFocus() == hEdit, "got %p\n", GetFocus() ); DestroyWindow(hComboEx); }
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { lpCmdLine = GetCommandLine() + 1; while (*lpCmdLine != '"') ++lpCmdLine; ExitProcess(WinMain2(GetModuleHandleA(NULL), 0, ++lpCmdLine, SW_SHOWDEFAULT)); }
static void test_SIPLoad(void) { BOOL ret; GUID subject; static GUID dummySubject = { 0xdeadbeef, 0xdead, 0xbeef, { 0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef }}; static GUID unknown = { 0xC689AABA, 0x8E78, 0x11D0, { 0x8C,0x47,0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; /* WINTRUST.DLL */ static GUID unknown2 = { 0xDE351A43, 0x8E59, 0x11D0, { 0x8C,0x47,0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; /* WINTRUST.DLL */ /* The next SIP is available on Windows and on Wine */ static GUID unknown3 = { 0x000C10F1, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 }}; /* MSISIP.DLL */ SIP_DISPATCH_INFO sdi; HMODULE hCrypt; /* All NULL */ SetLastError(0xdeadbeef); ret = CryptSIPLoad(NULL, 0, NULL); ok ( !ret, "Expected CryptSIPLoad to fail\n"); ok ( GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got 0x%08x\n", GetLastError()); /* Only pSipDispatch NULL */ SetLastError(0xdeadbeef); ret = CryptSIPLoad(&subject, 0, NULL); ok ( !ret, "Expected CryptSIPLoad to fail\n"); ok ( GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got 0x%08x\n", GetLastError()); /* No NULLs, but nonexistent pgSubject */ SetLastError(0xdeadbeef); memset(&sdi, 0, sizeof(SIP_DISPATCH_INFO)); sdi.cbSize = sizeof(SIP_DISPATCH_INFO); sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef; ret = CryptSIPLoad(&dummySubject, 0, &sdi); ok ( !ret, "Expected CryptSIPLoad to fail\n"); ok ( GetLastError() == TRUST_E_SUBJECT_FORM_UNKNOWN, "Expected TRUST_E_SUBJECT_FORM_UNKNOWN, got 0x%08x\n", GetLastError()); ok( sdi.pfGet == (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected no change to the function pointer\n"); hCrypt = GetModuleHandleA("crypt32.dll"); funcCryptSIPGetSignedDataMsg = (void*)GetProcAddress(hCrypt, "CryptSIPGetSignedDataMsg"); funcCryptSIPPutSignedDataMsg = (void*)GetProcAddress(hCrypt, "CryptSIPPutSignedDataMsg"); funcCryptSIPCreateIndirectData = (void*)GetProcAddress(hCrypt, "CryptSIPCreateIndirectData"); funcCryptSIPVerifyIndirectData = (void*)GetProcAddress(hCrypt, "CryptSIPVerifyIndirectData"); funcCryptSIPRemoveSignedDataMsg = (void*)GetProcAddress(hCrypt, "CryptSIPRemoveSignedDataMsg"); /* All OK */ SetLastError(0xdeadbeef); memset(&sdi, 0, sizeof(SIP_DISPATCH_INFO)); sdi.cbSize = sizeof(SIP_DISPATCH_INFO); sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef; ret = CryptSIPLoad(&unknown, 0, &sdi); ok ( ret, "Expected CryptSIPLoad to succeed\n"); /* On native the last error will always be ERROR_PROC_NOT_FOUND as native searches for the function DllCanUnloadNow * in WINTRUST.DLL (in this case). This function is not available in WINTRUST.DLL. * For now there's no need to implement this is Wine as I doubt any program will rely on * this last error when the call succeeded. */ ok( sdi.pfGet != (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected a function pointer to be loaded.\n"); /* The function addresses returned by CryptSIPLoad are actually the addresses of * crypt32's own functions. A function calling these addresses will end up first * calling crypt32 functions which in its turn call the equivalent in the SIP * as dictated by the given GUID. */ if (funcCryptSIPGetSignedDataMsg && funcCryptSIPPutSignedDataMsg && funcCryptSIPCreateIndirectData && funcCryptSIPVerifyIndirectData && funcCryptSIPRemoveSignedDataMsg) ok (sdi.pfGet == funcCryptSIPGetSignedDataMsg && sdi.pfPut == funcCryptSIPPutSignedDataMsg && sdi.pfCreate == funcCryptSIPCreateIndirectData && sdi.pfVerify == funcCryptSIPVerifyIndirectData && sdi.pfRemove == funcCryptSIPRemoveSignedDataMsg, "Expected function addresses to be from crypt32\n"); else trace("Couldn't load function pointers\n"); /* All OK, but different GUID (same SIP though) */ SetLastError(0xdeadbeef); memset(&sdi, 0, sizeof(SIP_DISPATCH_INFO)); sdi.cbSize = sizeof(SIP_DISPATCH_INFO); sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef; ret = CryptSIPLoad(&unknown2, 0, &sdi); ok ( ret, "Expected CryptSIPLoad to succeed\n"); /* This call on its own would have resulted in an ERROR_PROC_NOT_FOUND, but the previous * call to CryptSIPLoad already loaded wintrust.dll. As this information is cached, * CryptSIPLoad will not try to search for the already mentioned DllCanUnloadNow. */ ok( sdi.pfGet != (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected a function pointer to be loaded.\n"); /* All OK, but other SIP */ SetLastError(0xdeadbeef); memset(&sdi, 0, sizeof(SIP_DISPATCH_INFO)); sdi.cbSize = sizeof(SIP_DISPATCH_INFO); sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef; ret = CryptSIPLoad(&unknown3, 0, &sdi); if (ret) { /* The SIP is known so we can safely assume that the next tests can be done */ /* As msisip.dll is not checked yet by any of the previous calls, the * function DllCanUnloadNow will be checked again in msisip.dll (it's not present) */ ok( sdi.pfGet != (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected a function pointer to be loaded.\n"); /* This is another SIP but this test proves the function addresses are the same as * in the previous test. */ if (funcCryptSIPGetSignedDataMsg && funcCryptSIPPutSignedDataMsg && funcCryptSIPCreateIndirectData && funcCryptSIPVerifyIndirectData && funcCryptSIPRemoveSignedDataMsg) ok (sdi.pfGet == funcCryptSIPGetSignedDataMsg && sdi.pfPut == funcCryptSIPPutSignedDataMsg && sdi.pfCreate == funcCryptSIPCreateIndirectData && sdi.pfVerify == funcCryptSIPVerifyIndirectData && sdi.pfRemove == funcCryptSIPRemoveSignedDataMsg, "Expected function addresses to be from crypt32\n"); else trace("Couldn't load function pointers\n"); } /* Reserved parameter not 0 */ SetLastError(0xdeadbeef); memset(&sdi, 0, sizeof(SIP_DISPATCH_INFO)); sdi.cbSize = sizeof(SIP_DISPATCH_INFO); sdi.pfGet = (pCryptSIPGetSignedDataMsg)0xdeadbeef; ret = CryptSIPLoad(&unknown, 1, &sdi); ok ( !ret, "Expected CryptSIPLoad to fail\n"); ok ( GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got 0x%08x\n", GetLastError()); ok( sdi.pfGet == (pCryptSIPGetSignedDataMsg)0xdeadbeef, "Expected no change to the function pointer\n"); }