Hi folks, I need your advice or comment!
Implement ITextDocument_fnOpen[0] (riched20) is a part of work to my GSoC. The 'pencils down' date is coming. And I think it is time to clear the code up. This series of patches is the implementation of ITextDocument_fnOpen. I would like to improve it to be enough good for sending to wine-patches and being accepted. I split the implementation into six patches: - patch 0001 is just a simple implementation; - patch 0002 added the creation mode to let it support these parameters: tomCreateNew, tomCreateAlways, tomOpenExisting, tomOpenAlways, tomTruncateExisting; - patch 0003 added the access mode to let support tomReadOnly and any combination of tomReadOnly and tomShareDenyRead, tomShareDenyWrite, tomPasteFile; - patch 0004 added the support of RTF - patch 0005 added tomPasteFile support - patch 0006 added a UTF-16 support, with this patch you can open a UTF-6 text file without dependence of the long CodePage parameter. If you want to open a utf-8 text file with it, you may need these patch to fix a bug of EM_SETTEXTEX: http://source.winehq.org/patches/data/98574 http://source.winehq.org/patches/data/98575 http://source.winehq.org/patches/data/98576 http://source.winehq.org/patches/data/98577 I appreciate for any comment! :) Thank you. ** Thanks my mentor Huw and Qian Hong for giving me a lot good advice. Thanks other people for help! ** [0] http://msdn.microsoft.com/en-us/library/windows/desktop/bb774093(v=vs.85).aspx -- Regards, Jactry Zeng
From 1d1cd63088503c171b4979d624ea03a3120a00e7 Mon Sep 17 00:00:00 2001 From: Jactry Zeng <jactr...@gmail.com> Date: Sat, 7 Sep 2013 16:29:46 +0800 Subject: [PATCH 1/6] riched20: Implement ITextDocument_fnOpen. --- dlls/riched20/richole.c | 47 +++++++++++++++++++++++++++++++++++++++-- dlls/riched20/tests/richole.c | 8 +++---- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/dlls/riched20/richole.c b/dlls/riched20/richole.c index 6805873..e7da55f 100644 --- a/dlls/riched20/richole.c +++ b/dlls/riched20/richole.c @@ -582,8 +582,51 @@ ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, LONG CodePage) { IRichEditOleImpl *This = impl_from_ITextDocument(me); - FIXME("stub %p\n",This); - return E_NOTIMPL; + + HANDLE hFile; + DWORD dwReadSize, size; + SETTEXTEX settextex; + LPSTR chBuffer; + + TRACE("(%p %p 0x%x %d)\n", me, pVar, Flags, CodePage); + + if(V_VT(pVar) != VT_BSTR) return E_INVALIDARG; + + hFile = CreateFileW(V_BSTR(pVar), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ| + FILE_SHARE_WRITE|FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, 0, NULL); + + if(hFile == INVALID_HANDLE_VALUE) + return HRESULT_FROM_WIN32(GetLastError()); + + settextex.codepage = CodePage; + settextex.flags = ST_DEFAULT; + + size = GetFileSize(hFile, NULL); + if(size == INVALID_FILE_SIZE) + { + CloseHandle(hFile); + return HRESULT_FROM_WIN32(GetLastError()); + } + + chBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size+2); + if(!chBuffer) + { + CloseHandle(hFile); + return HRESULT_FROM_WIN32(GetLastError()); + } + + if(!ReadFile(hFile, chBuffer, size, &dwReadSize, NULL)) + { + CloseHandle(hFile); + HeapFree(GetProcessHeap(), 0, chBuffer); + return HRESULT_FROM_WIN32(GetLastError()); + } + + SendMessageW(This->editor->hWnd, EM_SETTEXTEX, (int)&settextex, (LPARAM)chBuffer); + CloseHandle(hFile); + + return S_OK; } static HRESULT WINAPI diff --git a/dlls/riched20/tests/richole.c b/dlls/riched20/tests/richole.c index 1bd0be9..6f2ed17 100644 --- a/dlls/riched20/tests/richole.c +++ b/dlls/riched20/tests/richole.c @@ -190,7 +190,7 @@ static void test_ITextDocument_Open(void) touch_file(filename); create_interfaces(&w, &reOle, &txtDoc, &txtSel); hres = ITextDocument_Open(txtDoc, &testfile, tomConstantsSingle[i], CP_ACP); - todo_wine ok(hres == S_OK, "ITextDocument_Open: Filename:test.txt Flags:0x%x Codepage:CP_ACP hres:0x%x\n", + ok(hres == S_OK, "ITextDocument_Open: Filename:test.txt Flags:0x%x Codepage:CP_ACP hres:0x%x\n", tomConstantsSingle[i], hres); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); @@ -198,7 +198,7 @@ static void test_ITextDocument_Open(void) touch_file(filename); create_interfaces(&w, &reOle, &txtDoc, &txtSel); hres = ITextDocument_Open(txtDoc, &testfile, tomConstantsSingle[i], CP_UTF8); - todo_wine ok(hres == S_OK, "ITextDocument_Open: Filename:test.txt Flags:0x%x Codepage:CP_UTF8 hres:0x%x\n", + ok(hres == S_OK, "ITextDocument_Open: Filename:test.txt Flags:0x%x Codepage:CP_UTF8 hres:0x%x\n", tomConstantsSingle[i], hres); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); @@ -209,7 +209,7 @@ static void test_ITextDocument_Open(void) touch_file(filename); create_interfaces(&w, &reOle, &txtDoc, &txtSel); hres = ITextDocument_Open(txtDoc, &testfile, tomConstantsMulti[i], CP_ACP); - todo_wine ok(hres == S_OK, "ITextDocument_Open: Filename:test.txt Flags:0x%x Codepage:CP_ACP hres:0x%x\n", + ok(hres == S_OK, "ITextDocument_Open: Filename:test.txt Flags:0x%x Codepage:CP_ACP hres:0x%x\n", tomConstantsMulti[i], hres); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); @@ -217,7 +217,7 @@ static void test_ITextDocument_Open(void) touch_file(filename); create_interfaces(&w, &reOle, &txtDoc, &txtSel); hres = ITextDocument_Open(txtDoc, &testfile, tomConstantsMulti[i], CP_UTF8); - todo_wine ok(hres == S_OK, "ITextDocument_Open: Filename:test.txt Flags:0x%x Codepage:CP_UTF8 hres:0x%x\n", + ok(hres == S_OK, "ITextDocument_Open: Filename:test.txt Flags:0x%x Codepage:CP_UTF8 hres:0x%x\n", tomConstantsMulti[i], hres); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); -- 1.7.10.4
From 8e4c922e6885cf81decfa63c030382a7e5311395 Mon Sep 17 00:00:00 2001 From: Jactry Zeng <jactr...@gmail.com> Date: Sat, 7 Sep 2013 16:45:07 +0800 Subject: [PATCH 2/6] riched20: Add creation mode support for ITextDocument_fnOpen. --- dlls/riched20/richole.c | 25 +++++++++++++++++++++++-- dlls/riched20/tests/richole.c | 34 +++++++++++++++++----------------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/dlls/riched20/richole.c b/dlls/riched20/richole.c index e7da55f..bd8aa60 100644 --- a/dlls/riched20/richole.c +++ b/dlls/riched20/richole.c @@ -577,6 +577,25 @@ ITextDocument_fnNew(ITextDocument* me) return E_NOTIMPL; } +static DWORD get_open_creation_mode(LONG Flags) +{ + switch(Flags & 0xf0) + { + case tomCreateNew: + return CREATE_NEW; + case tomCreateAlways: + return CREATE_ALWAYS; + case tomOpenExisting: + return OPEN_EXISTING; + case tomOpenAlways: + return OPEN_ALWAYS; + case tomTruncateExisting: + return TRUNCATE_EXISTING; + default: + return OPEN_ALWAYS; + } +} + static HRESULT WINAPI ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, LONG CodePage) @@ -584,7 +603,7 @@ ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, IRichEditOleImpl *This = impl_from_ITextDocument(me); HANDLE hFile; - DWORD dwReadSize, size; + DWORD dwReadSize, size, creationMode; SETTEXTEX settextex; LPSTR chBuffer; @@ -592,9 +611,11 @@ ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, if(V_VT(pVar) != VT_BSTR) return E_INVALIDARG; + creationMode = get_open_creation_mode(Flags); + hFile = CreateFileW(V_BSTR(pVar), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ| FILE_SHARE_WRITE|FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, 0, NULL); + NULL, creationMode, 0, NULL); if(hFile == INVALID_HANDLE_VALUE) return HRESULT_FROM_WIN32(GetLastError()); diff --git a/dlls/riched20/tests/richole.c b/dlls/riched20/tests/richole.c index 6f2ed17..72dd06e 100644 --- a/dlls/riched20/tests/richole.c +++ b/dlls/riched20/tests/richole.c @@ -225,74 +225,74 @@ static void test_ITextDocument_Open(void) create_interfaces(&w, &reOle, &txtDoc, &txtSel); hres = ITextDocument_Open(txtDoc, &testfile, tomCreateAlways, CP_ACP); - todo_wine ok(hres == S_OK, "ITextDocument_Open should success Codepage:CP_ACP\n"); - todo_wine ok(is_existing_file(filename), "ITextDocument_Open should create a file\n"); + ok(hres == S_OK, "ITextDocument_Open should success Codepage:CP_ACP\n"); + ok(is_existing_file(filename), "ITextDocument_Open should create a file\n"); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); create_interfaces(&w, &reOle, &txtDoc, &txtSel); hres = ITextDocument_Open(txtDoc, &testfile, tomCreateAlways, CP_UTF8); - todo_wine ok(hres == S_OK, "ITextDocument_Open should success Codepage:CP_UTF8\n"); - todo_wine ok(is_existing_file(filename), "ITextDocument_Open should create a file\n"); + ok(hres == S_OK, "ITextDocument_Open should success Codepage:CP_UTF8\n"); + ok(is_existing_file(filename), "ITextDocument_Open should create a file\n"); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); create_interfaces(&w, &reOle, &txtDoc, &txtSel); hres = ITextDocument_Open(txtDoc, &testfile, tomOpenAlways, CP_ACP); - todo_wine ok(hres == S_OK, "ITextDocument_Open should success Codepage:CP_ACP\n"); - todo_wine ok(is_existing_file(filename), "ITextDocument_Open should create a file\n"); + ok(hres == S_OK, "ITextDocument_Open should success Codepage:CP_ACP\n"); + ok(is_existing_file(filename), "ITextDocument_Open should create a file\n"); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); create_interfaces(&w, &reOle, &txtDoc, &txtSel); hres = ITextDocument_Open(txtDoc, &testfile, tomOpenAlways, CP_UTF8); - todo_wine ok(hres == S_OK, "ITextDocument_Open should success Codepage:CP_UTF8\n"); - todo_wine ok(is_existing_file(filename), "ITextDocument_Open should create a file\n"); + ok(hres == S_OK, "ITextDocument_Open should success Codepage:CP_UTF8\n"); + ok(is_existing_file(filename), "ITextDocument_Open should create a file\n"); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); create_interfaces(&w, &reOle, &txtDoc, &txtSel); hres = ITextDocument_Open(txtDoc, &testfile, tomCreateNew, CP_ACP); - todo_wine ok(hres == S_OK, "ITextDocument_Open should success Codepage:CP_ACP\n"); - todo_wine ok(is_existing_file(filename), "ITextDocument_Open should create a file\n"); + ok(hres == S_OK, "ITextDocument_Open should success Codepage:CP_ACP\n"); + ok(is_existing_file(filename), "ITextDocument_Open should create a file\n"); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); create_interfaces(&w, &reOle, &txtDoc, &txtSel); hres = ITextDocument_Open(txtDoc, &testfile, tomCreateNew, CP_UTF8); - todo_wine ok(hres == S_OK, "ITextDocument_Open should success Codepage:CP_UTF8\n"); - todo_wine ok(is_existing_file(filename), "ITextDocument_Open should create a file\n"); + ok(hres == S_OK, "ITextDocument_Open should success Codepage:CP_UTF8\n"); + ok(is_existing_file(filename), "ITextDocument_Open should create a file\n"); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); create_interfaces(&w, &reOle, &txtDoc, &txtSel); touch_file(filename); hres = ITextDocument_Open(txtDoc, &testfile, tomCreateNew, CP_ACP); - todo_wine ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "ITextDocument_Open should fail Codepage:CP_ACP\n"); + ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "ITextDocument_Open should fail Codepage:CP_ACP\n"); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); create_interfaces(&w, &reOle, &txtDoc, &txtSel); touch_file(filename); hres = ITextDocument_Open(txtDoc, &testfile, tomCreateNew, CP_UTF8); - todo_wine ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "ITextDocument_Open should fail Codepage:CP_UTF8\n"); + ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "ITextDocument_Open should fail Codepage:CP_UTF8\n"); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); create_interfaces(&w, &reOle, &txtDoc, &txtSel); hres = ITextDocument_Open(txtDoc, &testfile, tomOpenExisting, CP_ACP); - todo_wine ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "ITextDocument_Open should fail Codepage:CP_ACP\n"); + ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "ITextDocument_Open should fail Codepage:CP_ACP\n"); release_interfaces(&w, &reOle, &txtDoc, &txtSel); create_interfaces(&w, &reOle, &txtDoc, &txtSel); hres = ITextDocument_Open(txtDoc, &testfile, tomOpenExisting, CP_UTF8); - todo_wine ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "ITextDocument_Open should fail Codepage:CP_UTF8\n"); + ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "ITextDocument_Open should fail Codepage:CP_UTF8\n"); release_interfaces(&w, &reOle, &txtDoc, &txtSel); create_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); ITextDocument_Open(txtDoc, &testfile, tomText, CP_ACP); - todo_wine ok(is_existing_file(filename) == TRUE, "a file should be created default\n"); + ok(is_existing_file(filename) == TRUE, "a file should be created default\n"); release_interfaces(&w, &reOle, &txtDoc, &txtSel); DeleteFileW(filename); -- 1.7.10.4
From a570cb25f4907ce6d04cd19fd39bf088b6ff73ac Mon Sep 17 00:00:00 2001 From: Jactry Zeng <jactr...@gmail.com> Date: Sat, 7 Sep 2013 16:53:49 +0800 Subject: [PATCH 3/6] riched20: Add access mode support for ITextDocument_fnOpen. --- dlls/riched20/richole.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/dlls/riched20/richole.c b/dlls/riched20/richole.c index bd8aa60..c75aefb 100644 --- a/dlls/riched20/richole.c +++ b/dlls/riched20/richole.c @@ -596,6 +596,23 @@ static DWORD get_open_creation_mode(LONG Flags) } } +static DWORD get_open_access_mode(LONG Flags) +{ + switch(Flags & 0xf00) + { + case tomReadOnly: + return GENERIC_READ; + case tomReadOnly|tomShareDenyRead: + return GENERIC_READ; + case tomReadOnly|tomShareDenyWrite: + return GENERIC_READ; + case tomReadOnly|tomShareDenyRead|tomShareDenyWrite: + return GENERIC_READ; + default: + return GENERIC_READ|GENERIC_WRITE; + } +} + static HRESULT WINAPI ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, LONG CodePage) @@ -603,7 +620,7 @@ ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, IRichEditOleImpl *This = impl_from_ITextDocument(me); HANDLE hFile; - DWORD dwReadSize, size, creationMode; + DWORD dwReadSize, size, creationMode, accessMode; SETTEXTEX settextex; LPSTR chBuffer; @@ -612,8 +629,9 @@ ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, if(V_VT(pVar) != VT_BSTR) return E_INVALIDARG; creationMode = get_open_creation_mode(Flags); + accessMode = get_open_access_mode(Flags); - hFile = CreateFileW(V_BSTR(pVar), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ| + hFile = CreateFileW(V_BSTR(pVar), accessMode, FILE_SHARE_READ| FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, creationMode, 0, NULL); -- 1.7.10.4
From 0a07e329c816b9be02666f2a775e1eec748a7624 Mon Sep 17 00:00:00 2001 From: Jactry Zeng <jactr...@gmail.com> Date: Sun, 8 Sep 2013 12:45:22 +0800 Subject: [PATCH 4/6] riched20: Add RTF support for ITextDocument_fnOpen. --- dlls/riched20/richole.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/dlls/riched20/richole.c b/dlls/riched20/richole.c index c75aefb..3da8653 100644 --- a/dlls/riched20/richole.c +++ b/dlls/riched20/richole.c @@ -613,6 +613,17 @@ static DWORD get_open_access_mode(LONG Flags) } } +static DWORD CALLBACK stream_in(DWORD_PTR hFile, LPBYTE buffer, LONG cb, LONG *pcb) +{ + DWORD read; + + if(!ReadFile((HANDLE)hFile, buffer, cb, &read, 0)) + return 1; + + *pcb = read; + return 0; +} + static HRESULT WINAPI ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, LONG CodePage) @@ -621,6 +632,9 @@ ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, HANDLE hFile; DWORD dwReadSize, size, creationMode, accessMode; + static const char header[] = "{\\rtf"; + char beginHex[5]; + DWORD readOut; SETTEXTEX settextex; LPSTR chBuffer; @@ -638,6 +652,26 @@ ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, if(hFile == INVALID_HANDLE_VALUE) return HRESULT_FROM_WIN32(GetLastError()); + ReadFile(hFile, beginHex, 5, &readOut, NULL); + SetFilePointer(hFile, 0, NULL, FILE_BEGIN); + + /* Open a rtf with tomText. */ + if(readOut >= 5 && !memcmp(header, beginHex, 5) && ((Flags & 0xf) == tomText)) + { + EDITSTREAM editstream; + + editstream.dwCookie = (DWORD_PTR)hFile; + editstream.pfnCallback = stream_in; + + if((Flags & 0xf000) == tomPasteFile) + SendMessageW(This->editor->hWnd, EM_STREAMIN, SF_TEXT|SFF_SELECTION, (LPARAM)&editstream); + else + SendMessageW(This->editor->hWnd, EM_STREAMIN, SF_TEXT, (LPARAM)&editstream); + + CloseHandle(hFile); + return S_OK; + } + settextex.codepage = CodePage; settextex.flags = ST_DEFAULT; -- 1.7.10.4
From 8b6c9c44258271ea521c254aaab657f2a36b455c Mon Sep 17 00:00:00 2001 From: Jactry Zeng <jactr...@gmail.com> Date: Sun, 8 Sep 2013 12:57:01 +0800 Subject: [PATCH 5/6] riched20: Add tomPasteFile support for ITextDocument_fnOpen. --- dlls/riched20/richole.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/riched20/richole.c b/dlls/riched20/richole.c index 3da8653..55dbda1 100644 --- a/dlls/riched20/richole.c +++ b/dlls/riched20/richole.c @@ -634,6 +634,7 @@ ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, DWORD dwReadSize, size, creationMode, accessMode; static const char header[] = "{\\rtf"; char beginHex[5]; + LONG flags; DWORD readOut; SETTEXTEX settextex; LPSTR chBuffer; @@ -672,8 +673,11 @@ ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, return S_OK; } + if((Flags & 0xf000) == tomPasteFile) flags = ST_SELECTION|ST_DEFAULT; + else flags = ST_DEFAULT; + settextex.codepage = CodePage; - settextex.flags = ST_DEFAULT; + settextex.flags = flags; size = GetFileSize(hFile, NULL); if(size == INVALID_FILE_SIZE) -- 1.7.10.4
From 02e8f59926c80469f1b42285a74db4bcb7b6df67 Mon Sep 17 00:00:00 2001 From: Jactry Zeng <jactr...@gmail.com> Date: Sun, 8 Sep 2013 13:03:10 +0800 Subject: [PATCH 6/6] riched20: Add UTF-16 support for ITextDocument_fnOpen. --- dlls/riched20/richole.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dlls/riched20/richole.c b/dlls/riched20/richole.c index 55dbda1..86f7617 100644 --- a/dlls/riched20/richole.c +++ b/dlls/riched20/richole.c @@ -676,9 +676,18 @@ ITextDocument_fnOpen(ITextDocument* me, VARIANT* pVar, LONG Flags, if((Flags & 0xf000) == tomPasteFile) flags = ST_SELECTION|ST_DEFAULT; else flags = ST_DEFAULT; + if(readOut >= 2 && (BYTE)beginHex[0] == 0xff && (BYTE)beginHex[1] == 0xfe) + { + settextex.codepage = 1200; + settextex.flags = flags; + goto end; + } + settextex.codepage = CodePage; settextex.flags = flags; + goto end; +end: size = GetFileSize(hFile, NULL); if(size == INVALID_FILE_SIZE) { -- 1.7.10.4