Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com ---
Notes: v1 -> v2: - remove unused typedef storage class specifier from struct IRichEditOleCallbackImpl definition (thanks huw) - remove Hungarian notation from struct fields and callback params (thanks huw)
dlls/riched20/tests/richole.c | 247 ++++++++++++++++++++++++++++++++-- 1 file changed, 236 insertions(+), 11 deletions(-)
diff --git a/dlls/riched20/tests/richole.c b/dlls/riched20/tests/richole.c index 24284a24484..fce4e74285d 100644 --- a/dlls/riched20/tests/richole.c +++ b/dlls/riched20/tests/richole.c @@ -33,6 +33,169 @@ #include <tom.h> #include <wine/test.h>
+#define EXPECT_TODO_WINE 0x80000000UL + +struct IRichEditOleCallbackImpl { + IRichEditOleCallback IRichEditOleCallback_iface; + LONG ref; + int line; + + ULONG expect_queryinsertobject; + + const CLSID *clsid; + LPSTORAGE stg; + LONG cp; + HRESULT queryinsertobject_result; +}; + +static inline struct IRichEditOleCallbackImpl *impl_from_IRichEditOleCallback(IRichEditOleCallback *iface) +{ + return CONTAINING_RECORD(iface, struct IRichEditOleCallbackImpl, IRichEditOleCallback_iface); +} + +static HRESULT STDMETHODCALLTYPE RichEditOleCallbackImpl_QueryInterface(IRichEditOleCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IRichEditOleCallback)) { + IRichEditOleCallback_AddRef(iface); + *obj = iface; + return S_OK; + } + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE RichEditOleCallbackImpl_AddRef(IRichEditOleCallback *iface) +{ + struct IRichEditOleCallbackImpl *This = impl_from_IRichEditOleCallback(iface); + ULONG ref = InterlockedIncrement(&This->ref); + return ref; +} + +static ULONG STDMETHODCALLTYPE RichEditOleCallbackImpl_Release(IRichEditOleCallback *iface) +{ + struct IRichEditOleCallbackImpl *This = impl_from_IRichEditOleCallback(iface); + ULONG ref = InterlockedDecrement(&This->ref); + if (!ref) free(This); + return ref; +} + +static HRESULT STDMETHODCALLTYPE RichEditOleCallbackImpl_GetNewStorage(IRichEditOleCallback *iface, LPSTORAGE *stg) +{ + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE RichEditOleCallbackImpl_GetInPlaceContext(IRichEditOleCallback *iface, LPOLEINPLACEFRAME *frame, LPOLEINPLACEUIWINDOW *doc, LPOLEINPLACEFRAMEINFO frame_info) +{ + return E_INVALIDARG; +} + +static HRESULT STDMETHODCALLTYPE RichEditOleCallbackImpl_ShowContainerUI(IRichEditOleCallback *iface, BOOL show) +{ + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE RichEditOleCallbackImpl_QueryInsertObject(IRichEditOleCallback *iface, LPCLSID clsid, LPSTORAGE stg, LONG cp) +{ + struct IRichEditOleCallbackImpl *This = impl_from_IRichEditOleCallback(iface); + ULONG expect = This->expect_queryinsertobject; + + todo_wine_if(expect & EXPECT_TODO_WINE) + ok_(__FILE__,This->line)( expect & ~EXPECT_TODO_WINE, "unexpected call to IRichEditOleCallback_QueryInsertObject\n"); + if (!(expect & ~EXPECT_TODO_WINE)) return S_OK; + This->expect_queryinsertobject--; + + if (This->clsid && clsid) + ok_(__FILE__,This->line)( IsEqualGUID(This->clsid, clsid), "QueryInsertObject clsid expected %s, got %s\n", wine_dbgstr_guid( This->clsid ), wine_dbgstr_guid( clsid )); + else + ok_(__FILE__,This->line)( This->clsid == clsid, "QueryInsertObject clsid expected %p, got %p\n", This->clsid, clsid ); + ok_(__FILE__,This->line)( This->stg == stg, "QueryInsertObject stg expected %p, got %p\n", This->stg, stg ); + ok_(__FILE__,This->line)( This->cp == cp, "QueryInsertObject cp expected %ld, got %ld\n", This->cp, cp ); + return This->queryinsertobject_result; +} + +static HRESULT STDMETHODCALLTYPE RichEditOleCallbackImpl_DeleteObject(IRichEditOleCallback *iface, LPOLEOBJECT oleobj) +{ + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE RichEditOleCallbackImpl_QueryAcceptData(IRichEditOleCallback *iface, LPDATAOBJECT dataobj, CLIPFORMAT *cf_format, DWORD reco, BOOL really, HGLOBAL metapict) +{ + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE RichEditOleCallbackImpl_ContextSensitiveHelp(IRichEditOleCallback *iface, BOOL enter_mode) +{ + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE RichEditOleCallbackImpl_GetClipboardData(IRichEditOleCallback *iface, CHARRANGE *chrg, DWORD reco, LPDATAOBJECT *dataobj) +{ + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE RichEditOleCallbackImpl_GetDragDropEffect(IRichEditOleCallback *iface, BOOL drag, DWORD key_state, LPDWORD effect) +{ + if (effect) *effect = DROPEFFECT_COPY; + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE RichEditOleCallbackImpl_GetContextMenu(IRichEditOleCallback *iface, WORD seltype, LPOLEOBJECT oleobj, CHARRANGE *chrg, HMENU *hmenu) +{ + return E_NOTIMPL; +} + +static const struct IRichEditOleCallbackVtbl RichEditOleCallbackImpl_Vtbl = { + RichEditOleCallbackImpl_QueryInterface, + RichEditOleCallbackImpl_AddRef, + RichEditOleCallbackImpl_Release, + RichEditOleCallbackImpl_GetNewStorage, + RichEditOleCallbackImpl_GetInPlaceContext, + RichEditOleCallbackImpl_ShowContainerUI, + RichEditOleCallbackImpl_QueryInsertObject, + RichEditOleCallbackImpl_DeleteObject, + RichEditOleCallbackImpl_QueryAcceptData, + RichEditOleCallbackImpl_ContextSensitiveHelp, + RichEditOleCallbackImpl_GetClipboardData, + RichEditOleCallbackImpl_GetDragDropEffect, + RichEditOleCallbackImpl_GetContextMenu, +}; + +static HRESULT RichEditOleCallbackImpl_Create(struct IRichEditOleCallbackImpl **objptr) +{ + struct IRichEditOleCallbackImpl *obj; + + obj = calloc(sizeof(struct IRichEditOleCallbackImpl), 1); + if (!obj) return E_OUTOFMEMORY; + + obj->IRichEditOleCallback_iface.lpVtbl = &RichEditOleCallbackImpl_Vtbl; + obj->ref = 1; + + *objptr = obj; + return S_OK; +} + +static void olecb_expect_QueryInsertObject(struct IRichEditOleCallbackImpl *This, int line, ULONG expect, const CLSID *clsid, LPSTORAGE stg, LONG cp, HRESULT result) +{ + if (!This) return; + + This->line = line; + This->expect_queryinsertobject = expect; + This->clsid = clsid; + This->stg = stg; + This->cp = cp; + This->queryinsertobject_result = result; +} + +static void olecb_check_QueryInsertObject(struct IRichEditOleCallbackImpl *This, int line) +{ + if (!This) return; + + todo_wine_if(This->expect_queryinsertobject & EXPECT_TODO_WINE) + ok(!(This->expect_queryinsertobject & ~EXPECT_TODO_WINE), "expected IRichEditOleCallback_QueryInsertObject to be called\n"); + + olecb_expect_QueryInsertObject(This, 0, 0, NULL, NULL, 0, S_OK); +} + static HMODULE hmoduleRichEdit;
DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); @@ -3233,21 +3396,24 @@ static void _check_reobject_struct(IRichEditOle *reole, LONG index, DWORD flags, ok_(__FILE__,line)(reobj.dwUser == user, "got wrong user-defined value.\n"); }
-#define INSERT_REOBJECT(reole,reobj,cp,user) \ - _insert_reobject(reole, reobj, cp, user, __LINE__) -static void _insert_reobject(IRichEditOle *reole, REOBJECT *reobj, LONG cp, DWORD user, int line) +#define INSERT_REOBJECT(callback,reole,reobj,cp,user) \ + _insert_reobject(callback, reole, reobj, cp, user, __LINE__) +static void _insert_reobject(struct IRichEditOleCallbackImpl *callback, IRichEditOle *reole, REOBJECT *reobj, LONG cp, DWORD user, int line) { IOleClientSite *clientsite; HRESULT hr; + + olecb_expect_QueryInsertObject(callback, line, EXPECT_TODO_WINE | 1, &CLSID_NULL, NULL, REO_CP_SELECTION /* cp overriden */, S_OK); hr = IRichEditOle_GetClientSite(reole, &clientsite); ok_(__FILE__,line)(hr == S_OK, "IRichEditOle_GetClientSite got hr %#lx.\n", hr); fill_reobject_struct(reobj, cp, NULL, NULL, clientsite, 10, 10, DVASPECT_CONTENT, 0, user); hr = IRichEditOle_InsertObject(reole, reobj); ok_(__FILE__,line)(hr == S_OK, "IRichEditOle_InsertObject got hr %#lx.\n", hr); IOleClientSite_Release(clientsite); + olecb_check_QueryInsertObject(callback, line); }
-static void test_InsertObject(void) +static void subtest_InsertObject(struct IRichEditOleCallbackImpl *callback) { static CHAR test_text1[] = "abcdefg"; IRichEditOle *reole = NULL; @@ -3271,6 +3437,12 @@ static void test_InsertObject(void) BSTR bstr;
create_interfaces(&hwnd, &reole, &doc, &selection); + if (callback) + { + LRESULT sendres = SendMessageA(hwnd, EM_SETOLECALLBACK, 0, (LPARAM)&callback->IRichEditOleCallback_iface); + ok( !!sendres, "EM_SETOLECALLBACK should succeed\n" ); + } + SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_text1);
hr = IRichEditOle_InsertObject(reole, NULL); @@ -3278,22 +3450,47 @@ static void test_InsertObject(void)
/* insert object1 in (0, 1)*/ SendMessageA(hwnd, EM_SETSEL, 0, 1); - INSERT_REOBJECT(reole, &reo1, REO_CP_SELECTION, 1); + INSERT_REOBJECT(callback, reole, &reo1, REO_CP_SELECTION, 1); count = IRichEditOle_GetObjectCount(reole); ok(count == 1, "got wrong object count: %ld\n", count);
/* insert object2 in (2, 3)*/ SendMessageA(hwnd, EM_SETSEL, 2, 3); - INSERT_REOBJECT(reole, &reo2, REO_CP_SELECTION, 2); + INSERT_REOBJECT(callback, reole, &reo2, REO_CP_SELECTION, 2); count = IRichEditOle_GetObjectCount(reole); ok(count == 2, "got wrong object count: %ld\n", count);
/* insert object3 in (1, 2)*/ SendMessageA(hwnd, EM_SETSEL, 1, 2); - INSERT_REOBJECT(reole, &reo3, REO_CP_SELECTION, 3); + INSERT_REOBJECT(callback, reole, &reo3, REO_CP_SELECTION, 3); count = IRichEditOle_GetObjectCount(reole); ok(count == 3, "got wrong object count: %ld\n", count);
+ if (callback) + { + IOleClientSite *clientsite; + REOBJECT reobj; + + /* (fail to) insert object1 in (3, 4)*/ + SendMessageA(hwnd, EM_SETSEL, 3, 4); + + hr = IRichEditOle_GetClientSite(reole, &clientsite); + ok(hr == S_OK, "IRichEditOle_GetClientSite got hr %#lx.\n", hr); + + olecb_expect_QueryInsertObject(callback, __LINE__, EXPECT_TODO_WINE | 1, &CLSID_NULL, NULL, REO_CP_SELECTION, S_FALSE); + fill_reobject_struct(&reobj, REO_CP_SELECTION, NULL, NULL, clientsite, 10, 10, DVASPECT_CONTENT, 0, 0); + hr = IRichEditOle_InsertObject(reole, &reobj); + todo_wine + ok(hr == S_FALSE, "IRichEditOle_InsertObject got hr %#lx.\n", hr); + olecb_check_QueryInsertObject(callback, __LINE__); + + IOleClientSite_Release(clientsite); + + count = IRichEditOle_GetObjectCount(reole); + todo_wine + ok(count == 3, "got wrong object count: %ld\n", count); + } + /* tests below show that order of rebject (from 0 to 2) is: reo1,reo3,reo2 */ CHECK_REOBJECT_STRUCT(reole, 0, REO_GETOBJ_ALL_INTERFACES, 0, 0, NULL, NULL, reo1.polesite, 1); CHECK_REOBJECT_STRUCT(reole, 1, REO_GETOBJ_ALL_INTERFACES, 0, 1, NULL, NULL, reo3.polesite, 3); @@ -3371,8 +3568,8 @@ static void test_InsertObject(void) SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_text1);
/* "abc|d|efg" */ - INSERT_REOBJECT(reole, &reo1, 3, 1); - INSERT_REOBJECT(reole, &reo2, 5, 2); + INSERT_REOBJECT(callback, reole, &reo1, 3, 1); + INSERT_REOBJECT(callback, reole, &reo2, 5, 2);
SendMessageW(hwnd, EM_SETSEL, 2, 3); result = SendMessageW(hwnd, EM_SELECTIONTYPE, 0, 0); @@ -3473,8 +3670,8 @@ static void test_InsertObject(void) ok(!result, "Got result %lx.\n", result); /* "abc|d|efg" */ SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_text1); - INSERT_REOBJECT(reole, &reo1, 3, 1); - INSERT_REOBJECT(reole, &reo2, 5, 2); + INSERT_REOBJECT(callback, reole, &reo1, 3, 1); + INSERT_REOBJECT(callback, reole, &reo2, 5, 2);
expected_string = L"abc d efg"; charrange.cpMin = 0; @@ -3551,9 +3748,37 @@ static void test_InsertObject(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); todo_wine ok(result == 0xfffc, "Got char: %lc\n", (WCHAR)result);
+ if (callback) + { + LRESULT sendres = SendMessageA(hwnd, EM_SETOLECALLBACK, 0, 0); + ok( !!sendres, "EM_SETOLECALLBACK should succeed\n" ); + } + release_interfaces(&hwnd, &reole, &doc, &selection); }
+static void test_InsertObject(void) +{ + struct IRichEditOleCallbackImpl *callback; + HRESULT hr; + ULONG ref; + + subtest_InsertObject(NULL); + + hr = RichEditOleCallbackImpl_Create(&callback); + ok(SUCCEEDED(hr), "RichEditOleCallbackImpl_Create returned %#lx\n", hr); + if (SUCCEEDED(hr)) + { + subtest_InsertObject(callback); + ref = IRichEditOleCallback_Release(&callback->IRichEditOleCallback_iface); + ok(ref == 0, "expected IRichEditOleCallback recount to be 0, got %lu\n", ref); + } + else + { + skip("cannot test InsertObject with callback\n"); + } +} + static void test_GetStoryLength(void) { static const CHAR test_text1[] = "TestSomeText";
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/riched20/caret.c | 11 ++++++++++- dlls/riched20/editor.c | 3 +-- dlls/riched20/editor.h | 2 +- dlls/riched20/richole.c | 6 +++++- dlls/riched20/tests/richole.c | 6 ++---- 5 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/dlls/riched20/caret.c b/dlls/riched20/caret.c index c8658098e18..09ec0ffc735 100644 --- a/dlls/riched20/caret.c +++ b/dlls/riched20/caret.c @@ -456,13 +456,21 @@ static struct re_object* create_re_object(const REOBJECT *reo, ME_Run *run) return reobj; }
-void editor_insert_oleobj(ME_TextEditor *editor, const REOBJECT *reo) +HRESULT editor_insert_oleobj(ME_TextEditor *editor, const REOBJECT *reo) { ME_Run *run, *prev; const WCHAR space = ' '; struct re_object *reobj_prev = NULL; ME_Cursor *cursor, cursor_from_ofs; ME_Style *style; + HRESULT hr; + + if (editor->lpOleCallback) + { + hr = IRichEditOleCallback_QueryInsertObject(editor->lpOleCallback, (LPCLSID)&reo->clsid, reo->pstg, REO_CP_SELECTION); + if (hr != S_OK) + return hr; + }
if (reo->cp == REO_CP_SELECTION) cursor = editor->pCursors; @@ -495,6 +503,7 @@ void editor_insert_oleobj(ME_TextEditor *editor, const REOBJECT *reo) list_add_head(&editor->reobj_list, &run->reobj->entry);
ME_ReleaseStyle( style ); + return S_OK; }
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index a8cf3175591..3628e51ac9b 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -1171,8 +1171,7 @@ static HRESULT insert_static_object(ME_TextEditor *editor, HENHMETAFILE hemf, HB reobject.dwFlags = 0; /* FIXME */ reobject.dwUser = 0;
- editor_insert_oleobj(editor, &reobject); - hr = S_OK; + hr = editor_insert_oleobj(editor, &reobject); }
if (lpObject) IOleObject_Release(lpObject); diff --git a/dlls/riched20/editor.h b/dlls/riched20/editor.h index e0df63ae92d..3028d9bdbd5 100644 --- a/dlls/riched20/editor.h +++ b/dlls/riched20/editor.h @@ -187,7 +187,7 @@ int ME_GetSelection(ME_TextEditor *editor, ME_Cursor **from, ME_Cursor **to) DEC BOOL ME_IsSelection(ME_TextEditor *editor) DECLSPEC_HIDDEN; void ME_DeleteSelection(ME_TextEditor *editor) DECLSPEC_HIDDEN; void ME_SendSelChange(ME_TextEditor *editor) DECLSPEC_HIDDEN; -void editor_insert_oleobj( ME_TextEditor *editor, const REOBJECT *reo ) DECLSPEC_HIDDEN; +HRESULT editor_insert_oleobj( ME_TextEditor *editor, const REOBJECT *reo ) DECLSPEC_HIDDEN; BOOL ME_InternalDeleteText(ME_TextEditor *editor, ME_Cursor *start, int nChars, BOOL bForce) DECLSPEC_HIDDEN; int ME_GetTextLength(ME_TextEditor *editor) DECLSPEC_HIDDEN; int ME_GetTextLengthEx(ME_TextEditor *editor, const GETTEXTLENGTHEX *how) DECLSPEC_HIDDEN; diff --git a/dlls/riched20/richole.c b/dlls/riched20/richole.c index a23f4c82730..936f1c928b3 100644 --- a/dlls/riched20/richole.c +++ b/dlls/riched20/richole.c @@ -1361,6 +1361,7 @@ static HRESULT WINAPI IRichEditOle_fnInsertObject(IRichEditOle *iface, REOBJECT *reo) { struct text_services *services = impl_from_IRichEditOle( iface ); + HRESULT hr;
TRACE("(%p,%p)\n", services, reo);
@@ -1369,7 +1370,10 @@ IRichEditOle_fnInsertObject(IRichEditOle *iface, REOBJECT *reo)
if (reo->cbStruct < sizeof(*reo)) return STG_E_INVALIDPARAMETER;
- editor_insert_oleobj(services->editor, reo); + hr = editor_insert_oleobj(services->editor, reo); + if (hr != S_OK) + return hr; + ME_CommitUndo(services->editor); ME_UpdateRepaint(services->editor, FALSE); return S_OK; diff --git a/dlls/riched20/tests/richole.c b/dlls/riched20/tests/richole.c index fce4e74285d..0359bfe14c0 100644 --- a/dlls/riched20/tests/richole.c +++ b/dlls/riched20/tests/richole.c @@ -3403,7 +3403,7 @@ static void _insert_reobject(struct IRichEditOleCallbackImpl *callback, IRichEdi IOleClientSite *clientsite; HRESULT hr;
- olecb_expect_QueryInsertObject(callback, line, EXPECT_TODO_WINE | 1, &CLSID_NULL, NULL, REO_CP_SELECTION /* cp overriden */, S_OK); + olecb_expect_QueryInsertObject(callback, line, 1, &CLSID_NULL, NULL, REO_CP_SELECTION /* cp overriden */, S_OK); hr = IRichEditOle_GetClientSite(reole, &clientsite); ok_(__FILE__,line)(hr == S_OK, "IRichEditOle_GetClientSite got hr %#lx.\n", hr); fill_reobject_struct(reobj, cp, NULL, NULL, clientsite, 10, 10, DVASPECT_CONTENT, 0, user); @@ -3477,17 +3477,15 @@ static void subtest_InsertObject(struct IRichEditOleCallbackImpl *callback) hr = IRichEditOle_GetClientSite(reole, &clientsite); ok(hr == S_OK, "IRichEditOle_GetClientSite got hr %#lx.\n", hr);
- olecb_expect_QueryInsertObject(callback, __LINE__, EXPECT_TODO_WINE | 1, &CLSID_NULL, NULL, REO_CP_SELECTION, S_FALSE); + olecb_expect_QueryInsertObject(callback, __LINE__, 1, &CLSID_NULL, NULL, REO_CP_SELECTION, S_FALSE); fill_reobject_struct(&reobj, REO_CP_SELECTION, NULL, NULL, clientsite, 10, 10, DVASPECT_CONTENT, 0, 0); hr = IRichEditOle_InsertObject(reole, &reobj); - todo_wine ok(hr == S_FALSE, "IRichEditOle_InsertObject got hr %#lx.\n", hr); olecb_check_QueryInsertObject(callback, __LINE__);
IOleClientSite_Release(clientsite);
count = IRichEditOle_GetObjectCount(reole); - todo_wine ok(count == 3, "got wrong object count: %ld\n", count); }
On Sat, Apr 02, 2022 at 01:26:43AM +0900, Jinoh Kang wrote:
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com
Notes: v1 -> v2: - remove unused typedef storage class specifier from struct IRichEditOleCallbackImpl definition (thanks huw) - remove Hungarian notation from struct fields and callback params (thanks huw)
dlls/riched20/tests/richole.c | 247 ++++++++++++++++++++++++++++++++-- 1 file changed, 236 insertions(+), 11 deletions(-)
diff --git a/dlls/riched20/tests/richole.c b/dlls/riched20/tests/richole.c index 24284a24484..fce4e74285d 100644 --- a/dlls/riched20/tests/richole.c +++ b/dlls/riched20/tests/richole.c @@ -33,6 +33,169 @@ #include <tom.h> #include <wine/test.h>
+#define EXPECT_TODO_WINE 0x80000000UL
+struct IRichEditOleCallbackImpl {
Let's put that brace on a new line.
- IRichEditOleCallback IRichEditOleCallback_iface;
- LONG ref;
- int line;
- ULONG expect_queryinsertobject;
- const CLSID *clsid;
- LPSTORAGE stg;
IStorage *
As already mentioned, there are many more LPXXXX below.
Also some of the lines are really long, let's get them below ~120 chars. (Part of the issue is the "RichEditOleCallbackImpl_" prefix, "re_ole_cb_" would be shorter).
Huw.