From 76cf09cfea15911082245a65547fb67512b710ce Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Sat, 23 Nov 2019 12:11:20 +0100 Subject: [PATCH] [RICHED20_WINETEST] Sync with Wine Staging 4.18. CORE-16441 --- modules/rostests/winetests/riched20/editor.c | 202 ++++++--- modules/rostests/winetests/riched20/richole.c | 403 ++++++++---------- modules/rostests/winetests/riched20/txtsrv.c | 228 +++++++--- 3 files changed, 485 insertions(+), 348 deletions(-) diff --git a/modules/rostests/winetests/riched20/editor.c b/modules/rostests/winetests/riched20/editor.c index 6712ab1a150..28f9849cba0 100644 --- a/modules/rostests/winetests/riched20/editor.c +++ b/modules/rostests/winetests/riched20/editor.c @@ -340,14 +340,12 @@ static void test_EM_FINDTEXT(BOOL unicode) hwndRichEdit = new_richedit(NULL); /* Empty rich edit control */ - run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests, - sizeof(find_tests)/sizeof(struct find_s), unicode); + run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests, ARRAY_SIZE(find_tests), unicode); SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)haystack); /* Haystack text */ - run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2, - sizeof(find_tests2)/sizeof(struct find_s), unicode); + run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2, ARRAY_SIZE(find_tests2), unicode); /* Setting a format on an arbitrary range should have no effect in search results. This tests correct offset reporting across runs. */ @@ -359,8 +357,7 @@ static void test_EM_FINDTEXT(BOOL unicode) SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); /* Haystack text, again */ - run_tests_EM_FINDTEXT(hwndRichEdit, "2-bis", find_tests2, - sizeof(find_tests2)/sizeof(struct find_s), unicode); + run_tests_EM_FINDTEXT(hwndRichEdit, "2-bis", find_tests2, ARRAY_SIZE(find_tests2), unicode); /* Yet another range */ cf2.dwMask = CFM_BOLD | cf2.dwMask; @@ -369,8 +366,7 @@ static void test_EM_FINDTEXT(BOOL unicode) SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); /* Haystack text, again */ - run_tests_EM_FINDTEXT(hwndRichEdit, "2-bisbis", find_tests2, - sizeof(find_tests2)/sizeof(struct find_s), unicode); + run_tests_EM_FINDTEXT(hwndRichEdit, "2-bisbis", find_tests2, ARRAY_SIZE(find_tests2), unicode); DestroyWindow(hwndRichEdit); } @@ -404,7 +400,7 @@ static void test_EM_GETLINE(void) SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text); memset(origdest, 0xBB, nBuf); - for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++) + for (i = 0; i < ARRAY_SIZE(gl); i++) { int nCopied; int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text)); @@ -509,7 +505,7 @@ static void test_EM_LINELENGTH(void) {15, 4}, /* Line 3: |wine */ }; SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1); - for (i = 0; i < sizeof(offset_test1)/sizeof(offset_test1[0]); i++) { + for (i = 0; i < ARRAY_SIZE(offset_test1); i++) { result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test1[i][0], 0); ok(result == offset_test1[i][1], "Length of line at offset %d is %ld, expected %d\n", offset_test1[i][0], result, offset_test1[i][1]); @@ -755,6 +751,8 @@ static void test_EM_SETCHARFORMAT(void) HWND hwndRichEdit = new_richedit(NULL); CHARFORMAT2A cf2; CHARFORMAT2W cfW; + CHARFORMATA cf1a; + CHARFORMATW cf1w; int rc = 0; int tested_effects[] = { CFE_BOLD, @@ -1342,6 +1340,23 @@ static void test_EM_SETCHARFORMAT(void) ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects); ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType); + /* Check setting CFM_ALL2/CFM_EFFECTS2 in CHARFORMAT(A/W). */ + memset(&cf1a, 0, sizeof(CHARFORMATA)); + memset(&cf1w, 0, sizeof(CHARFORMATW)); + cf1a.cbSize = sizeof(CHARFORMATA); + cf1w.cbSize = sizeof(CHARFORMATW); + cf1a.dwMask = cf1w.dwMask = CFM_ALL2; + cf1a.dwEffects = cf1w.dwEffects = CFM_EFFECTS2; + SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1a); + SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1a); + /* flags only valid for CHARFORMAT2 should be masked out */ + ok((cf1a.dwMask & (CFM_ALL2 & ~CFM_ALL)) == 0, "flags were not masked out\n"); + ok((cf1a.dwEffects & (CFM_EFFECTS2 & ~CFM_EFFECTS)) == 0, "flags were not masked out\n"); + SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1w); + SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1w); + ok((cf1w.dwMask & (CFM_ALL2 & ~CFM_ALL)) == 0, "flags were not masked out\n"); + ok((cf1w.dwEffects & (CFM_EFFECTS2 & ~CFM_EFFECTS)) == 0, "flags were not masked out\n"); + DestroyWindow(hwndRichEdit); } @@ -2049,7 +2064,7 @@ static void test_EM_AUTOURLDETECT(void) urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h"); ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet); /* for each url, check the text to see if CFE_LINK effect is present */ - for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) { + for (i = 0; i < ARRAY_SIZE(urls); i++) { SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0); SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)urls[i].text); @@ -2063,10 +2078,10 @@ static void test_EM_AUTOURLDETECT(void) DestroyWindow(hwndRichEdit); /* Test detection of URLs within normal text - WM_SETTEXT case. */ - for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) { + for (i = 0; i < ARRAY_SIZE(urls); i++) { hwndRichEdit = new_richedit(parent); - for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { + for (j = 0; j < ARRAY_SIZE(templates_delim); j++) { char * at_pos; int at_offset; int end_offset; @@ -2117,7 +2132,7 @@ static void test_EM_AUTOURLDETECT(void) } } - for (j = 0; j < sizeof(templates_non_delim) / sizeof(const char *); j++) { + for (j = 0; j < ARRAY_SIZE(templates_non_delim); j++) { char * at_pos; int at_offset; int end_offset; @@ -2158,7 +2173,7 @@ static void test_EM_AUTOURLDETECT(void) } } - for (j = 0; j < sizeof(templates_xten_delim) / sizeof(const char *); j++) { + for (j = 0; j < ARRAY_SIZE(templates_xten_delim); j++) { char * at_pos; int at_offset; int end_offset; @@ -2213,7 +2228,7 @@ static void test_EM_AUTOURLDETECT(void) } } - for (j = 0; j < sizeof(templates_neutral_delim) / sizeof(const char *); j++) { + for (j = 0; j < ARRAY_SIZE(templates_neutral_delim); j++) { char * at_pos, * end_pos; int at_offset; int end_offset; @@ -2421,7 +2436,7 @@ static void test_EM_AUTOURLDETECT(void) */ /* Set entire text in one go, like WM_SETTEXT */ - for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { + for (j = 0; j < ARRAY_SIZE(templates_delim); j++) { char * at_pos; int at_offset; int end_offset; @@ -2476,7 +2491,7 @@ static void test_EM_AUTOURLDETECT(void) } /* Set selection with X to the URL */ - for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { + for (j = 0; j < ARRAY_SIZE(templates_delim); j++) { char * at_pos; int at_offset; int end_offset; @@ -2530,7 +2545,7 @@ static void test_EM_AUTOURLDETECT(void) } /* Set selection with X to the first character of the URL, then the rest */ - for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { + for (j = 0; j < ARRAY_SIZE(templates_delim); j++) { char * at_pos; int at_offset; int end_offset; @@ -2598,7 +2613,7 @@ static void test_EM_AUTOURLDETECT(void) hwndRichEdit = new_richedit(parent); /* Set selection with X to the URL */ - for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { + for (j = 0; j < ARRAY_SIZE(templates_delim); j++) { char * at_pos; int at_offset; int end_offset; @@ -2649,7 +2664,7 @@ static void test_EM_AUTOURLDETECT(void) } /* Set selection with X to the first character of the URL, then the rest */ - for (j = 0; j < sizeof(templates_delim) / sizeof(const char *); j++) { + for (j = 0; j < ARRAY_SIZE(templates_delim); j++) { char * at_pos; int at_offset; int end_offset; @@ -4933,7 +4948,7 @@ static void test_EM_EXSETSEL(void) { HWND hwndRichEdit = new_richedit(NULL); int i; - const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s); + const int num_tests = ARRAY_SIZE(exsetsel_tests); /* sending some text to the window */ SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection"); @@ -4955,7 +4970,7 @@ static void test_EM_EXSETSEL(void) /* Test with multibyte character */ SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk"); /* 012345 6 78901 */ - cr.cpMin = 4, cr.cpMax = 8; + cr.cpMin = 4; cr.cpMax = 8; result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); ok(result == 8, "EM_EXSETSEL return %ld expected 8\n", result); result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(bufA), (LPARAM)bufA); @@ -4988,7 +5003,7 @@ static void test_EM_SETSEL(void) char buffA[32] = {0}; HWND hwndRichEdit = new_richedit(NULL); int i; - const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s); + const int num_tests = ARRAY_SIZE(exsetsel_tests); /* sending some text to the window */ SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection"); @@ -5623,7 +5638,7 @@ static void test_EM_FORMATRANGE(void) SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, 0); - for (i = 0; i < sizeof(fmtstrings)/sizeof(fmtstrings[0]); i++) + for (i = 0; i < ARRAY_SIZE(fmtstrings); i++) { GETTEXTLENGTHEX gtl; SIZE stringsize; @@ -5758,6 +5773,30 @@ static DWORD CALLBACK test_EM_STREAMIN_esCallback_UTF8Split(DWORD_PTR dwCookie, return 0; } +static DWORD CALLBACK test_EM_STREAMIN_null_bytes(DWORD_PTR cookie, BYTE *buf, LONG size, LONG *written) +{ + DWORD *phase = (DWORD *)cookie; + + if (*phase == 0) + { + static const char first[] = "{\\rtf1\\ansi{Th\0is"; + *written = sizeof(first); + memcpy(buf, first, *written); + } + else if (*phase == 1) + { + static const char second[] = " is a test}}"; + *written = sizeof(second); + memcpy(buf, second, *written); + } + else + *written = 0; + + ++*phase; + + return 0; +} + struct StringWithLength { int length; char *buffer; @@ -5831,7 +5870,7 @@ static void test_EM_STREAMIN(void) }; const WCHAR streamText5[] = { 'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't' }; - int length5 = sizeof(streamText5) / sizeof(WCHAR); + int length5 = ARRAY_SIZE(streamText5); struct StringWithLength cookieForStream5 = { sizeof(streamText5), (char *)streamText5, @@ -6044,6 +6083,17 @@ static void test_EM_STREAMIN(void) result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); ok (!strcmp(buffer, "line1"), "EM_STREAMIN: Unexpected text '%s'\n", buffer); + + /* Test 0-bytes inside text */ + hwndRichEdit = new_richedit_with_style(NULL, 0); + phase = 0; + es.dwCookie = (DWORD_PTR)&phase; + es.dwError = 0; + es.pfnCallback = test_EM_STREAMIN_null_bytes; + result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); + ok(result == 16, "got %ld, expected %d\n", result, 16); + result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer); + ok (!strcmp(buffer, "Th is is a test"), "EM_STREAMIN: Unexpected text '%s'\n", buffer); } static void test_EM_StreamIn_Undo(void) @@ -6868,7 +6918,7 @@ static void test_EN_LINK(void) GetCursorPos(&orig_cursor_pos); SetCursorPos(0, 0); - for (i = 0; i < sizeof(link_notify_tests)/sizeof(link_notify_tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(link_notify_tests); i++) { link_notify_test("cursor position simulated", i, hwnd, parent, link_notify_tests[i].msg, link_notify_tests[i].wParam, link_notify_tests[i].lParam, @@ -6878,7 +6928,7 @@ static void test_EN_LINK(void) ClientToScreen(hwnd, &cursor_screen_pos); SetCursorPos(cursor_screen_pos.x, cursor_screen_pos.y); - for (i = 0; i < sizeof(link_notify_tests)/sizeof(link_notify_tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(link_notify_tests); i++) { link_notify_test("cursor position set", i, hwnd, parent, link_notify_tests[i].msg, link_notify_tests[i].wParam, link_notify_tests[i].lParam, @@ -8178,7 +8228,7 @@ static void test_EM_FINDWORDBREAK_W(void) int i; HWND hwndRichEdit = new_richeditW(NULL); ok(IsWindowUnicode(hwndRichEdit), "window should be unicode\n"); - for (i = 0; i < sizeof(delimiter_tests)/sizeof(delimiter_tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(delimiter_tests); i++) { WCHAR wbuf[2]; int result; @@ -8212,7 +8262,7 @@ static void test_EM_FINDWORDBREAK_A(void) HWND hwndRichEdit = new_richedit(NULL); ok(!IsWindowUnicode(hwndRichEdit), "window should not be unicode\n"); - for (i = 0; i < sizeof(delimiter_tests)/sizeof(delimiter_tests[0]); i++) + for (i = 0; i < ARRAY_SIZE(delimiter_tests); i++) { int result; char buf[2]; @@ -8228,12 +8278,21 @@ static void test_EM_FINDWORDBREAK_A(void) DestroyWindow(hwndRichEdit); } +static void format_test_result(char *target, const char *src) +{ + int i; + for (i = 0; i < strlen(src); i++) + sprintf(target + 2*i, "%02x", src[i] & 0xFF); + target[2*i] = 0; +} + /* * This test attempts to show the effect of enter on a richedit * control v1.0 inserts CRLF whereas for higher versions it only * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT * and also shows that GT_USECRLF has no effect in richedit 1.0, but * does for higher. The same test is cloned in riched32 and riched20. + * Also shows the difference between WM_CHAR/WM_KEYDOWN in v1.0 and higher versions */ static void test_enter(void) { @@ -8254,15 +8313,14 @@ static void test_enter(void) char expectedbuf[1024]; char resultbuf[1024]; HWND hwndRichEdit = new_richedit(NULL); - UINT i,j; - - for (i = 0; i < sizeof(testenteritems)/sizeof(testenteritems[0]); i++) { - - char buf[1024] = {0}; - LRESULT result; - GETTEXTEX getText; - const char *expected; + UINT i; + char buf[1024] = {0}; + GETTEXTEX getText = {sizeof(buf)}; + LRESULT result; + const char *expected; + for (i = 0; i < ARRAY_SIZE(testenteritems); i++) + { /* Set the text to the initial text */ result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)testenteritems[i].initialtext); ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result); @@ -8276,12 +8334,8 @@ static void test_enter(void) result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); expected = testenteritems[i].expectedwmtext; - resultbuf[0]=0x00; - for (j = 0; j < (UINT)result; j++) - sprintf(resultbuf+strlen(resultbuf), "%02x", buf[j] & 0xFF); - expectedbuf[0] = '\0'; - for (j = 0; j < strlen(expected); j++) - sprintf(expectedbuf+strlen(expectedbuf), "%02x", expected[j] & 0xFF); + format_test_result(resultbuf, buf); + format_test_result(expectedbuf, expected); result = strcmp(expected, buf); ok (result == 0, @@ -8289,21 +8343,14 @@ static void test_enter(void) i, resultbuf, expectedbuf); /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */ - getText.cb = sizeof(buf); getText.flags = GT_DEFAULT; - getText.codepage = CP_ACP; - getText.lpDefaultChar = NULL; - getText.lpUsedDefChar = NULL; + getText.codepage = CP_ACP; buf[0] = 0x00; result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); expected = testenteritems[i].expectedemtext; - resultbuf[0]=0x00; - for (j = 0; j < (UINT)result; j++) - sprintf(resultbuf+strlen(resultbuf), "%02x", buf[j] & 0xFF); - expectedbuf[0] = '\0'; - for (j = 0; j < strlen(expected); j++) - sprintf(expectedbuf+strlen(expectedbuf), "%02x", expected[j] & 0xFF); + format_test_result(resultbuf, buf); + format_test_result(expectedbuf, expected); result = strcmp(expected, buf); ok (result == 0, @@ -8311,21 +8358,14 @@ static void test_enter(void) i, resultbuf, expectedbuf); /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */ - getText.cb = sizeof(buf); getText.flags = GT_USECRLF; - getText.codepage = CP_ACP; - getText.lpDefaultChar = NULL; - getText.lpUsedDefChar = NULL; + getText.codepage = CP_ACP; buf[0] = 0x00; result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); expected = testenteritems[i].expectedemtextcrlf; - resultbuf[0]=0x00; - for (j = 0; j < (UINT)result; j++) - sprintf(resultbuf+strlen(resultbuf), "%02x", buf[j] & 0xFF); - expectedbuf[0] = '\0'; - for (j = 0; j < strlen(expected); j++) - sprintf(expectedbuf+strlen(expectedbuf), "%02x", expected[j] & 0xFF); + format_test_result(resultbuf, buf); + format_test_result(expectedbuf, expected); result = strcmp(expected, buf); ok (result == 0, @@ -8333,6 +8373,34 @@ static void test_enter(void) i, resultbuf, expectedbuf); } + /* Show that WM_CHAR is handled differently from WM_KEYDOWN */ + getText.flags = GT_DEFAULT; + getText.codepage = CP_ACP; + + result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); + ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result); + SendMessageW(hwndRichEdit, WM_CHAR, 'T', 0); + SendMessageW(hwndRichEdit, WM_KEYDOWN, VK_RETURN, 0); + + result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); + ok(result == 2, "Got %d\n", (int)result); + format_test_result(resultbuf, buf); + format_test_result(expectedbuf, "T\r"); + result = strcmp(resultbuf, expectedbuf); + ok (result == 0, "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", i, resultbuf, expectedbuf); + + result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)""); + ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result); + SendMessageW(hwndRichEdit, WM_CHAR, 'T', 0); + SendMessageW(hwndRichEdit, WM_CHAR, '\r', 0); + + result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf); + ok(result == 1, "Got %d\n", (int)result); + format_test_result(resultbuf, buf); + format_test_result(expectedbuf, "T"); + result = strcmp(resultbuf, expectedbuf); + ok (result == 0, "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", i, resultbuf, expectedbuf); + DestroyWindow(hwndRichEdit); } @@ -8538,7 +8606,7 @@ static void test_alignment_style(void) EDITSTREAM es; int i; - for (i = 0; i < sizeof(align_style) / sizeof(align_style[0]); i++) + for (i = 0; i < ARRAY_SIZE(align_style); i++) { DWORD dwStyle, new_align; @@ -8646,8 +8714,8 @@ static void test_rtf(void) result = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es ); ok( result == 11, "got %ld\n", result ); - result = SendMessageW( edit, WM_GETTEXT, sizeof(buf)/sizeof(buf[0]), (LPARAM)buf ); - ok( result == sizeof(expect_specials)/sizeof(expect_specials[0]), "got %ld\n", result ); + result = SendMessageW( edit, WM_GETTEXT, ARRAY_SIZE(buf), (LPARAM)buf ); + ok( result == ARRAY_SIZE(expect_specials), "got %ld\n", result ); ok( !memcmp( buf, expect_specials, sizeof(expect_specials) ), "got %s\n", wine_dbgstr_w(buf) ); /* Show that \rtlpar propagates to the second paragraph and is diff --git a/modules/rostests/winetests/riched20/richole.c b/modules/rostests/winetests/riched20/richole.c index 617d1f978bb..492bdc3fa9a 100644 --- a/modules/rostests/winetests/riched20/richole.c +++ b/modules/rostests/winetests/riched20/richole.c @@ -113,10 +113,36 @@ static ULONG get_refcount(IUnknown *iface) return IUnknown_Release(iface); } +#define CHECK_TYPEINFO(disp,expected_riid) _check_typeinfo((IDispatch *)disp, expected_riid, __LINE__) +static void _check_typeinfo(IDispatch* disp, REFIID expected_riid, int line) +{ + ITypeInfo *typeinfo; + TYPEATTR *typeattr; + UINT count; + HRESULT hr; + + count = 10; + hr = IDispatch_GetTypeInfoCount(disp, &count); + ok_(__FILE__,line)(hr == S_OK, "IDispatch_GetTypeInfoCount failed: 0x%08x.\n", hr); + ok_(__FILE__,line)(count == 1, "got wrong count: %u.\n", count); + + hr = IDispatch_GetTypeInfo(disp, 0, LOCALE_SYSTEM_DEFAULT, &typeinfo); + ok_(__FILE__,line)(hr == S_OK, "IDispatch_GetTypeInfo failed: 0x%08x.\n", hr); + + hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr); + ok_(__FILE__,line)(hr == S_OK, "ITypeInfo_GetTypeAttr failed: 0x%08x.\n", hr); + ok_(__FILE__,line)(IsEqualGUID(&typeattr->guid, expected_riid), + "Unexpected type guid: %s.\n", wine_dbgstr_guid(&typeattr->guid)); + + ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr); + ITypeInfo_Release(typeinfo); +} + static void test_Interfaces(void) { IRichEditOle *reOle = NULL, *reOle1 = NULL; ITextDocument *txtDoc = NULL; + ITextDocument2Old *txtDoc2Old = NULL; ITextSelection *txtSel = NULL, *txtSel2; IUnknown *punk; HRESULT hres; @@ -144,6 +170,7 @@ static void test_Interfaces(void) (void **) &txtDoc); ok(hres == S_OK, "IRichEditOle_QueryInterface\n"); ok(txtDoc != NULL, "IRichEditOle_QueryInterface\n"); + CHECK_TYPEINFO(txtDoc, &IID_ITextDocument); hres = ITextDocument_GetSelection(txtDoc, NULL); ok(hres == E_INVALIDARG, "ITextDocument_GetSelection: 0x%x\n", hres); @@ -195,6 +222,16 @@ static void test_Interfaces(void) hres = IRichEditOle_QueryInterface(reOle, &IID_IOleInPlaceSite, (void **) &punk); ok(hres == E_NOINTERFACE, "IRichEditOle_QueryInterface\n"); + hres = IRichEditOle_QueryInterface(reOle, &IID_ITextDocument2Old, (void **)&txtDoc2Old); + ok(hres == S_OK, "IRichEditOle_QueryInterface\n"); + ok(txtDoc2Old != NULL, "IRichEditOle_QueryInterface\n"); + ok((ITextDocument *)txtDoc2Old == txtDoc, "interface pointer isn't equal.\n"); + EXPECT_REF(txtDoc2Old, 5); + EXPECT_REF(reOle, 5); + CHECK_TYPEINFO(txtDoc2Old, &IID_ITextDocument); + + ITextDocument2Old_Release(txtDoc2Old); + ITextDocument_Release(txtDoc); IRichEditOle_Release(reOle); refcount = IRichEditOle_Release(reOle); @@ -207,6 +244,19 @@ static void test_Interfaces(void) ok(hres == CO_E_RELEASED, "ITextSelection after ITextDocument destroyed\n"); ITextSelection_Release(txtSel); + + w = new_richedit(NULL); + res = SendMessageA(w, EM_GETOLEINTERFACE, 0, (LPARAM)&reOle); + ok(res, "SendMessage\n"); + ok(reOle != NULL, "EM_GETOLEINTERFACE\n"); + + hres = IRichEditOle_QueryInterface(reOle, &IID_ITextDocument2Old, (void **)&txtDoc2Old); + ok(hres == S_OK, "IRichEditOle_QueryInterface failed: 0x%08x.\n", hres); + ok(txtDoc2Old != NULL, "IRichEditOle_QueryInterface\n"); + CHECK_TYPEINFO(txtDoc2Old, &IID_ITextDocument); + ITextDocument2Old_Release(txtDoc2Old); + IRichEditOle_Release(reOle); + DestroyWindow(w); } static void test_ITextDocument_Open(void) @@ -247,8 +297,8 @@ static void test_ITextDocument_Open(void) tomReadOnly|tomShareDenyWrite, tomReadOnly|tomShareDenyRead }; - int tomNumSingle = sizeof(tomConstantsSingle)/sizeof(tomConstantsSingle[0]); - int tomNumMulti = sizeof(tomConstantsMulti)/sizeof(tomConstantsMulti[0]); + int tomNumSingle = ARRAY_SIZE(tomConstantsSingle); + int tomNumMulti = ARRAY_SIZE(tomConstantsMulti); int i; V_VT(&testfile) = VT_BSTR; @@ -481,21 +531,21 @@ static void test_GetText(void) SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); /* ITextSelection */ - first = 0, lim = 4; + first = 0; lim = 4; SendMessageA(w, EM_SETSEL, first, lim); hres = ITextSelection_GetText(txtSel, &bstr); ok(hres == S_OK, "ITextSelection_GetText\n"); ok(!lstrcmpW(bstr, bufW1), "got wrong text: %s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr); - first = 4, lim = 0; + first = 4; lim = 0; SendMessageA(w, EM_SETSEL, first, lim); hres = ITextSelection_GetText(txtSel, &bstr); ok(hres == S_OK, "ITextSelection_GetText\n"); ok(!lstrcmpW(bstr, bufW1), "got wrong text: %s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr); - first = 1, lim = 1; + first = 1; lim = 1; SendMessageA(w, EM_SETSEL, first, lim); hres = ITextSelection_GetText(txtSel, &bstr); ok(hres == S_OK, "ITextSelection_GetText\n"); @@ -507,35 +557,35 @@ static void test_GetText(void) ok(hres == E_INVALIDARG, "ITextSelection_GetText\n"); } - first = 8, lim = 12; + first = 8; lim = 12; SendMessageA(w, EM_SETSEL, first, lim); hres = ITextSelection_GetText(txtSel, &bstr); ok(hres == S_OK, "ITextSelection_GetText\n"); ok(!lstrcmpW(bstr, bufW3), "got wrong text: %s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr); - first = 8, lim = 13; + first = 8; lim = 13; SendMessageA(w, EM_SETSEL, first, lim); hres = ITextSelection_GetText(txtSel, &bstr); ok(hres == S_OK, "ITextSelection_GetText\n"); ok(!lstrcmpW(bstr, bufW2), "got wrong text: %s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr); - first = 12, lim = 13; + first = 12; lim = 13; SendMessageA(w, EM_SETSEL, first, lim); hres = ITextSelection_GetText(txtSel, &bstr); ok(hres == S_OK, "ITextSelection_GetText\n"); ok(!lstrcmpW(bstr, bufW5), "got wrong text: %s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr); - first = 0, lim = -1; + first = 0; lim = -1; SendMessageA(w, EM_SETSEL, first, lim); hres = ITextSelection_GetText(txtSel, &bstr); ok(hres == S_OK, "ITextSelection_GetText\n"); ok(!lstrcmpW(bstr, bufW4), "got wrong text: %s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr); - first = -1, lim = 9; + first = -1; lim = 9; SendMessageA(w, EM_SETSEL, first, lim); hres = ITextSelection_GetText(txtSel, &bstr); ok(hres == S_OK, "ITextSelection_GetText\n"); @@ -707,7 +757,7 @@ static void test_ITextRange_GetChar(void) ITextRange_Release(txtRge); release_interfaces(&w, &reOle, &txtDoc, NULL); - first = 0, lim = 0; + first = 0; lim = 0; create_interfaces(&w, &reOle, &txtDoc, NULL); SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); hres = ITextDocument_Range(txtDoc, first, lim, &txtRge); @@ -719,7 +769,7 @@ static void test_ITextRange_GetChar(void) ITextRange_Release(txtRge); release_interfaces(&w, &reOle, &txtDoc, NULL); - first = 12, lim = 12; + first = 12; lim = 12; create_interfaces(&w, &reOle, &txtDoc, NULL); SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); hres = ITextDocument_Range(txtDoc, first, lim, &txtRge); @@ -731,7 +781,7 @@ static void test_ITextRange_GetChar(void) ITextRange_Release(txtRge); release_interfaces(&w, &reOle, &txtDoc, NULL); - first = 13, lim = 13; + first = 13; lim = 13; create_interfaces(&w, &reOle, &txtDoc, NULL); SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); hres = ITextDocument_Range(txtDoc, first, lim, &txtRge); @@ -745,7 +795,7 @@ static void test_ITextRange_GetChar(void) create_interfaces(&w, &reOle, &txtDoc, NULL); SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); - first = 12, lim = 12; + first = 12; lim = 12; hres = ITextDocument_Range(txtDoc, first, lim, &txtRge); ok(hres == S_OK, "got 0x%08x\n", hres); hres = ITextRange_GetChar(txtRge, NULL); @@ -803,15 +853,19 @@ static void test_ITextRange_ScrollIntoView(void) /* Scroll to the top. */ check_range(w, txtDoc, 0, 1, tomStart, 0); + check_range(w, txtDoc, 0, 1, tomEnd, 0); /* Scroll to the bottom. */ check_range(w, txtDoc, 19, 20, tomStart, 1); + check_range(w, txtDoc, 19, 20, tomEnd, 1); /* Back up to the top. */ check_range(w, txtDoc, 0, 1, tomStart, 0); + check_range(w, txtDoc, 0, 1, tomEnd, 0); /* Large range */ check_range(w, txtDoc, 0, 20, tomStart, 0); + check_range(w, txtDoc, 0, 20, tomEnd, 1); hres = ITextDocument_Range(txtDoc, 0, 0, &txtRge); ok(hres == S_OK, "got 0x%08x\n", hres); @@ -835,28 +889,28 @@ static void test_ITextSelection_GetChar(void) create_interfaces(&w, &reOle, &txtDoc, &txtSel); SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); - first = 0, lim = 4; + first = 0; lim = 4; SendMessageA(w, EM_SETSEL, first, lim); pch = 0xdeadbeef; hres = ITextSelection_GetChar(txtSel, &pch); ok(hres == S_OK, "ITextSelection_GetChar\n"); ok(pch == 'T', "got wrong char: %c\n", pch); - first = 0, lim = 0; + first = 0; lim = 0; SendMessageA(w, EM_SETSEL, first, lim); pch = 0xdeadbeef; hres = ITextSelection_GetChar(txtSel, &pch); ok(hres == S_OK, "ITextSelection_GetChar\n"); ok(pch == 'T', "got wrong char: %c\n", pch); - first = 12, lim = 12; + first = 12; lim = 12; SendMessageA(w, EM_SETSEL, first, lim); pch = 0xdeadbeef; hres = ITextSelection_GetChar(txtSel, &pch); ok(hres == S_OK, "ITextSelection_GetChar\n"); ok(pch == '\r', "got wrong char: %c\n", pch); - first = 13, lim = 13; + first = 13; lim = 13; SendMessageA(w, EM_SETSEL, first, lim); pch = 0xdeadbeef; hres = ITextSelection_GetChar(txtSel, &pch); @@ -890,7 +944,7 @@ static void test_ITextRange_GetStart_GetEnd(void) create_interfaces(&w, &reOle, &txtDoc, NULL); SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); - first = 1, lim = 6; + first = 1; lim = 6; hres = ITextDocument_Range(txtDoc, first, lim, &txtRge); ok(hres == S_OK, "got 0x%08x\n", hres); start = 0xdeadbeef; @@ -903,7 +957,7 @@ static void test_ITextRange_GetStart_GetEnd(void) ok(end == 6, "got wrong end value: %d\n", end); ITextRange_Release(txtRge); - first = 6, lim = 1; + first = 6; lim = 1; hres = ITextDocument_Range(txtDoc, first, lim, &txtRge); ok(hres == S_OK, "got 0x%08x\n", hres); start = 0xdeadbeef; @@ -916,7 +970,7 @@ static void test_ITextRange_GetStart_GetEnd(void) ok(end == 6, "got wrong end value: %d\n", end); ITextRange_Release(txtRge); - first = -1, lim = 13; + first = -1; lim = 13; hres = ITextDocument_Range(txtDoc, first, lim, &txtRge); ok(hres == S_OK, "got 0x%08x\n", hres); start = 0xdeadbeef; @@ -929,7 +983,7 @@ static void test_ITextRange_GetStart_GetEnd(void) ok(end == 13, "got wrong end value: %d\n", end); ITextRange_Release(txtRge); - first = 13, lim = 13; + first = 13; lim = 13; hres = ITextDocument_Range(txtDoc, first, lim, &txtRge); ok(hres == S_OK, "got 0x%08x\n", hres); start = 0xdeadbeef; @@ -1109,7 +1163,7 @@ static void test_ITextSelection_GetStart_GetEnd(void) create_interfaces(&w, &reOle, &txtDoc, &txtSel); SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); - first = 2, lim = 5; + first = 2; lim = 5; SendMessageA(w, EM_SETSEL, first, lim); start = 0xdeadbeef; hres = ITextSelection_GetStart(txtSel, &start); @@ -1120,7 +1174,7 @@ static void test_ITextSelection_GetStart_GetEnd(void) ok(hres == S_OK, "ITextSelection_GetEnd\n"); ok(end == 5, "got wrong end value: %d\n", end); - first = 5, lim = 2; + first = 5; lim = 2; SendMessageA(w, EM_SETSEL, first, lim); start = 0xdeadbeef; hres = ITextSelection_GetStart(txtSel, &start); @@ -1131,7 +1185,7 @@ static void test_ITextSelection_GetStart_GetEnd(void) ok(hres == S_OK, "ITextSelection_GetEnd\n"); ok(end == 5, "got wrong end value: %d\n", end); - first = 0, lim = -1; + first = 0; lim = -1; SendMessageA(w, EM_SETSEL, first, lim); start = 0xdeadbeef; hres = ITextSelection_GetStart(txtSel, &start); @@ -1142,7 +1196,7 @@ static void test_ITextSelection_GetStart_GetEnd(void) ok(hres == S_OK, "ITextSelection_GetEnd\n"); ok(end == 13, "got wrong end value: %d\n", end); - first = 13, lim = 13; + first = 13; lim = 13; SendMessageA(w, EM_SETSEL, first, lim); start = 0xdeadbeef; hres = ITextSelection_GetStart(txtSel, &start); @@ -1315,7 +1369,7 @@ static void test_ITextRange_GetDuplicate(void) create_interfaces(&w, &reOle, &txtDoc, NULL); SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); - first = 0, lim = 4; + first = 0; lim = 4; hres = ITextDocument_Range(txtDoc, first, lim, &txtRge); ok(hres == S_OK, "ITextDocument_Range fails 0x%x.\n", hres); @@ -1358,7 +1412,7 @@ static void test_ITextRange_Collapse(void) create_interfaces(&w, &reOle, &txtDoc, NULL); SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); - first = 4, lim = 8; + first = 4; lim = 8; hres = ITextDocument_Range(txtDoc, first, lim, &txtRge); ok(hres == S_OK, "got 0x%08x\n", hres); hres = ITextRange_Collapse(txtRge, tomTrue); @@ -1420,7 +1474,7 @@ static void test_ITextRange_Collapse(void) ok(end == 4, "got wrong end value: %d\n", end); ITextRange_Release(txtRge); - first = 6, lim = 6; + first = 6; lim = 6; hres = ITextDocument_Range(txtDoc, first, lim, &txtRge); ok(hres == S_OK, "got 0x%08x\n", hres); hres = ITextRange_Collapse(txtRge, tomEnd); @@ -1433,7 +1487,7 @@ static void test_ITextRange_Collapse(void) ok(end == 6, "got wrong end value: %d\n", end); ITextRange_Release(txtRge); - first = 8, lim = 8; + first = 8; lim = 8; hres = ITextDocument_Range(txtDoc, first, lim, &txtRge); ok(hres == S_OK, "got 0x%08x\n", hres); hres = ITextRange_Collapse(txtRge, tomStart); @@ -1469,7 +1523,7 @@ static void test_ITextSelection_Collapse(void) create_interfaces(&w, &reOle, &txtDoc, &txtSel); SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); - first = 4, lim = 8; + first = 4; lim = 8; SendMessageA(w, EM_SETSEL, first, lim); hres = ITextSelection_Collapse(txtSel, tomTrue); ok(hres == S_OK, "ITextSelection_Collapse\n"); @@ -1506,7 +1560,7 @@ static void test_ITextSelection_Collapse(void) ok(start == 4, "got wrong start value: %d\n", start); ok(end == 4, "got wrong end value: %d\n", end); - first = 6, lim = 6; + first = 6; lim = 6; SendMessageA(w, EM_SETSEL, first, lim); hres = ITextSelection_Collapse(txtSel, tomEnd); ok(hres == S_FALSE, "ITextSelection_Collapse\n"); @@ -1514,7 +1568,7 @@ static void test_ITextSelection_Collapse(void) ok(start == 6, "got wrong start value: %d\n", start); ok(end == 6, "got wrong end value: %d\n", end); - first = 8, lim = 8; + first = 8; lim = 8; SendMessageA(w, EM_SETSEL, first, lim); hres = ITextSelection_Collapse(txtSel, tomStart); ok(hres == S_FALSE, "ITextSelection_Collapse\n"); @@ -3278,6 +3332,61 @@ static void test_InsertObject(void) /* received_reo4 didn't be zeroed in E_INVALIDARG case */ CHECK_REOBJECT_STRUCT(received_reo4, NULL, NULL, reo2.polesite, 2); + SendMessageA(hwnd, EM_SETSEL, 0, 1); + received_reo4.cbStruct = sizeof(received_reo4); + received_reo4.cp = 1; + hr = IRichEditOle_GetObject(reole, REO_IOB_SELECTION, &received_reo4, REO_GETOBJ_ALL_INTERFACES); + ok(hr == S_OK, "IRichEditOle_GetObject failed: 0x%08x\n", hr); + CHECK_REOBJECT_STRUCT(received_reo4, NULL, NULL, reo1.polesite, 1); + + SendMessageA(hwnd, EM_SETSEL, 1, 2); + received_reo4.cbStruct = sizeof(received_reo4); + received_reo4.cp = 0; + hr = IRichEditOle_GetObject(reole, REO_IOB_SELECTION, &received_reo4, REO_GETOBJ_ALL_INTERFACES); + ok(hr == S_OK, "IRichEditOle_GetObject failed: 0x%08x\n", hr); + CHECK_REOBJECT_STRUCT(received_reo4, NULL, NULL, reo3.polesite, 3); + + SendMessageA(hwnd, EM_SETSEL, 2, 3); + received_reo4.cbStruct = sizeof(received_reo4); + received_reo4.cp = 0; + hr = IRichEditOle_GetObject(reole, REO_IOB_SELECTION, &received_reo4, REO_GETOBJ_ALL_INTERFACES); + ok(hr == S_OK, "IRichEditOle_GetObject failed: 0x%08x\n", hr); + CHECK_REOBJECT_STRUCT(received_reo4, NULL, NULL, reo2.polesite, 2); + + SendMessageA(hwnd, EM_SETSEL, 0, 2); + received_reo4.cbStruct = sizeof(received_reo4); + received_reo4.cp = 0; + hr = IRichEditOle_GetObject(reole, REO_IOB_SELECTION, &received_reo4, REO_GETOBJ_ALL_INTERFACES); + ok(hr == S_OK, "IRichEditOle_GetObject failed: 0x%08x\n", hr); + CHECK_REOBJECT_STRUCT(received_reo4, NULL, NULL, reo1.polesite, 1); + + SendMessageA(hwnd, EM_SETSEL, 1, 3); + received_reo4.cbStruct = sizeof(received_reo4); + received_reo4.cp = 0; + hr = IRichEditOle_GetObject(reole, REO_IOB_SELECTION, &received_reo4, REO_GETOBJ_ALL_INTERFACES); + ok(hr == S_OK, "IRichEditOle_GetObject failed: 0x%08x\n", hr); + CHECK_REOBJECT_STRUCT(received_reo4, NULL, NULL, reo3.polesite, 3); + + SendMessageA(hwnd, EM_SETSEL, 2, 0); + received_reo4.cbStruct = sizeof(received_reo4); + received_reo4.cp = 0; + hr = IRichEditOle_GetObject(reole, REO_IOB_SELECTION, &received_reo4, REO_GETOBJ_ALL_INTERFACES); + ok(hr == S_OK, "IRichEditOle_GetObject failed: 0x%08x\n", hr); + CHECK_REOBJECT_STRUCT(received_reo4, NULL, NULL, reo1.polesite, 1); + + SendMessageA(hwnd, EM_SETSEL, 0, 6); + received_reo4.cbStruct = sizeof(received_reo4); + received_reo4.cp = 0; + hr = IRichEditOle_GetObject(reole, REO_IOB_SELECTION, &received_reo4, REO_GETOBJ_ALL_INTERFACES); + ok(hr == S_OK, "IRichEditOle_GetObject failed: 0x%08x\n", hr); + CHECK_REOBJECT_STRUCT(received_reo4, NULL, NULL, reo1.polesite, 1); + + SendMessageA(hwnd, EM_SETSEL, 4, 5); + received_reo4.cbStruct = sizeof(received_reo4); + received_reo4.cp = 0; + hr = IRichEditOle_GetObject(reole, REO_IOB_SELECTION, &received_reo4, REO_GETOBJ_ALL_INTERFACES); + ok(hr == E_INVALIDARG, "IRichEditOle_GetObject should fail: 0x%08x\n", hr); + release_interfaces(&hwnd, &reole, &doc, NULL); } @@ -3481,6 +3590,51 @@ static void _check_selection(ITextSelection *selection, LONG expected_start, LON expected_end, value); } +static void test_ITextRange_SetRange(void) +{ + static const CHAR test_text1[] = "TestSomeText"; + ITextDocument *txtDoc = NULL; + IRichEditOle *reOle = NULL; + ITextRange *txtRge = NULL; + HRESULT hr; + HWND w; + + create_interfaces(&w, &reOle, &txtDoc, NULL); + SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); + ITextDocument_Range(txtDoc, 0, 0, &txtRge); + + hr = ITextRange_SetRange(txtRge, 2, 4); + ok(hr == S_OK, "got 0x%08x.\n", hr); + CHECK_RANGE(txtRge, 2, 4); + + hr = ITextRange_SetRange(txtRge, 2, 4); + ok(hr == S_FALSE, "got 0x%08x.\n", hr); + CHECK_RANGE(txtRge, 2, 4); + + hr = ITextRange_SetRange(txtRge, 4, 2); + ok(hr == S_FALSE, "got 0x%08x.\n", hr); + CHECK_RANGE(txtRge, 2, 4); + + hr = ITextRange_SetRange(txtRge, 14, 14); + ok(hr == S_OK, "got 0x%08x.\n", hr); + CHECK_RANGE(txtRge, 12, 12); + + hr = ITextRange_SetRange(txtRge, 15, 15); + ok(hr == S_FALSE, "got 0x%08x.\n", hr); + CHECK_RANGE(txtRge, 12, 12); + + hr = ITextRange_SetRange(txtRge, 14, 1); + ok(hr == S_OK, "got 0x%08x.\n", hr); + CHECK_RANGE(txtRge, 1, 13); + + hr = ITextRange_SetRange(txtRge, -1, 4); + ok(hr == S_OK, "got 0x%08x.\n", hr); + CHECK_RANGE(txtRge, 0, 4); + + ITextRange_Release(txtRge); + release_interfaces(&w, &reOle, &txtDoc, NULL); +} + static void test_Expand(void) { static const char test_text1[] = "TestSomeText"; @@ -3922,183 +4076,6 @@ static void test_ITextRange_GetPara(void) ITextPara_Release(txtPara); } -static void test_ITextRange_GetText(void) -{ - HWND w; - IRichEditOle *reOle = NULL; - ITextDocument *txtDoc = NULL; - ITextRange *txtRge = NULL; - HRESULT hres; - BSTR bstr = NULL; - static const CHAR test_text1[] = "TestSomeText"; - static const WCHAR bufW1[] = {'T', 'e', 's', 't', 0}; - static const WCHAR bufW2[] = {'T', 'e', 'x', 't', '\r', 0}; - static const WCHAR bufW3[] = {'T', 'e', 'x', 't', 0}; - static const WCHAR bufW4[] = {'T', 'e', 's', 't', 'S', 'o', 'm', - 'e', 'T', 'e', 'x', 't', '\r', 0}; - static const WCHAR bufW5[] = {'\r', 0}; - - -#define TEST_TXTRGE_GETTEXT(first, lim, expected_string) \ - create_interfaces(&w, &reOle, &txtDoc, NULL); \ - SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); \ - ITextDocument_Range(txtDoc, first, lim, &txtRge); \ - hres = ITextRange_GetText(txtRge, &bstr); \ - ok(hres == S_OK, "ITextRange_GetText\n"); \ - ok(!lstrcmpW(bstr, expected_string), "got wrong text: %s\n", wine_dbgstr_w(bstr)); \ - SysFreeString(bstr); \ - ITextRange_Release(txtRge); \ - release_interfaces(&w, &reOle, &txtDoc, NULL); - - TEST_TXTRGE_GETTEXT(0, 4, bufW1) - TEST_TXTRGE_GETTEXT(4, 0, bufW1) - TEST_TXTRGE_GETTEXT(8, 12, bufW3) - TEST_TXTRGE_GETTEXT(8, 13, bufW2) - TEST_TXTRGE_GETTEXT(12, 13, bufW5) - TEST_TXTRGE_GETTEXT(0, 13, bufW4) - TEST_TXTRGE_GETTEXT(1, 1, NULL) -} - -static void test_ITextRange_SetRange(void) -{ - HWND w; - IRichEditOle *reOle = NULL; - ITextDocument *txtDoc = NULL; - ITextRange *txtRge = NULL; - HRESULT hres; - int start, end; - static const CHAR test_text1[] = "TestSomeText"; - - create_interfaces(&w, &reOle, &txtDoc, NULL); - SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); - ITextDocument_Range(txtDoc, 0, 0, &txtRge); - -#define TEST_TXTRGE_SETRANGE(first, lim, expected_start, expected_end, expected_return) \ - hres = ITextRange_SetRange(txtRge, first, lim); \ - ok(hres == expected_return, "ITextRange_SetRange\n"); \ - ITextRange_GetStart(txtRge, &start); \ - ITextRange_GetEnd(txtRge, &end); \ - ok(start == expected_start, "got wrong start value: %d\n", start); \ - ok(end == expected_end, "got wrong end value: %d\n", end); - - TEST_TXTRGE_SETRANGE(2, 4, 2, 4, S_OK) - TEST_TXTRGE_SETRANGE(2, 4, 2, 4, S_FALSE) - TEST_TXTRGE_SETRANGE(4, 2, 2, 4, S_FALSE) - TEST_TXTRGE_SETRANGE(14, 14, 12, 12, S_OK) - TEST_TXTRGE_SETRANGE(15, 15, 12, 12, S_FALSE) - TEST_TXTRGE_SETRANGE(14, 1, 1, 13, S_OK) - TEST_TXTRGE_SETRANGE(-1, 4, 0, 4, S_OK) - - ITextRange_Release(txtRge); - release_interfaces(&w, &reOle, &txtDoc, NULL); -} - -static void test_ITextRange_IsEqual2(void) -{ - HWND w; - IRichEditOle *reOle = NULL; - ITextDocument *txtDoc = NULL; - ITextRange *txtRge1 = NULL, *txtRge2 = NULL; - HRESULT hres; - static const CHAR test_text1[] = "TestSomeText"; - LONG res; - - create_interfaces(&w, &reOle, &txtDoc, NULL); - SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); - ITextDocument_Range(txtDoc, 2, 4, &txtRge1); - ITextDocument_Range(txtDoc, 2, 4, &txtRge2); - -#define TEST_TXTRGE_ISEQUAL(expected_hres, expected_res) \ - hres = ITextRange_IsEqual(txtRge1, txtRge2, &res); \ - ok(hres == expected_hres, "ITextRange_IsEqual\n"); \ - ok(res == expected_res, "got wrong return value: %d\n", res); - - TEST_TXTRGE_ISEQUAL(S_OK, tomTrue) - ITextRange_SetRange(txtRge2, 1, 2); - TEST_TXTRGE_ISEQUAL(S_FALSE, tomFalse) - - ITextRange_SetRange(txtRge1, 1, 1); - ITextRange_SetRange(txtRge2, 2, 2); - TEST_TXTRGE_ISEQUAL(S_FALSE, tomFalse) - - ITextRange_SetRange(txtRge2, 1, 1); - TEST_TXTRGE_ISEQUAL(S_OK, tomTrue) - - hres = ITextRange_IsEqual(txtRge1, txtRge1, &res); - ok(hres == S_OK, "ITextRange_IsEqual\n"); - ok(res == tomTrue, "got wrong return value: %d\n", res); - - hres = ITextRange_IsEqual(txtRge1, txtRge2, NULL); - ok(hres == S_OK, "ITextRange_IsEqual\n"); - - hres = ITextRange_IsEqual(txtRge1, NULL, NULL); - ok(hres == S_FALSE, "ITextRange_IsEqual\n"); - - ITextRange_Release(txtRge1); - ITextRange_Release(txtRge2); - release_interfaces(&w, &reOle, &txtDoc, NULL); -} - -static void test_ITextRange_GetStoryLength(void) -{ - HWND w; - IRichEditOle *reOle = NULL; - ITextDocument *txtDoc = NULL; - ITextRange *txtRge = NULL; - HRESULT hres; - LONG count; - static const CHAR test_text1[] = "TestSomeText"; - int len = strlen(test_text1) + 1; - - create_interfaces(&w, &reOle, &txtDoc, NULL); - SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); - ITextDocument_Range(txtDoc, 0, 0, &txtRge); - - hres = ITextRange_GetStoryLength(txtRge, &count); - ok(hres == S_OK, "ITextRange_GetStoryLength\n"); - ok(count == len, "got wrong length: %d\n", count); - - ITextRange_SetRange(txtRge, 1, 2); - hres = ITextRange_GetStoryLength(txtRge, &count); - ok(hres == S_OK, "ITextRange_GetStoryLength\n"); - ok(count == len, "got wrong length: %d\n", count); - - hres = ITextRange_GetStoryLength(txtRge, NULL); - ok(hres == E_INVALIDARG, "ITextRange_GetStoryLength\n"); - - ITextRange_Release(txtRge); - release_interfaces(&w, &reOle, &txtDoc, NULL); -} - -static void test_ITextSelection_GetStoryLength(void) -{ - HWND w; - IRichEditOle *reOle = NULL; - ITextDocument *txtDoc = NULL; - ITextSelection *txtSel = NULL; - HRESULT hres; - LONG count; - static const CHAR test_text1[] = "TestSomeText"; - int len = strlen(test_text1) + 1; - - create_interfaces(&w, &reOle, &txtDoc, &txtSel); - SendMessageA(w, WM_SETTEXT, 0, (LPARAM)test_text1); - - hres = ITextSelection_GetStoryLength(txtSel, &count); - ok(hres == S_OK, "ITextSelection_GetStoryLength\n"); - ok(count == len, "got wrong length: %d\n", count); - - SendMessageA(w, EM_SETSEL, 1, 2); - hres = ITextSelection_GetStoryLength(txtSel, &count); - ok(hres == S_OK, "ITextSelection_GetStoryLength\n"); - ok(count == len, "got wrong length: %d\n", count); - - hres = ITextSelection_GetStoryLength(txtSel, NULL); - ok(hres == E_INVALIDARG, "ITextSelection_GetStoryLength\n"); - - release_interfaces(&w, &reOle, &txtDoc, &txtSel); -} - START_TEST(richole) { /* Must explicitly LoadLibrary(). The test has no references to functions in @@ -4115,21 +4092,17 @@ START_TEST(richole) test_ITextSelection_SetEnd(); test_ITextSelection_Collapse(); test_ITextSelection_GetFont(); - test_ITextSelection_GetStoryLength(); test_ITextDocument_Range(); test_ITextRange_GetChar(); test_ITextRange_ScrollIntoView(); test_ITextRange_GetStart_GetEnd(); + test_ITextRange_SetRange(); test_ITextRange_GetDuplicate(); test_ITextRange_SetStart(); test_ITextRange_SetEnd(); test_ITextRange_Collapse(); test_ITextRange_GetFont(); test_ITextRange_GetPara(); - test_ITextRange_GetText(); - test_ITextRange_SetRange(); - test_ITextRange_IsEqual2(); - test_ITextRange_GetStoryLength(); test_GetClientSite(); test_IOleWindow_GetWindow(); test_IOleInPlaceSite_GetWindow(); diff --git a/modules/rostests/winetests/riched20/txtsrv.c b/modules/rostests/winetests/riched20/txtsrv.c index 88b5adf13cc..5a59c871815 100644 --- a/modules/rostests/winetests/riched20/txtsrv.c +++ b/modules/rostests/winetests/riched20/txtsrv.c @@ -48,7 +48,7 @@ static PCreateTextServices pCreateTextServices; /* Use a special table for x86 machines to convert the thiscall * calling convention. This isn't needed on other platforms. */ -#ifdef __i386__ +#if defined(__i386__) && !defined(__MINGW32__) static ITextServicesVtbl itextServicesStdcallVtbl; #define TXTSERV_VTABLE(This) (&itextServicesStdcallVtbl) #else /* __i386__ */ @@ -85,6 +85,7 @@ typedef struct ITextHostTestImpl { ITextHost ITextHost_iface; LONG refCount; + CHARFORMAT2W char_format; } ITextHostTestImpl; static inline ITextHostTestImpl *impl_from_ITextHost(ITextHost *iface) @@ -534,7 +535,7 @@ typedef struct static void setup_thiscall_wrappers(void) { -#ifdef __i386__ +#if defined(__i386__) && !defined(__MINGW32__) void** pVtable; void** pVtableEnd; THISCALL_TO_STDCALL_THUNK *thunk; @@ -600,6 +601,21 @@ static void setup_thiscall_wrappers(void) #endif /* __i386__ */ } +static void hf_to_cf(HFONT hf, CHARFORMAT2W *cf) +{ + LOGFONTW lf; + + GetObjectW(hf, sizeof(lf), &lf); + lstrcpyW(cf->szFaceName, lf.lfFaceName); + cf->yHeight = MulDiv(abs(lf.lfHeight), 1440, GetDeviceCaps(GetDC(NULL), LOGPIXELSY)); + if (lf.lfWeight > FW_NORMAL) cf->dwEffects |= CFE_BOLD; + if (lf.lfItalic) cf->dwEffects |= CFE_ITALIC; + if (lf.lfUnderline) cf->dwEffects |= CFE_UNDERLINE; + if (lf.lfStrikeOut) cf->dwEffects |= CFE_SUBSCRIPT; + cf->bPitchAndFamily = lf.lfPitchAndFamily; + cf->bCharSet = lf.lfCharSet; +} + /*************************************************************************/ /* Conformance test functions. */ @@ -609,6 +625,7 @@ static BOOL init_texthost(ITextServices **txtserv, ITextHost **ret) ITextHostTestImpl *dummyTextHost; IUnknown *init; HRESULT result; + HFONT hf; dummyTextHost = CoTaskMemAlloc(sizeof(*dummyTextHost)); if (dummyTextHost == NULL) { @@ -617,6 +634,11 @@ static BOOL init_texthost(ITextServices **txtserv, ITextHost **ret) } dummyTextHost->ITextHost_iface.lpVtbl = &itextHostVtbl; dummyTextHost->refCount = 1; + memset(&dummyTextHost->char_format, 0, sizeof(dummyTextHost->char_format)); + dummyTextHost->char_format.cbSize = sizeof(dummyTextHost->char_format); + dummyTextHost->char_format.dwMask = CFM_ALL2; + hf = GetStockObject(DEFAULT_GUI_FONT); + hf_to_cf(hf, &dummyTextHost->char_format); /* MSDN states that an IUnknown object is returned by CreateTextServices which is then queried to obtain a @@ -682,6 +704,8 @@ static void test_TxSetText(void) ok(memcmp(rettext,settext,SysStringByteLen(rettext)) == 0, "String returned differs\n"); + SysFreeString(rettext); + /* Null-pointer should behave the same as empty-string */ hres = ITextServices_TxSetText(txtserv, 0); @@ -697,81 +721,68 @@ static void test_TxSetText(void) ITextHost_Release(host); } +#define CHECK_TXGETNATURALSIZE(res,width,height,hdc,rect,string) \ + _check_txgetnaturalsize(res, width, height, hdc, rect, string, __LINE__) +static void _check_txgetnaturalsize(HRESULT res, LONG width, LONG height, HDC hdc, RECT rect, LPCWSTR string, int line) +{ + RECT expected_rect = rect; + LONG expected_width, expected_height; + + DrawTextW(hdc, string, -1, &expected_rect, DT_LEFT | DT_CALCRECT | DT_NOCLIP | DT_EDITCONTROL | DT_WORDBREAK); + expected_width = expected_rect.right - expected_rect.left; + expected_height = expected_rect.bottom - expected_rect.top; + ok_(__FILE__,line)(res == S_OK, "ITextServices_TxGetNaturalSize failed: 0x%08x.\n", res); + ok_(__FILE__,line)(width >= expected_width && width <= expected_width + 1, + "got wrong width: %d, expected: %d {+1}.\n", width, expected_width); + ok_(__FILE__,line)(height == expected_height, "got wrong height: %d, expected: %d.\n", + height, expected_height); +} + static void test_TxGetNaturalSize(void) { ITextServices *txtserv; ITextHost *host; HRESULT result; - BOOL ret; - - /* This value is used when calling TxGetNaturalSize. MSDN says - that this is not supported however a null pointer cannot be - used as it will cause a segmentation violation. The values in - the structure being pointed to are required to be INT_MAX - otherwise calculations can give wrong values. */ - const SIZEL psizelExtent = {INT_MAX,INT_MAX}; - - static const WCHAR oneA[] = {'A',0}; - - /* Results of measurements */ - LONG xdim, ydim; - - /* The device context to do the tests in */ + SIZEL extent; + static const WCHAR test_text[] = {'T','e','s','t','S','o','m','e','T','e','x','t',0}; + LONG width, height; HDC hdcDraw; - - /* Variables with the text metric information */ - INT charwidth_caps_text[26]; - TEXTMETRICA tmInfo_text; + HWND hwnd; + RECT rect; + CHARFORMAT2W cf; + LRESULT lresult; + HFONT hf; if (!init_texthost(&txtserv, &host)) return; - hdcDraw = GetDC(NULL); - SaveDC(hdcDraw); - - /* Populate the metric strucs */ + hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP | WS_VISIBLE, + 0, 0, 100, 100, 0, 0, 0, NULL); + hdcDraw = GetDC(hwnd); SetMapMode(hdcDraw,MM_TEXT); - GetTextMetricsA(hdcDraw, &tmInfo_text); - SetLastError(0xdeadbeef); - ret = GetCharWidth32A(hdcDraw,'A','Z',charwidth_caps_text); - if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - win_skip("GetCharWidth32 is not available\n"); - goto cleanup; - } - - /* Make measurements in MM_TEXT */ - SetMapMode(hdcDraw,MM_TEXT); - xdim = 0; ydim = 0; - - result = ITextServices_TxSetText(txtserv, oneA); - ok(result == S_OK, "ITextServices_TxSetText failed (result = %x)\n", result); - if (result != S_OK) { - skip("Could not set text\n"); - goto cleanup; - } - - SetLastError(0xdeadbeef); - result = ITextServices_TxGetNaturalSize(txtserv, DVASPECT_CONTENT, - hdcDraw, NULL, NULL, - TXTNS_FITTOCONTENT, &psizelExtent, - &xdim, &ydim); - todo_wine ok(result == S_OK || broken(result == E_FAIL), /* WINXP Arabic Language */ - "TxGetNaturalSize gave unexpected return value (result = %x)\n", result); - if (result == S_OK) { - todo_wine ok(ydim == tmInfo_text.tmHeight, - "Height calculated incorrectly (expected %d, got %d)\n", - tmInfo_text.tmHeight, ydim); - /* The native DLL adds one pixel extra when calculating widths. */ - todo_wine ok(xdim >= charwidth_caps_text[0] && xdim <= charwidth_caps_text[0] + 1, - "Width calculated incorrectly (expected %d {+1}, got %d)\n", - charwidth_caps_text[0], xdim); - } else - skip("TxGetNaturalSize measurements not performed (xdim = %d, ydim = %d, result = %x, error = %x)\n", - xdim, ydim, result, GetLastError()); - -cleanup: - RestoreDC(hdcDraw,1); - ReleaseDC(NULL,hdcDraw); + GetClientRect(hwnd, &rect); + + memset(&cf, 0, sizeof(cf)); + cf.cbSize = sizeof(cf); + cf.dwMask = CFM_ALL2; + hf = GetStockObject(DEFAULT_GUI_FONT); + hf_to_cf(hf, &cf); + result = ITextServices_TxSendMessage(txtserv, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf, &lresult); + ok(result == S_OK, "ITextServices_TxSendMessage failed: 0x%08x.\n", result); + SelectObject(hdcDraw, hf); + + result = ITextServices_TxSetText(txtserv, test_text); + ok(result == S_OK, "ITextServices_TxSetText failed: 0x%08x.\n", result); + + extent.cx = -1; extent.cy = -1; + width = rect.right - rect.left; + height = 0; + result = ITextServices_TxGetNaturalSize(txtserv, DVASPECT_CONTENT, hdcDraw, NULL, NULL, + TXTNS_FITTOCONTENT, &extent, &width, &height); + todo_wine CHECK_TXGETNATURALSIZE(result, width, height, hdcDraw, rect, test_text); + + ReleaseDC(hwnd, hdcDraw); + DestroyWindow(hwnd); ITextServices_Release(txtserv); ITextHost_Release(host); } @@ -894,6 +905,7 @@ static void test_QueryInterface(void) HRESULT hres; IRichEditOle *reole, *txtsrv_reole; ITextDocument *txtdoc, *txtsrv_txtdoc; + ITextDocument2Old *txtdoc2old, *txtsrv_txtdoc2old; ULONG refcount; if(!init_texthost(&txtserv, &host)) @@ -920,6 +932,17 @@ static void test_QueryInterface(void) ITextDocument_Release(txtdoc); refcount = get_refcount((IUnknown *)txtserv); ok(refcount == 2, "got wrong ref count: %d\n", refcount); + + hres = IRichEditOle_QueryInterface(txtsrv_reole, &IID_ITextDocument2Old, (void **)&txtdoc2old); + ok(hres == S_OK, "IRichEditOle_QueryInterface: 0x%08x\n", hres); + refcount = get_refcount((IUnknown *)txtserv); + ok(refcount == 3, "got wrong ref count: %d\n", refcount); + refcount = get_refcount((IUnknown *)txtsrv_reole); + ok(refcount == 3, "got wrong ref count: %d\n", refcount); + + ITextDocument2Old_Release(txtdoc2old); + refcount = get_refcount((IUnknown *)txtserv); + ok(refcount == 2, "got wrong ref count: %d\n", refcount); IRichEditOle_Release(txtsrv_reole); refcount = get_refcount((IUnknown *)txtserv); ok(refcount == 1, "got wrong ref count: %d\n", refcount); @@ -946,6 +969,77 @@ static void test_QueryInterface(void) refcount = get_refcount((IUnknown *)txtserv); ok(refcount == 1, "got wrong ref count: %d\n", refcount); + /* ITextDocument2Old */ + hres = ITextServices_QueryInterface(txtserv, &IID_ITextDocument2Old, (void **)&txtsrv_txtdoc2old); + ok(hres == S_OK, "ITextServices_QueryInterface: 0x%08x\n", hres); + refcount = get_refcount((IUnknown *)txtserv); + ok(refcount == 2, "got wrong ref count: %d\n", refcount); + refcount = get_refcount((IUnknown *)txtsrv_txtdoc2old); + ok(refcount == 2, "got wrong ref count: %d\n", refcount); + + hres = ITextDocument2Old_QueryInterface(txtsrv_txtdoc2old, &IID_IRichEditOle, (void **)&reole); + ok(hres == S_OK, "ITextDocument2Old_QueryInterface: 0x%08x\n", hres); + refcount = get_refcount((IUnknown *)txtserv); + ok(refcount == 3, "got wrong ref count: %d\n", refcount); + refcount = get_refcount((IUnknown *)txtsrv_txtdoc2old); + ok(refcount == 3, "got wrong ref count: %d\n", refcount); + + IRichEditOle_Release(reole); + refcount = get_refcount((IUnknown *)txtserv); + ok(refcount == 2, "got wrong ref count: %d\n", refcount); + ITextDocument2Old_Release(txtsrv_txtdoc2old); + refcount = get_refcount((IUnknown *)txtserv); + ok(refcount == 1, "got wrong ref count: %d\n", refcount); + + ITextServices_Release(txtserv); + ITextHost_Release(host); +} + +static void test_default_format(void) +{ + ITextServices *txtserv; + ITextHost *host; + HRESULT result; + LRESULT lresult; + CHARFORMAT2W cf2; + const CHARFORMATW *host_cf; + DWORD expected_effects; + + if (!init_texthost(&txtserv, &host)) + return; + + cf2.cbSize = sizeof(CHARFORMAT2W); + result = ITextServices_TxSendMessage(txtserv, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2, &lresult); + ok(result == S_OK, "ITextServices_TxSendMessage failed: 0x%08x.\n", result); + + ITextHostImpl_TxGetCharFormat(host, &host_cf); + ok(!lstrcmpW(host_cf->szFaceName, cf2.szFaceName), "got wrong font name: %s.\n", wine_dbgstr_w(cf2.szFaceName)); + ok(cf2.yHeight == host_cf->yHeight, "got wrong yHeight: %d, expected %d.\n", cf2.yHeight, host_cf->yHeight); + expected_effects = (cf2.dwEffects & ~(CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR)); + ok(host_cf->dwEffects == expected_effects, "got wrong dwEffects: %x, expected %x.\n", cf2.dwEffects, expected_effects); + ok(cf2.bPitchAndFamily == host_cf->bPitchAndFamily, "got wrong bPitchAndFamily: %x, expected %x.\n", + cf2.bPitchAndFamily, host_cf->bPitchAndFamily); + ok(cf2.bCharSet == host_cf->bCharSet, "got wrong bCharSet: %x, expected %x.\n", cf2.bCharSet, host_cf->bCharSet); + + ITextServices_Release(txtserv); + ITextHost_Release(host); +} + +static void test_TxGetScroll(void) +{ + ITextServices *txtserv; + ITextHost *host; + HRESULT ret; + + if (!init_texthost(&txtserv, &host)) + return; + + ret = ITextServices_TxGetHScroll(txtserv, NULL, NULL, NULL, NULL, NULL); + ok(ret == S_OK, "ITextSerHices_GetVScroll failed: 0x%08x.\n", ret); + + ret = ITextServices_TxGetVScroll(txtserv, NULL, NULL, NULL, NULL, NULL); + ok(ret == S_OK, "ITextServices_GetVScroll failed: 0x%08x.\n", ret); + ITextServices_Release(txtserv); ITextHost_Release(host); } @@ -980,6 +1074,8 @@ START_TEST( txtsrv ) test_TxGetNaturalSize(); test_TxDraw(); test_QueryInterface(); + test_default_format(); + test_TxGetScroll(); } if (wrapperCodeMem) VirtualFree(wrapperCodeMem, 0, MEM_RELEASE); } -- 2.17.1