diff --git a/dlls/riched20/tests/txtsrv.c b/dlls/riched20/tests/txtsrv.c index da8c81d..72d93c9 100644 --- a/dlls/riched20/tests/txtsrv.c +++ b/dlls/riched20/tests/txtsrv.c @@ -34,6 +34,35 @@ static HMODULE hmoduleRichEdit; +/* Define C Macros for ITextServices calls. */ + +/* Use a special table for x86 machines to convert the thiscall + * calling convention. This isn't needed on other platforms. */ +#ifdef __i386__ +#define TXTSERV_VTABLE(This) (&itextServicesStdcallVtbl) +#else /* __i386__ */ +#define TXTSERV_VTABLE(This) (This)->lpVtbl +#endif /* __i386__ */ + +#define ITextServices_TxSendMessage(This,a,b,c,d) TXTSERV_VTABLE(This)->TxSendMessage(This,a,b,c,d) +#define ITextServices_TxDraw(This,a,b,c,d,e,f,g,h,i,j,k,l) TXTSERV_VTABLE(This)->TxDraw(This,a,b,c,d,e,f,g,h,i,j,k,l) +#define ITextServices_TxGetHScroll(This,a,b,c,d,e) TXTSERV_VTABLE(This)->TxGetHScroll(This,a,b,c,d,e) +#define ITextServices_TxGetVScroll(This,a,b,c,d,e) TXTSERV_VTABLE(This)->TxGetVScroll(This,a,b,c,d,e) +#define ITextServices_OnTxSetCursor(This,a,b,c,d,e,f,g,h,i) TXTSERV_VTABLE(This)->OnTxSetCursor(This,a,b,c,d,e,f,g,h,i) +#define ITextServices_TxQueryHitPoint(This,a,b,c,d,e,f,g,h,i,j) TXTSERV_VTABLE(This)->TxQueryHitPoint(This,a,b,c,d,e,f,g,h,i,j) +#define ITextServices_OnTxInplaceActivate(This,a) TXTSERV_VTABLE(This)->OnTxInplaceActivate(This,a) +#define ITextServices_OnTxInplaceDeactivate(This) TXTSERV_VTABLE(This)->OnTxInplaceDeactivate(This) +#define ITextServices_OnTxUIActivate(This) TXTSERV_VTABLE(This)->OnTxUIActivate(This) +#define ITextServices_OnTxUIDeactivate(This) TXTSERV_VTABLE(This)->OnTxUIDeactivate(This) +#define ITextServices_TxGetText(This,a) TXTSERV_VTABLE(This)->TxGetText(This,a) +#define ITextServices_TxSetText(This,a) TXTSERV_VTABLE(This)->TxSetText(This,a) +#define ITextServices_TxGetCurrentTargetX(This,a) TXTSERV_VTABLE(This)->TxGetCurrentTargetX(This,a) +#define ITextServices_TxGetBaseLinePos(This,a) TXTSERV_VTABLE(This)->TxGetBaseLinePos(This,a) +#define ITextServices_TxGetNaturalSize(This,a,b,c,d,e,f,g,h) TXTSERV_VTABLE(This)->TxGetNaturalSize(This,a,b,c,d,e,f,g,h) +#define ITextServices_TxGetDropTarget(This,a) TXTSERV_VTABLE(This)->TxGetDropTarget(This,a) +#define ITextServices_OnTxPropertyBitsChange(This,a,b) TXTSERV_VTABLE(This)->OnTxPropertyBitsChange(This,a,b) +#define ITextServices_TxGetCachedSize(This,a,b) TXTSERV_VTABLE(This)->TxGetCachedSize(This,a,b) + /* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose * function call traces of ITextHost. */ #define TRACECALL if(winetest_debug > 1) trace @@ -412,6 +441,8 @@ static HRESULT WINAPI ITextHostImpl_TxGetSelectionBarWidth(ITextHost *iface, return E_NOTIMPL; } +static ITextServicesVtbl itextServicesStdcallVtbl; + static ITextHostVtbl itextHostVtbl = { ITextHostImpl_QueryInterface, ITextHostImpl_AddRef, @@ -482,6 +513,18 @@ char thiscall_to_stdcall_x86_code[] = { }; #define STDCALL_FUNC_ADDRESS_BYTE_POSITION 4 +char stdcall_to_thiscall_x86_code[] = { + 0x58, /* pop %eax */ + 0x59, /* pop %ecx */ + 0x50, /* push %eax */ + 0x8b, 0x01, /* mov (%ecx), %eax */ + /* The third byte (0x0) is a placeholder for the offset of the + * function pointer in the vtable. */ + 0x8b, 0x40, 0x00, /* mov 0x0(%eax),%eax */ + 0xff, 0xe0 /* jmp *%eax */ +}; +#define VTABLE_OFFSET_DWORD_POSITION 7 + static void setup_thiscall_wrappers() { @@ -493,7 +536,9 @@ static void setup_thiscall_wrappers() DWORD oldProtectFlags; code_size = ((sizeof(ITextHostVtbl) / sizeof(void*)) - 3) - * sizeof(thiscall_to_stdcall_x86_code); + * sizeof(thiscall_to_stdcall_x86_code) + + ((sizeof(ITextServicesVtbl) / sizeof(void*)) - 3) + * sizeof(stdcall_to_thiscall_x86_code); wrapperCodeMem = VirtualAlloc(NULL, code_size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); wrapper_code = wrapperCodeMem; @@ -518,6 +563,28 @@ static void setup_thiscall_wrappers() pVtable++; wrapper_code += sizeof(thiscall_to_stdcall_x86_code); } + + /* Setup an ITextServices standard call vtable that will call the + * native thiscall vtable when the methods are called. */ + + /* QueryInterface, AddRef, and Release should be called directly on the + * real vtable since they use the stdcall calling convention. */ + FillMemory(&itextServicesStdcallVtbl, sizeof(void**) * 3, 0); + pVtable = ((void**)&itextServicesStdcallVtbl) + 3; + pVtableEnd = (void**)(((char*)&itextServicesStdcallVtbl) + sizeof(ITextServicesVtbl)); + while (pVtable != pVtableEnd) { + char *placeholder; + + CopyMemory(wrapper_code, stdcall_to_thiscall_x86_code, + sizeof(stdcall_to_thiscall_x86_code)); + /* Modify the 1 byte placeholder in the code for the vtable offset. */ + placeholder = wrapper_code + VTABLE_OFFSET_DWORD_POSITION; + *placeholder = (char)(pVtable - ((void**)&itextServicesStdcallVtbl)) * 4; + *pVtable = wrapper_code; + pVtable++; + wrapper_code += sizeof(stdcall_to_thiscall_x86_code); + } + VirtualProtect(wrapperCodeMem, code_size, PAGE_EXECUTE, &oldProtectFlags); #endif /* __i386__ */ } @@ -573,6 +640,21 @@ BOOL init_texthost() return TRUE; } +static void test_TxGetText() +{ + HRESULT hres; + BSTR rettext; + + if (!init_texthost()) + return; + + hres = ITextServices_TxGetText(txtserv, &rettext); + todo_wine ok(hres == S_OK, "ITextServices_TxGetText failed\n"); + + IUnknown_Release(txtserv); + CoTaskMemFree(dummyTextHost); +} + START_TEST( txtsrv ) { setup_thiscall_wrappers(); @@ -590,5 +672,7 @@ START_TEST( txtsrv ) IUnknown_Release(txtserv); CoTaskMemFree(dummyTextHost); + test_TxGetText(); + destroy_thiscall_wrappers(); } diff --git a/include/textserv.h b/include/textserv.h index 9b3cbf9..1c262ac 100644 --- a/include/textserv.h +++ b/include/textserv.h @@ -147,25 +147,6 @@ DECLARE_INTERFACE_(ITextServices,IUnknown) #define ITextServices_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) #define ITextServices_AddRef(p) (p)->lpVtbl->AddRef(p) #define ITextServices_Release(p) (p)->lpVtbl->Release(p) -/*** ITextServices methods ***/ -#define ITextServices_TxSendMessage(p,a,b,c,d) (p)->lpVtbl->TxSendMessage(p,a,b,c,d) -#define ITextServices_TxDraw(p,a,b,c,d,e,f,g,h,i,j,k,l) (p)->lpVtbl->TxDraw(p,a,b,c,d,e,f,g,h,i,j,k,l) -#define ITextServices_TxGetHScroll(p,a,b,c,d,e) (p)->lpVtbl->TxGetHScroll(p,a,b,c,d,e) -#define ITextServices_TxGetVScroll(p,a,b,c,d,e) (p)->lpVtbl->TxGetVScroll(p,a,b,c,d,e) -#define ITextServices_OnTxSetCursor(p,a,b,c,d,e,f,g,h,i) (p)->lpVtbl->OnTxSetCursor(p,a,b,c,d,e,f,g,h,i) -#define ITextServices_TxQueryHitPoint(p,a,b,c,d,e,f,g,h,i,j) (p)->lpVtbl->TxQueryHitPoint(p,a,b,c,d,e,f,g,h,i,j) -#define ITextServices_OnTxInplaceActivate(p,a) (p)->lpVtbl->OnTxInplaceActivate(p,a) -#define ITextServices_OnTxInplaceDeactivate(p) (p)->lpVtbl->OnTxInplaceDeactivate(p) -#define ITextServices_OnTxUIActivate(p) (p)->lpVtbl->OnTxUIActivate(p) -#define ITextServices_OnTxUIDeactivate(p) (p)->lpVtbl->OnTxUIDeactivate(p) -#define ITextServices_TxGetText(p,a) (p)->lpVtbl->TxGetText(p,a) -#define ITextServices_TxSetText(p,a) (p)->lpVtbl->TxSetText(p,a) -#define ITextServices_TxGetCurrentTargetX(p,a) (p)->lpVtbl->TxGetCurrentTargetX(p,a) -#define ITextServices_TxGetBaseLinePos(p,a) (p)->lpVtbl->TxGetBaseLinePos(p,a) -#define ITextServices_TxGetNaturalSize(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->TxGetNaturalSize(p,a,b,c,d,e,f,g,h) -#define ITextServices_TxGetDropTarget(p,a) (p)->lpVtbl->TxGetDropTarget(p,a) -#define ITextServices_OnTxPropertyBitsChange(p,a,b) (p)->lpVtbl->OnTxPropertyBitsChange(p,a,b) -#define ITextServices_TxGetCachedSize(p,a,b) (p)->lpVtbl->TxGetCachedSize(p,a,b) #endif #undef INTERFACE