[WINESYNC]
authorAleksey Bragin <aleksey@reactos.org>
Wed, 21 Apr 2010 20:35:09 +0000 (20:35 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Wed, 21 Apr 2010 20:35:09 +0000 (20:35 +0000)
- Sync comdlg32, crypt32, gdiplus, inetcomm, jscript, msctf, mshtml, msxml3, rsaenh, schannel, shlwapi, urlmon, usp10, wininet winetests.

svn path=/trunk/; revision=46982

41 files changed:
rostests/winetests/comdlg32/comdlg32.rbuild
rostests/winetests/comdlg32/filedlg.c
rostests/winetests/comdlg32/fontdlg.c [new file with mode: 0644]
rostests/winetests/comdlg32/printdlg.c
rostests/winetests/comdlg32/rsrc.rc
rostests/winetests/crypt32/chain.c
rostests/winetests/crypt32/main.c
rostests/winetests/crypt32/msg.c
rostests/winetests/gdiplus/brush.c
rostests/winetests/gdiplus/font.c
rostests/winetests/gdiplus/graphics.c
rostests/winetests/gdiplus/image.c
rostests/winetests/inetcomm/mimeintl.c
rostests/winetests/jscript/regexp.js
rostests/winetests/msctf/inputprocessor.c
rostests/winetests/mshtml/dom.c
rostests/winetests/mshtml/events.c
rostests/winetests/mshtml/jstest.html
rostests/winetests/mshtml/script.c
rostests/winetests/msxml3/domdoc.c
rostests/winetests/rsaenh/rsaenh.c
rostests/winetests/schannel/main.c
rostests/winetests/shlwapi/generated.c
rostests/winetests/shlwapi/istream.c
rostests/winetests/shlwapi/ordinal.c
rostests/winetests/shlwapi/path.c
rostests/winetests/shlwapi/shlwapi.rbuild
rostests/winetests/shlwapi/string.c
rostests/winetests/shlwapi/url.c
rostests/winetests/urlmon/generated.c
rostests/winetests/urlmon/misc.c
rostests/winetests/urlmon/sec_mgr.c
rostests/winetests/urlmon/url.c
rostests/winetests/usp10/usp10.c
rostests/winetests/wininet/ftp.c
rostests/winetests/wininet/generated.c
rostests/winetests/wininet/http.c
rostests/winetests/wininet/internet.c
rostests/winetests/wininet/url.c
rostests/winetests/wininet/urlcache.c
rostests/winetests/wininet/wininet.rbuild

index d24dc1b..2d5dec2 100644 (file)
@@ -5,11 +5,13 @@
        <include base="comdlg32_winetest">.</include>
     <define name="__ROS_LONG64__" />
        <file>filedlg.c</file>
+       <file>fontdlg.c</file>
        <file>printdlg.c</file>
        <file>testlist.c</file>
        <file>rsrc.rc</file>
        <library>wine</library>
        <library>comdlg32</library>
+       <library>winspool</library>
        <library>user32</library>
        <library>gdi32</library>
        <library>ntdll</library>
index 9714dda..71f7d2a 100644 (file)
 
 /* ##### */
 
+static int resizesupported = TRUE;
+
+static void toolbarcheck( HWND hDlg)
+{
+    /* test toolbar properties */
+    /* bug #10532 */
+    int maxtextrows;
+    HWND ctrl;
+    DWORD ret;
+    char classname[20];
+
+    for( ctrl = GetWindow( hDlg, GW_CHILD);
+            ctrl ; ctrl = GetWindow( ctrl, GW_HWNDNEXT)) {
+        GetClassName( ctrl, classname, 10);
+        classname[7] = '\0';
+        if( !strcmp( classname, "Toolbar")) break;
+    }
+    ok( ctrl != NULL, "could not get the toolbar control\n");
+    ret = SendMessage( ctrl, TB_ADDSTRING, 0, (LPARAM)"winetestwinetest\0\0");
+    ok( ret == 0, "addstring returned %d (expected 0)\n", ret);
+    maxtextrows = SendMessage( ctrl, TB_GETTEXTROWS, 0, 0);
+    ok( maxtextrows == 0 || broken(maxtextrows == 1),  /* Win2k and below */
+        "Get(Max)TextRows returned %d (expected 0)\n", maxtextrows);
+}
+
+
 static UINT_PTR CALLBACK OFNHookProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     LPNMHDR nmh;
@@ -49,6 +75,7 @@ static UINT_PTR CALLBACK OFNHookProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM
             ok(ret > 0, "CMD_GETFOLDERIDLIST not implemented\n");
             if (ret > 5)
                 ok(buf[0] == 0x66 && buf[1] == 0x66, "CMD_GETFOLDERIDLIST: The buffer was touched on failure\n");
+            toolbarcheck( GetParent(hDlg));
         }
     }
 
@@ -78,26 +105,26 @@ static void test_DialogCancel(void)
     ofn.lpstrInitialDir = szInitialDir;
 
     PrintDlgA(NULL);
-    ok(CDERR_INITIALIZATION == CommDlgExtendedError(), "expected %d, got %d\n",
-       CDERR_INITIALIZATION, CommDlgExtendedError());
+    ok(CDERR_INITIALIZATION == CommDlgExtendedError(),
+       "expected CDERR_INITIALIZATION, got %d\n", CommDlgExtendedError());
 
     result = GetOpenFileNameA(&ofn);
-    ok(0 == result, "expected %d, got %d\n", 0, result);
-    ok(0 == CommDlgExtendedError(), "expected %d, got %d\n", 0,
+    ok(0 == result, "expected 0, got %d\n", result);
+    ok(0 == CommDlgExtendedError(), "expected 0, got %d\n",
        CommDlgExtendedError());
 
     PrintDlgA(NULL);
-    ok(CDERR_INITIALIZATION == CommDlgExtendedError(), "expected %d, got %d\n",
-              CDERR_INITIALIZATION, CommDlgExtendedError());
+    ok(CDERR_INITIALIZATION == CommDlgExtendedError(),
+       "expected CDERR_INITIALIZATION, got %d\n", CommDlgExtendedError());
 
     result = GetSaveFileNameA(&ofn);
-    ok(0 == result, "expected %d, got %d\n", 0, result);
-    ok(0 == CommDlgExtendedError(), "expected %d, got %d\n", 0,
+    ok(0 == result, "expected 0, got %d\n", result);
+    ok(0 == CommDlgExtendedError(), "expected 0, got %d\n",
        CommDlgExtendedError());
 
     PrintDlgA(NULL);
-    ok(CDERR_INITIALIZATION == CommDlgExtendedError(), "expected %d, got %d\n",
-              CDERR_INITIALIZATION, CommDlgExtendedError());
+    ok(CDERR_INITIALIZATION == CommDlgExtendedError(),
+       "expected CDERR_INITIALIZATION, got %d\n", CommDlgExtendedError());
 
     /* Before passing the ofn to Unicode functions, remove the ANSI strings */
     ofn.lpstrFilter = NULL;
@@ -105,8 +132,8 @@ static void test_DialogCancel(void)
     ofn.lpstrDefExt = NULL;
 
     PrintDlgA(NULL);
-    ok(CDERR_INITIALIZATION == CommDlgExtendedError(), "expected %d, got %d\n",
-              CDERR_INITIALIZATION, CommDlgExtendedError());
+    ok(CDERR_INITIALIZATION == CommDlgExtendedError(),
+       "expected CDERR_INITIALIZATION, got %d\n", CommDlgExtendedError());
 
     SetLastError(0xdeadbeef);
     result = GetOpenFileNameW((LPOPENFILENAMEW) &ofn);
@@ -114,11 +141,10 @@ static void test_DialogCancel(void)
         win_skip("GetOpenFileNameW is not implemented\n");
     else
     {
-        ok(0 == result, "expected %d, got %d\n", 0, result);
+        ok(0 == result, "expected 0, got %d\n", result);
         ok(0 == CommDlgExtendedError() ||
-           CDERR_INITIALIZATION == CommDlgExtendedError(), /* win9x */
-           "expected %d or %d, got %d\n", 0, CDERR_INITIALIZATION,
-           CommDlgExtendedError());
+           broken(CDERR_INITIALIZATION == CommDlgExtendedError()), /* win9x */
+           "expected 0, got %d\n", CommDlgExtendedError());
     }
 
     SetLastError(0xdeadbeef);
@@ -127,11 +153,10 @@ static void test_DialogCancel(void)
         win_skip("GetSaveFileNameW is not implemented\n");
     else
     {
-        ok(0 == result, "expected %d, got %d\n", 0, result);
+        ok(0 == result, "expected 0, got %d\n", result);
         ok(0 == CommDlgExtendedError() ||
-           CDERR_INITIALIZATION == CommDlgExtendedError(), /* win9x */
-           "expected %d or %d, got %d\n", 0, CDERR_INITIALIZATION,
-           CommDlgExtendedError());
+           broken(CDERR_INITIALIZATION == CommDlgExtendedError()), /* win9x */
+           "expected 0, got %d\n", CommDlgExtendedError());
     }
 }
 
@@ -177,12 +202,19 @@ static UINT_PTR CALLBACK create_view_window2_hook(HWND dlg, UINT msg, WPARAM wPa
             view_params.hwndView = NULL;
 
             hr = IShellView2_CreateViewWindow2(shell_view2, &view_params);
+            if (hr == E_FAIL)
+            {
+                win_skip("CreateViewWindow2 is broken on Vista/W2K8\n");
+                goto cleanup;
+            }
             ok(SUCCEEDED(hr), "CreateViewWindow2 returned %#x\n", hr);
             if (FAILED(hr)) goto cleanup;
 
             hr = IShellView2_GetCurrentInfo(shell_view2, &folder_settings);
             ok(SUCCEEDED(hr), "GetCurrentInfo returned %#x\n", hr);
-            ok(folder_settings.ViewMode == FVM_LIST, "view mode is %d, expected %d\n", folder_settings.ViewMode, FVM_LIST);
+            ok(folder_settings.ViewMode == FVM_LIST,
+               "view mode is %d, expected FVM_LIST\n",
+               folder_settings.ViewMode);
 
             hr = IShellView2_DestroyViewWindow(shell_view2);
             ok(SUCCEEDED(hr), "DestroyViewWindow returned %#x\n", hr);
@@ -201,7 +233,8 @@ static UINT_PTR CALLBACK create_view_window2_hook(HWND dlg, UINT msg, WPARAM wPa
             ok(SUCCEEDED(hr), "GetCurrentInfo returned %#x\n", hr);
             ok(folder_settings.ViewMode == FVM_DETAILS ||
                broken(folder_settings.ViewMode == FVM_LIST), /* Win9x */
-               "view mode is %d, expected %d\n", folder_settings.ViewMode, FVM_DETAILS);
+               "view mode is %d, expected FVM_DETAILS\n",
+               folder_settings.ViewMode);
 
 cleanup:
             if (shell_view2) IShellView2_Release(shell_view2);
@@ -241,7 +274,7 @@ static void test_create_view_window2(void)
 
     ofn.lStructSize = sizeof(ofn);
     ofn.lpstrFile = filename;
-    ofn.nMaxFile = 1042;
+    ofn.nMaxFile = 1024;
     ofn.lpfnHook = create_view_window2_hook;
     ofn.Flags = OFN_ENABLEHOOK | OFN_EXPLORER;
     ret = GetOpenFileNameA(&ofn);
@@ -258,7 +291,7 @@ static void test_create_view_template(void)
 
     ofn.lStructSize = sizeof(ofn);
     ofn.lpstrFile = filename;
-    ofn.nMaxFile = 1042;
+    ofn.nMaxFile = 1024;
     ofn.lpfnHook = (LPOFNHOOKPROC)template_hook;
     ofn.Flags = OFN_ENABLEHOOK | OFN_EXPLORER| OFN_ENABLETEMPLATE;
     ofn.hInstance = GetModuleHandleA(NULL);
@@ -270,9 +303,694 @@ static void test_create_view_template(void)
     ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
 }
 
+/* test cases for resizing of the file dialog */
+struct {
+    DWORD flags;
+    int resize_folderchange;/* change in CDN_FOLDERCHANGE handler */
+    int resize_timer1;      /* change in first WM_TIMER handler */
+    int resize_check;       /* expected change (in second  WM_TIMER handler) */
+    BOOL todo;              /* mark that test todo_wine */
+    BOOL testcontrols;      /* test resizing and moving of the controls */
+} resize_testcases[] = {
+    { 0                , 10, 10, 20,FALSE,FALSE},   /* 0 */
+    { 0                ,-10,-10,-20,FALSE,FALSE},
+    { OFN_ENABLESIZING ,  0,  0,  0,FALSE,FALSE},
+    { OFN_ENABLESIZING ,  0,-10,  0,FALSE,FALSE},
+    { OFN_ENABLESIZING ,  0, 10, 10,FALSE, TRUE},
+    { OFN_ENABLESIZING ,-10,  0, 10,FALSE,FALSE},   /* 5 */
+    { OFN_ENABLESIZING , 10,  0, 10,FALSE,FALSE},
+    { OFN_ENABLESIZING ,  0, 10, 20,FALSE,FALSE},
+    /* mark the end */
+    { 0xffffffff }
+};
+
+static LONG_PTR WINAPI resize_template_hook(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static RECT initrc, rc;
+    static int index, count;
+    static int gotSWP_bottom, gotShowWindow;
+    HWND parent = GetParent( dlg);
+    int resize;
+#define MAXNRCTRLS 30
+    static RECT ctrlrcs[MAXNRCTRLS];
+    static int ctrlids[MAXNRCTRLS];
+    static HWND ctrls[MAXNRCTRLS];
+    static int nrctrls;
+
+    switch( msg)
+    {
+        case WM_INITDIALOG:
+        {
+            DWORD style;
+
+            index = ((OPENFILENAME*)lParam)->lCustData;
+            count = 0;
+            gotSWP_bottom = gotShowWindow = 0;
+            /* test style */
+            style = GetWindowLong( parent, GWL_STYLE);
+            if( resize_testcases[index].flags & OFN_ENABLESIZING)
+                if( !(style & WS_SIZEBOX)) {
+                    win_skip( "OFN_ENABLESIZING flag not supported.\n");
+                    resizesupported = FALSE;
+                    PostMessage( parent, WM_COMMAND, IDCANCEL, 0);
+                } else
+                    ok( style & WS_SIZEBOX,
+                            "testid %d: dialog should have a WS_SIZEBOX style.\n", index);
+            else
+                ok( !(style & WS_SIZEBOX),
+                        "testid %d: dialog should not have a WS_SIZEBOX style.\n", index);
+            break;
+        }
+        case WM_NOTIFY:
+        {
+            if(( (LPNMHDR)lParam)->code == CDN_FOLDERCHANGE){
+                GetWindowRect( parent, &initrc);
+                if( (resize  = resize_testcases[index].resize_folderchange)){
+                    MoveWindow( parent, initrc.left,initrc.top, initrc.right - initrc.left + resize,
+                            initrc.bottom - initrc.top + resize, TRUE);
+                }
+                SetTimer( dlg, 0, 100, 0);
+            }
+            break;
+        }
+        case WM_TIMER:
+        {
+            if( count == 0){
+                /* store the control rectangles */
+                if( resize_testcases[index].testcontrols) {
+                    HWND ctrl;
+                    int i;
+                    for( i = 0, ctrl = GetWindow( parent, GW_CHILD);
+                            i < MAXNRCTRLS && ctrl;
+                            i++, ctrl = GetWindow( ctrl, GW_HWNDNEXT)) {
+                        ctrlids[i] = GetDlgCtrlID( ctrl);
+                        GetWindowRect( ctrl, &ctrlrcs[i]);
+                        MapWindowPoints( NULL, parent, (LPPOINT) &ctrlrcs[i], 2);
+                        ctrls[i] = ctrl;
+                    }
+                    nrctrls = i;
+                }
+                if( (resize  = resize_testcases[index].resize_timer1)){
+                    GetWindowRect( parent, &rc);
+                    MoveWindow( parent, rc.left,rc.top, rc.right - rc.left + resize,
+                            rc.bottom - rc.top + resize, TRUE);
+                }
+            } else if( count == 1){
+                resize  = resize_testcases[index].resize_check;
+                GetWindowRect( parent, &rc);
+                if( resize_testcases[index].todo){
+                    todo_wine {
+                        ok( resize == rc.right - rc.left - initrc.right + initrc.left,
+                            "testid %d size-x change %d expected %d\n", index,
+                            rc.right - rc.left - initrc.right + initrc.left, resize);
+                        ok( resize == rc.bottom - rc.top - initrc.bottom + initrc.top,
+                            "testid %d size-y change %d expected %d\n", index,
+                            rc.bottom - rc.top - initrc.bottom + initrc.top, resize);
+                    }
+                }else{
+                    ok( resize == rc.right - rc.left - initrc.right + initrc.left,
+                        "testid %d size-x change %d expected %d\n", index,
+                        rc.right - rc.left - initrc.right + initrc.left, resize);
+                    ok( resize == rc.bottom - rc.top - initrc.bottom + initrc.top,
+                        "testid %d size-y change %d expected %d\n", index,
+                        rc.bottom - rc.top - initrc.bottom + initrc.top, resize);
+                }
+                if( resize_testcases[index].testcontrols) {
+                    int i;
+                    RECT rc;
+                    for( i = 0; i < nrctrls; i++) {
+                        GetWindowRect( ctrls[i], &rc);
+                        MapWindowPoints( NULL, parent, (LPPOINT) &rc, 2);
+                        switch( ctrlids[i]){
+
+/* test if RECT R1, moved and sized result in R2 */
+#define TESTRECTS( R1, R2, Mx, My, Sx, Sy) \
+         ((R1).left + (Mx) ==(R2).left \
+        &&(R1).top + (My) ==(R2).top \
+        &&(R1).right + (Mx) + (Sx) == (R2).right \
+        &&(R1).bottom + (My) + (Sy) ==(R2).bottom)
+
+                            /* sized horizontal and moved vertical */
+                            case cmb1:
+                            case edt1:
+                                ok( TESTRECTS( ctrlrcs[i], rc, 0, 10, 10, 0) ||
+                                    broken(TESTRECTS( ctrlrcs[i], rc, 0, 10, 0, 0)),/*win98*/
+                                    "control id %03x should have sized horizontally and moved vertically, before %d,%d-%d,%d after  %d,%d-%d,%d\n",
+                                    ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
+                                    ctrlrcs[i].right, ctrlrcs[i].bottom,
+                                    rc.left, rc.top, rc.right, rc.bottom);
+                                break;
+                            /* sized horizontal and vertical */
+                            case lst2:
+                                ok( TESTRECTS( ctrlrcs[i], rc, 0, 0, 10, 10),
+                                    "control id %03x should have sized horizontally and vertically, before %d,%d-%d,%d after  %d,%d-%d,%d\n",
+                                    ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
+                                    ctrlrcs[i].right, ctrlrcs[i].bottom,
+                                    rc.left, rc.top, rc.right, rc.bottom);
+                                break;
+                            /* moved horizontal and vertical */
+                            case IDCANCEL:
+                            case pshHelp:
+                                ok( TESTRECTS( ctrlrcs[i], rc, 10, 10, 0, 0) ||
+                                    broken(TESTRECTS( ctrlrcs[i], rc, 0, 10, 0, 0)),/*win98*/
+                                    "control id %03x should have moved horizontally and vertically, before %d,%d-%d,%d after  %d,%d-%d,%d\n",
+                                    ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
+                                    ctrlrcs[i].right, ctrlrcs[i].bottom,
+                                    rc.left, rc.top, rc.right, rc.bottom);
+                                break;
+                            /* moved vertically */
+                            case chx1:
+                            case stc2:
+                            case stc3:
+                                ok( TESTRECTS( ctrlrcs[i], rc, 0, 10, 0, 0),
+                                    "control id %03x should have moved vertically, before %d,%d-%d,%d after  %d,%d-%d,%d\n",
+                                    ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
+                                    ctrlrcs[i].right, ctrlrcs[i].bottom,
+                                    rc.left, rc.top, rc.right, rc.bottom);
+                                break;
+                            /* resized horizontal */
+                            case cmb2: /* aka IDC_LOOKIN */
+                                ok( TESTRECTS( ctrlrcs[i], rc, 0, 0, 10, 0)||
+                                        TESTRECTS( ctrlrcs[i], rc, 0, 0, 0, 0), /* Vista and higher */
+                                    "control id %03x should have resized horizontally, before %d,%d-%d,%d after  %d,%d-%d,%d\n",
+                                    ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
+                                    ctrlrcs[i].right, ctrlrcs[i].bottom,
+                                    rc.left, rc.top, rc.right, rc.bottom);
+                                break;
+                            /* non moving non sizing controls */
+                            case stc4:
+                                ok( TESTRECTS( rc, ctrlrcs[i], 0, 0, 0, 0),
+                                    "control id %03x was moved/resized, before %d,%d-%d,%d after  %d,%d-%d,%d\n",
+                                    ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
+                                    ctrlrcs[i].right, ctrlrcs[i].bottom,
+                                    rc.left, rc.top, rc.right, rc.bottom);
+                                break;
+                            /* todo_wine: non moving non sizing controls */
+                            case lst1:
+todo_wine
+                                ok( TESTRECTS( rc, ctrlrcs[i], 0, 0, 0, 0),
+                                    "control id %03x was moved/resized, before %d,%d-%d,%d after  %d,%d-%d,%d\n",
+                                    ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
+                                    ctrlrcs[i].right, ctrlrcs[i].bottom,
+                                    rc.left, rc.top, rc.right, rc.bottom);
+                                break;
+                            /* don't test: id is not unique */
+                            case IDOK:
+                            case stc1:
+                            case 0:
+                            case  -1:
+                                break;
+                            default:
+                                trace("untested control id %03x before %d,%d-%d,%d after  %d,%d-%d,%d\n",
+                                    ctrlids[i], ctrlrcs[i].left, ctrlrcs[i].top,
+                                    ctrlrcs[i].right, ctrlrcs[i].bottom,
+                                    rc.left, rc.top, rc.right, rc.bottom);
+#undef TESTRECTS
+#undef MAXNRCTRLS
+                        }
+                    }
+                }
+                KillTimer( dlg, 0);
+                PostMessage( parent, WM_COMMAND, IDCANCEL, 0);
+            }
+            count++;
+        }
+        break;
+        case WM_WINDOWPOSCHANGING:
+        {
+            WINDOWPOS *pwp = (WINDOWPOS *)lParam;
+            if(  !index && pwp->hwndInsertAfter == HWND_BOTTOM){
+                gotSWP_bottom = 1;
+                ok( gotShowWindow == 0, "The WM_WINDOWPOSCHANGING message came after a WM_SHOWWINDOW message\n");
+            }
+        }
+        break;
+        case WM_SHOWWINDOW:
+        {
+            if(  !index){
+                gotShowWindow = 1;
+                ok( gotSWP_bottom == 1, "No WM_WINDOWPOSCHANGING message came before a WM_SHOWWINDOW message\n");
+            }
+        }
+        break;
+    }
+    return 0;
+}
+
+static void test_resize(void)
+{
+    OPENFILENAME ofn = { sizeof(OPENFILENAME)};
+    char filename[1024] = {0};
+    DWORD ret;
+    int i;
+
+    ofn.lpstrFile = filename;
+    ofn.nMaxFile = 1024;
+    ofn.lpfnHook = (LPOFNHOOKPROC) resize_template_hook;
+    ofn.hInstance = GetModuleHandle(NULL);
+    ofn.lpTemplateName = "template_sz";
+    for( i = 0; resize_testcases[i].flags != 0xffffffff; i++) {
+        ofn.lCustData = i;
+        ofn.Flags = resize_testcases[i].flags |
+            OFN_ENABLEHOOK | OFN_EXPLORER| OFN_ENABLETEMPLATE | OFN_SHOWHELP ;
+        ret = GetOpenFileName(&ofn);
+        ok(!ret, "GetOpenFileName returned %#x\n", ret);
+        ret = CommDlgExtendedError();
+        ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
+    }
+}
+
+/* test cases for control message IDOK */
+/* Show case for bug #19079 */
+static struct {
+    int  retval;        /* return code of the message handler */
+    BOOL setmsgresult;  /* set the result in the DWLP_MSGRESULT */
+    BOOL usemsgokstr;   /* use the FILEOKSTRING message instead of WM_NOTIFY:CDN_FILEOK */
+    BOOL do_subclass;   /* subclass the dialog hook procedure */
+    BOOL expclose;      /* is the dialog expected to close ? */
+    BOOL actclose;      /* has the dialog actually closed ? */
+} ok_testcases[] = {
+    { 0,        FALSE,  FALSE,  FALSE,  TRUE},
+    { 0,         TRUE,  FALSE,  FALSE,  TRUE},
+    { 0,        FALSE,  FALSE,   TRUE,  TRUE},
+    { 0,         TRUE,  FALSE,   TRUE,  TRUE},
+    { 1,        FALSE,  FALSE,  FALSE,  TRUE},
+    { 1,         TRUE,  FALSE,  FALSE, FALSE},
+    { 1,        FALSE,  FALSE,   TRUE, FALSE},
+    { 1,         TRUE,  FALSE,   TRUE, FALSE},
+    /* FILEOKSTRING tests */
+    { 1,         TRUE,   TRUE,  FALSE, FALSE},
+    { 1,        FALSE,   TRUE,   TRUE, FALSE},
+    /* mark the end */
+    { -1 }
+};
+
+/* test_ok_wndproc can be used as hook procedure or a subclass
+ * window proc for the file dialog */
+static LONG_PTR WINAPI test_ok_wndproc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    HWND parent = GetParent( dlg);
+    static int index;
+    static UINT msgFILEOKSTRING;
+    if (msg == WM_INITDIALOG)
+    {
+        index = ((OPENFILENAME*)lParam)->lCustData;
+        ok_testcases[index].actclose = TRUE;
+        msgFILEOKSTRING = RegisterWindowMessageA( FILEOKSTRING);
+    }
+    if( msg == WM_NOTIFY) {
+        if(((LPNMHDR)lParam)->code == CDN_FOLDERCHANGE) {
+            SetTimer( dlg, 0, 100, 0);
+            PostMessage( parent, WM_COMMAND, IDOK, 0);
+            return FALSE;
+        } else if(((LPNMHDR)lParam)->code == CDN_FILEOK) {
+            if( ok_testcases[index].usemsgokstr)
+                return FALSE;
+            if( ok_testcases[index].setmsgresult)
+                SetWindowLongPtrA( dlg, DWLP_MSGRESULT, ok_testcases[index].retval);
+            return ok_testcases[index].retval;
+        }
+    }
+    if( msg == msgFILEOKSTRING) {
+        if( !ok_testcases[index].usemsgokstr)
+            return FALSE;
+        if( ok_testcases[index].setmsgresult)
+            SetWindowLongPtrA( dlg, DWLP_MSGRESULT, ok_testcases[index].retval);
+        return ok_testcases[index].retval;
+    }
+    if( msg == WM_TIMER) {
+        /* the dialog did not close automatically */
+        ok_testcases[index].actclose = FALSE;
+        KillTimer( dlg, 0);
+        PostMessage( parent, WM_COMMAND, IDCANCEL, 0);
+        return FALSE;
+    }
+    if( ok_testcases[index].do_subclass)
+        return DefWindowProc( dlg, msg, wParam, lParam);
+    return FALSE;
+}
+
+static LONG_PTR WINAPI ok_template_hook(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    if (msg == WM_SETFONT)
+        SetWindowLongPtrA( dlg, GWLP_WNDPROC, (LONG_PTR) test_ok_wndproc);
+    return FALSE;
+}
+
+static void test_ok(void)
+{
+    OPENFILENAME ofn = { sizeof(OPENFILENAME)};
+    char filename[1024] = {0};
+    char tmpfilename[ MAX_PATH];
+    char curdir[MAX_PATH];
+    int i;
+    DWORD ret;
+
+    ok(GetCurrentDirectoryA(sizeof(curdir), curdir) != 0, "Failed to get current dir err %d\n", GetLastError());
+    if (!GetTempFileNameA(".", "txt", 0, tmpfilename)) {
+        skip("Failed to create a temporary file name\n");
+        return;
+    }
+    ofn.lpstrFile = filename;
+    ofn.nMaxFile = 1024;
+    ofn.hInstance = GetModuleHandle(NULL);
+    ofn.lpTemplateName = "template1";
+    ofn.Flags =  OFN_ENABLEHOOK | OFN_EXPLORER| OFN_ENABLETEMPLATE ;
+    for( i = 0; ok_testcases[i].retval != -1; i++) {
+        strcpy( filename, tmpfilename);
+        ofn.lCustData = i;
+        ofn.lpfnHook = ok_testcases[i].do_subclass
+            ? (LPOFNHOOKPROC) ok_template_hook
+            : (LPOFNHOOKPROC) test_ok_wndproc;
+        ret = GetOpenFileNameA(&ofn);
+        ok( ok_testcases[i].expclose == ok_testcases[i].actclose,
+                "testid %d: Open File dialog should %shave closed.\n", i,
+                ok_testcases[i].expclose ? "" : "NOT ");
+        ok(ret == ok_testcases[i].expclose, "testid %d: GetOpenFileName returned %#x\n", i, ret);
+        ret = CommDlgExtendedError();
+        ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
+        ok(SetCurrentDirectoryA(curdir), "Failed to restore current dir err %d\n", GetLastError());
+    }
+    ret =  DeleteFileA( tmpfilename);
+    ok( ret, "Failed to delete temporary file %s err %d\n", tmpfilename, GetLastError());
+}
+
+/* test arranging with a custom template */
+typedef struct {
+    int x, y;  /* left, top coordinates */
+    int cx, cy; /* width and height */
+} posz;
+static struct {
+   int nrcontrols;    /* 0: no controls, 1: just the stc32 control 2: with button */
+   posz poszDlg;
+   posz poszStc32;
+   posz poszBtn;
+   DWORD ofnflags;
+} arrange_tests[] = {
+    /* do not change the first two cases: used to get the uncustomized sizes */
+    { 0, {0},{0},{0},0 },
+    { 0, {0},{0},{0}, OFN_SHOWHELP},
+    /* two tests with just a subdialog, no controls */
+    { 0, {0, 0, 316, 76},{0},{0},0 },
+    { 0, {0, 0, 100, 76},{0},{0}, OFN_SHOWHELP},
+    /* now with a control with id stc32 */
+    { 1, {0, 0, 316, 76} ,{0, 0, 204, 76,},{0},0 }, /* bug #17748*/
+    { 1, {0, 0, 316, 76} ,{0, 0, 204, 76,},{0}, OFN_SHOWHELP}, /* bug #17748*/
+    /* tests with size of the stc32 control higher or wider then the standard dialog */
+    { 1, {0, 0, 316, 170} ,{0, 0, 204, 170,},{0},0 },
+    { 1, {0, 0, 316, 165} ,{0, 0, 411, 165,},{0}, OFN_SHOWHELP },
+    /* move the stc32 control around */
+    { 1, {0, 0, 300, 100} ,{73, 17, 50, 50,},{0},0 },
+    /* add control */
+    { 2, {0, 0, 280, 100} ,{0, 0, 50, 50,},{300,20,30,30},0 },
+    /* enable resizing should make the dialog bigger */
+    { 0, {0},{0},{0}, OFN_SHOWHELP|OFN_ENABLESIZING},
+    /* mark the end */
+    { -1 }
+};
+
+static LONG_PTR WINAPI template_hook_arrange(HWND dlgChild, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static int index, fixhelp;
+    static posz posz0[2];
+    static RECT clrcParent, clrcChild, rcStc32;
+    static HWND hwndStc32;
+    HWND dlgParent;
+
+    dlgParent = GetParent( dlgChild);
+    if (msg == WM_INITDIALOG) {
+        index = ((OPENFILENAME*)lParam)->lCustData;
+        /* get the positions before rearrangement */
+        GetClientRect( dlgParent, &clrcParent);
+        GetClientRect( dlgChild, &clrcChild);
+        hwndStc32 = GetDlgItem( dlgChild, stc32);
+        if( hwndStc32)  GetWindowRect( hwndStc32, &rcStc32);
+    }
+    if (msg == WM_NOTIFY && ((LPNMHDR)lParam)->code == CDN_FOLDERCHANGE) {
+        RECT wrcParent;
+
+        GetWindowRect( dlgParent, &wrcParent);
+        /* the fist two "tests" just save the dialogs position, with and without
+         * help button */
+        if( index == 0) {
+            posz0[0].x = wrcParent.left;
+            posz0[0].y = wrcParent.top;
+            posz0[0].cx = wrcParent.right - wrcParent.left;
+            posz0[0].cy = wrcParent.bottom - wrcParent.top;
+        } else if( index == 1) {
+            posz0[1].x = wrcParent.left;
+            posz0[1].y = wrcParent.top;
+            posz0[1].cx = wrcParent.right - wrcParent.left;
+            posz0[1].cy = wrcParent.bottom - wrcParent.top;
+            fixhelp = posz0[1].cy - posz0[0].cy;
+        } else {
+            /* the real tests */
+            int withhelp;
+            int expectx, expecty;
+            DWORD style;
+
+            withhelp = (arrange_tests[index].ofnflags & OFN_SHOWHELP) != 0;
+            GetWindowRect( dlgParent, &wrcParent);
+            if( !hwndStc32) {
+                /* case with no custom subitem with stc32:
+                 * default to all custom controls below the standard */
+                expecty = posz0[withhelp].cy + clrcChild.bottom;
+                expectx =  posz0[withhelp].cx;
+            } else {
+                /* special case: there is a control with id stc32 */
+                /* expected height */
+                expecty = posz0[withhelp].cy;
+                if( rcStc32.bottom - rcStc32.top > clrcParent.bottom) {
+                    expecty +=  clrcChild.bottom -  clrcParent.bottom;
+                    if( !withhelp) expecty += fixhelp;
+                }
+                else
+                    expecty +=  clrcChild.bottom - ( rcStc32.bottom - rcStc32.top) ;
+                /* expected width */
+                expectx = posz0[withhelp].cx;
+                if( rcStc32.right - rcStc32.left > clrcParent.right) {
+                    expectx +=  clrcChild.right -  clrcParent.right;
+                }
+                else
+                    expectx +=  clrcChild.right - ( rcStc32.right - rcStc32.left) ;
+            }
+            style = GetWindowLong( dlgParent, GWL_STYLE);
+            if( !(style & WS_SIZEBOX)) {
+                /* without the OFN_ENABLESIZING flag */
+                ok( wrcParent.bottom - wrcParent.top == expecty,
+                        "Wrong height of dialog %d, expected %d\n",
+                        wrcParent.bottom - wrcParent.top, expecty);
+                ok( wrcParent.right - wrcParent.left == expectx,
+                        "Wrong width of dialog %d, expected %d\n",
+                        wrcParent.right - wrcParent.left, expectx);
+            } else todo_wine {
+                /* with the OFN_ENABLESIZING flag */
+                ok( wrcParent.bottom - wrcParent.top > expecty,
+                        "Wrong height of dialog %d, expected more than %d\n",
+                        wrcParent.bottom - wrcParent.top, expecty);
+                ok( wrcParent.right - wrcParent.left > expectx,
+                        "Wrong width of dialog %d, expected more than %d\n",
+                        wrcParent.right - wrcParent.left, expectx);
+            }
+
+        }
+        PostMessage( dlgParent, WM_COMMAND, IDCANCEL, 0);
+    }
+    return 0;
+}
+
+static void test_arrange(void)
+{
+    OPENFILENAMEA ofn = {0};
+    char filename[1024] = {0};
+    DWORD ret;
+    HRSRC hRes;
+    HANDLE hDlgTmpl;
+    LPBYTE pv;
+    DLGTEMPLATE *template;
+    DLGITEMTEMPLATE *itemtemplateStc32, *itemtemplateBtn;
+    int i;
+
+    /* load subdialog template into memory */
+    hRes = FindResource( GetModuleHandle(NULL), "template_stc32", (LPSTR)RT_DIALOG);
+    hDlgTmpl = LoadResource( GetModuleHandle(NULL), hRes );
+    /* get pointers to the structures for the dialog and the controls */
+    pv = LockResource( hDlgTmpl );
+    template = (DLGTEMPLATE*)pv;
+    if( template->x != 11111) {
+        win_skip("could not find the dialog template\n");
+        return;
+    }
+    /* skip dialog template, menu, class and title */
+    pv +=  sizeof(DLGTEMPLATE);
+    pv += 3 * sizeof(WORD);
+    /* skip font info */
+    while( *(WORD*)pv)
+        pv += sizeof(WORD);
+    pv += sizeof(WORD);
+    /* align on 32 bit boundaries */
+    pv = (LPBYTE)(((UINT_PTR)pv + 3 ) & ~3);
+    itemtemplateStc32 = (DLGITEMTEMPLATE*)pv;
+    if( itemtemplateStc32->x != 22222) {
+        win_skip("could not find the first item template\n");
+        return;
+    }
+    /* skip itemtemplate, class, title and creation data */
+    pv += sizeof(DLGITEMTEMPLATE);
+    pv +=  4 * sizeof(WORD);
+    /* align on 32 bit boundaries */
+    pv = (LPBYTE)(((UINT_PTR)pv + 3 ) & ~3);
+    itemtemplateBtn = (DLGITEMTEMPLATE*)pv;
+    if( itemtemplateBtn->x != 12345) {
+        win_skip("could not find the second item template\n");
+        return;
+    }
+
+    ofn.lStructSize = sizeof(ofn);
+    ofn.lpstrFile = filename;
+    ofn.nMaxFile = 1024;
+    ofn.lpfnHook = (LPOFNHOOKPROC)template_hook_arrange;
+    ofn.hInstance = hDlgTmpl;
+    ofn.lpstrFilter="text\0*.txt\0All\0*\0\0";
+    for( i = 0; arrange_tests[i].nrcontrols != -1; i++) {
+        ofn.lCustData = i;
+        ofn.Flags = OFN_ENABLEHOOK | OFN_EXPLORER| OFN_ENABLETEMPLATEHANDLE | OFN_HIDEREADONLY |
+            arrange_tests[i].ofnflags;
+        template->cdit = arrange_tests[i].nrcontrols;
+        template->x = arrange_tests[i].poszDlg.x;
+        template->y = arrange_tests[i].poszDlg.y;
+        template->cx = arrange_tests[i].poszDlg.cx;
+        template->cy = arrange_tests[i].poszDlg.cy;
+        itemtemplateStc32->x = arrange_tests[i].poszStc32.x;
+        itemtemplateStc32->y = arrange_tests[i].poszStc32.y;
+        itemtemplateStc32->cx = arrange_tests[i].poszStc32.cx;
+        itemtemplateStc32->cy = arrange_tests[i].poszStc32.cy;
+        itemtemplateBtn->x = arrange_tests[i].poszBtn.x;
+        itemtemplateBtn->y = arrange_tests[i].poszBtn.y;
+        itemtemplateBtn->cx = arrange_tests[i].poszBtn.cx;
+        itemtemplateBtn->cy = arrange_tests[i].poszBtn.cy;
+        ret = GetOpenFileNameA(&ofn);
+        ok(!ret, "GetOpenFileNameA returned %#x\n", ret);
+        ret = CommDlgExtendedError();
+        ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
+    }
+}
+
+static CHAR SYSDIR[MAX_PATH];
+
+static UINT_PTR CALLBACK path_hook_proc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    LPNMHDR nmh;
+
+    if( msg == WM_NOTIFY)
+    {
+        nmh = (LPNMHDR) lParam;
+        if( nmh->code == CDN_INITDONE)
+        {
+            PostMessage( GetParent(hDlg), WM_COMMAND, IDCANCEL, FALSE);
+        }
+        else if ( nmh->code == CDN_FOLDERCHANGE)
+        {
+            char buf[1024];
+            int ret;
+
+            memset(buf, 0x66, sizeof(buf));
+            ret = SendMessageA( GetParent(hDlg), CDM_GETFOLDERPATH, sizeof(buf), (LPARAM)buf);
+            ok(!lstrcmpiA(SYSDIR, buf), "Expected '%s', got '%s'\n", SYSDIR, buf);
+            ok(lstrlenA(SYSDIR) + 1 == ret, "Expected %d, got %d\n", lstrlenA(SYSDIR) + 1, ret);
+        }
+    }
+
+    return 0;
+}
+
+static void test_getfolderpath(void)
+{
+    OPENFILENAMEA ofn;
+    BOOL result;
+    char szFileName[MAX_PATH] = "";
+    char szInitialDir[MAX_PATH];
+
+    /* We need to pick a different directory as the other tests because of new
+     * Windows 7 behavior.
+     */
+    GetSystemDirectory(szInitialDir, MAX_PATH);
+    lstrcpyA(SYSDIR, szInitialDir);
+
+    ZeroMemory(&ofn, sizeof(ofn));
+
+    ofn.lStructSize = sizeof(ofn);
+    ofn.hwndOwner = NULL;
+    ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
+    ofn.lpstrFile = szFileName;
+    ofn.nMaxFile = MAX_PATH;
+    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLEHOOK;
+    ofn.lpstrDefExt = "txt";
+    ofn.lpfnHook = path_hook_proc;
+    ofn.lpstrInitialDir = szInitialDir;
+
+    result = GetOpenFileNameA(&ofn);
+    ok(0 == result, "expected 0, got %d\n", result);
+    ok(0 == CommDlgExtendedError(), "expected 0, got %d\n",
+       CommDlgExtendedError());
+
+    result = GetSaveFileNameA(&ofn);
+    ok(0 == result, "expected 0, got %d\n", result);
+    ok(0 == CommDlgExtendedError(), "expected 0, got %d\n",
+       CommDlgExtendedError());
+}
+
+static void test_resizable2(void)
+{
+    OPENFILENAMEA ofn = {0};
+    char filename[1024] = "pls press Enter if sizable, Esc otherwise";
+    DWORD ret;
+
+    /* interactive because there is no hook function */
+    if( !winetest_interactive) {
+        skip( "some interactive resizable dialog tests (set WINETEST_INTERACTIVE=1)\n");
+        return;
+    }
+    ofn.lStructSize = sizeof(ofn);
+    ofn.lpstrFile = filename;
+    ofn.nMaxFile = 1024;
+    ofn.lpfnHook = NULL;
+    ofn.hInstance = GetModuleHandleA(NULL);
+    ofn.lpTemplateName = "template1";
+    ofn.Flags = OFN_EXPLORER;
+#define ISSIZABLE 1
+    ret = GetOpenFileNameA(&ofn);
+    ok( ret == ISSIZABLE, "File Dialog should have been sizable\n");
+    ret = CommDlgExtendedError();
+    ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
+    ofn.Flags = OFN_EXPLORER | OFN_ENABLETEMPLATE;
+    ret = GetOpenFileNameA(&ofn);
+    ok( ret != ISSIZABLE, "File Dialog should NOT have been sizable\n");
+    ret = CommDlgExtendedError();
+    ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
+    ofn.Flags = OFN_EXPLORER | OFN_ENABLETEMPLATEHANDLE;
+    ofn.hInstance = LoadResource( GetModuleHandle(NULL), FindResource( GetModuleHandle(NULL), "template1", (LPSTR)RT_DIALOG));
+    ofn.lpTemplateName = NULL;
+    ret = GetOpenFileNameA(&ofn);
+    ok( ret != ISSIZABLE, "File Dialog should NOT have been sizable\n");
+    ret = CommDlgExtendedError();
+    ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
+    ofn.Flags = OFN_EXPLORER | OFN_ENABLEHOOK;
+    ret = GetOpenFileNameA(&ofn);
+    ok( ret != ISSIZABLE, "File Dialog should NOT have been sizable\n");
+    ret = CommDlgExtendedError();
+    ok(!ret, "CommDlgExtendedError returned %#x\n", ret);
+#undef ISSIZABLE
+}
+
 START_TEST(filedlg)
 {
     test_DialogCancel();
     test_create_view_window2();
     test_create_view_template();
+    test_arrange();
+    test_resize();
+    test_ok();
+    test_getfolderpath();
+    if( resizesupported) test_resizable2();
 }
diff --git a/rostests/winetests/comdlg32/fontdlg.c b/rostests/winetests/comdlg32/fontdlg.c
new file mode 100644 (file)
index 0000000..57c1d90
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Unit test suite for comdlg32 API functions: font dialogs
+ *
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wingdi.h"
+#include "winspool.h"
+#include "winuser.h"
+#include "objbase.h"
+
+#include "commdlg.h"
+
+#include "wine/test.h"
+
+static int get_dpiy(void)
+{
+    HDC hdc;
+    int result;
+
+    hdc = GetDC(0);
+    result = GetDeviceCaps(hdc, LOGPIXELSY);
+    ReleaseDC(0, hdc);
+
+    return result;
+}
+
+static HDC get_printer_ic(void)
+{
+    PRINTER_INFO_2A *info;
+    DWORD info_size, num_printers=0;
+    BOOL ret;
+    HDC result=NULL;
+
+    EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &info_size, &num_printers);
+
+    if (info_size == 0)
+        return NULL;
+
+    info = HeapAlloc(GetProcessHeap(), 0, info_size);
+
+    ret = EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)info, info_size, &info_size, &num_printers);
+
+    if (ret)
+        result = CreateICA(info->pDriverName, info->pPrinterName, NULL, NULL);
+
+    HeapFree(GetProcessHeap(), 0, info);
+
+    return result;
+}
+
+static UINT_PTR CALLBACK CFHookProcOK(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch (msg)
+    {
+    case WM_INITDIALOG:
+        PostMessageA(hdlg, WM_COMMAND, IDOK, FALSE);
+        return 0;
+    default:
+        return 0;
+    }
+}
+
+static void test_ChooseFontA(void)
+{
+    LOGFONTA lfa;
+    CHOOSEFONTA cfa;
+    BOOL ret;
+    int dpiy = get_dpiy();
+    int expected_pointsize, expected_lfheight;
+    HDC printer_ic;
+
+    memset(&lfa, 0, sizeof(LOGFONTA));
+    lfa.lfHeight = -16;
+    lfa.lfWeight = FW_NORMAL;
+    strcpy(lfa.lfFaceName, "Symbol");
+
+    memset(&cfa, 0, sizeof(CHOOSEFONTA));
+    cfa.lStructSize = sizeof(cfa);
+    cfa.lpLogFont = &lfa;
+    cfa.Flags = CF_ENABLEHOOK|CF_INITTOLOGFONTSTRUCT|CF_SCREENFONTS;
+    cfa.lpfnHook = CFHookProcOK;
+
+    ret = ChooseFontA(&cfa);
+
+    expected_pointsize = MulDiv(16, 72, dpiy) * 10;
+    expected_lfheight = -MulDiv(expected_pointsize, dpiy, 720);
+
+    ok(ret == TRUE, "ChooseFontA returned FALSE\n");
+    ok(cfa.iPointSize == expected_pointsize, "Expected %i, got %i\n", expected_pointsize, cfa.iPointSize);
+    ok(lfa.lfHeight == expected_lfheight, "Expected %i, got %i\n", expected_lfheight, lfa.lfHeight);
+    ok(lfa.lfWeight == FW_NORMAL, "Expected FW_NORMAL, got %i\n", lfa.lfWeight);
+    ok(strcmp(lfa.lfFaceName, "Symbol") == 0, "Expected Symbol, got %s\n", lfa.lfFaceName);
+
+    printer_ic = get_printer_ic();
+    if (!printer_ic)
+        skip("can't get a DC for a local printer\n");
+    else
+    {
+        memset(&lfa, 0, sizeof(LOGFONTA));
+        lfa.lfHeight = -16;
+        lfa.lfWeight = FW_NORMAL;
+        strcpy(lfa.lfFaceName, "Symbol");
+
+        memset(&cfa, 0, sizeof(CHOOSEFONTA));
+        cfa.lStructSize = sizeof(cfa);
+        cfa.lpLogFont = &lfa;
+        cfa.Flags = CF_ENABLEHOOK|CF_INITTOLOGFONTSTRUCT|CF_PRINTERFONTS;
+        cfa.hDC = printer_ic;
+        cfa.lpfnHook = CFHookProcOK;
+
+        ret = ChooseFontA(&cfa);
+
+        expected_pointsize = MulDiv(16, 72, dpiy) * 10;
+        expected_lfheight = -MulDiv(expected_pointsize, dpiy, 720);
+
+        ok(ret == TRUE, "ChooseFontA returned FALSE\n");
+        ok(cfa.iPointSize == expected_pointsize, "Expected %i, got %i\n", expected_pointsize, cfa.iPointSize);
+        ok(lfa.lfHeight == expected_lfheight, "Expected %i, got %i\n", expected_lfheight, lfa.lfHeight);
+        ok(lfa.lfWeight == FW_NORMAL, "Expected FW_NORMAL, got %i\n", lfa.lfWeight);
+        ok(strcmp(lfa.lfFaceName, "Symbol") == 0, "Expected Symbol, got %s\n", lfa.lfFaceName);
+
+        DeleteDC(printer_ic);
+    }
+}
+
+START_TEST(fontdlg)
+{
+    test_ChooseFontA();
+}
index ec63da9..f021b01 100644 (file)
@@ -246,6 +246,11 @@ static void test_PrintDlgExW(void)
     PrintDlg(NULL);
     SetLastError(0xdeadbeef);
     res = pPrintDlgExW(NULL);
+    if(res == E_NOTIMPL)
+    {
+        win_skip("PrintDlgExW returns not implemented\n");
+        return;
+    }
     ok( (res == E_INVALIDARG),
         "got 0x%x with %u and %u (expected 'E_INVALIDARG')\n",
         res, GetLastError(), CommDlgExtendedError());
@@ -318,6 +323,8 @@ static void test_abort_proc(void)
         ok(DeleteFileA(filename), "Failed to delete temporary file\n");
         return;
     }
+    GlobalFree(pd.hDevMode);
+    GlobalFree(pd.hDevNames);
 
     ok(pd.hDC != NULL, "PrintDlg didn't return a DC.\n");
     if (!(print_dc = pd.hDC))
@@ -346,25 +353,19 @@ static void test_abort_proc(void)
         goto end;
     }
 
-    ok(abort_proc_called, "AbortProc didn't get called by StartDoc.\n");
-    abort_proc_called = FALSE;
+    /* StartDoc may or may not call abort proc */
 
+    abort_proc_called = FALSE;
     ok(StartPage(print_dc) > 0, "StartPage failed\n");
     ok(!abort_proc_called, "AbortProc got called unexpectedly by StartPage.\n");
     abort_proc_called = FALSE;
 
+    /* following functions sometimes call abort proc too */
     ok(FillRect(print_dc, &rect, (HBRUSH)(COLOR_BACKGROUND + 1)), "FillRect failed\n");
-    ok(!abort_proc_called, "AbortProc got called unexpectedly by StretchBlt.\n");
-    abort_proc_called = FALSE;
-
     ok(EndPage(print_dc) > 0, "EndPage failed\n");
-    ok(!abort_proc_called, "AbortProc got called unexpectedly by EndPage.\n");
-    abort_proc_called = FALSE;
-
     ok(EndDoc(print_dc) > 0, "EndDoc failed\n");
-    ok(!abort_proc_called, "AbortProc got called unexpectedly by EndDoc.\n");
-    abort_proc_called = FALSE;
 
+    abort_proc_called = FALSE;
     ok(DeleteDC(print_dc), "DeleteDC failed\n");
     ok(!abort_proc_called, "AbortProc got called unexpectedly by DeleteDC.\n");
     abort_proc_called = FALSE;
index 51415fd..65e7972 100644 (file)
@@ -32,3 +32,28 @@ FONT 8, "MS Shell Dlg"
     LTEXT           "",-1,28,16,204,31
     EDITTEXT        56,65,2,200,12,ES_AUTOHSCROLL
 }
+
+/* Used by the resize file dialog tests.
+ * Keep this template small or get failures
+ * resizing on small desk tops.
+ * This will work with 640x480 pixels
+ */
+TEMPLATE_SZ DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 300, 40
+STYLE WS_CHILD | WS_CLIPSIBLINGS
+FONT 8, "MS Shell Dlg"
+{
+    LTEXT           "Path:",-1,28,4,36,8
+    LTEXT           "Text1",-1,4,16,20,40
+    LTEXT           "Text2",-1,232,20,65,8
+    LTEXT           "",-1,28,16,204,31
+    EDITTEXT        56,65,2,200,12,ES_AUTOHSCROLL
+}
+
+/* note: the test program will modify coordinates and nr of controls in this template */
+TEMPLATE_STC32 DIALOG LOADONCALL MOVEABLE DISCARDABLE 11111, 0, 316, 76
+STYLE WS_CHILD | WS_CLIPSIBLINGS
+FONT 8, "MS Shell Dlg"
+{
+        LTEXT   "",  1119, 22222, 0, 204, 76
+        PUSHBUTTON "TEST", -1, 12345, 0, 20, 20
+}
index a626b82..f9ccaed 100644 (file)
@@ -58,6 +58,8 @@ static VOID (WINAPI *pCertFreeCertificateChain)(PCCERT_CHAIN_CONTEXT);
 static VOID (WINAPI *pCertFreeCertificateChainEngine)(HCERTCHAINENGINE);
 static BOOL (WINAPI *pCertVerifyCertificateChainPolicy)(LPCSTR,PCCERT_CHAIN_CONTEXT,PCERT_CHAIN_POLICY_PARA,PCERT_CHAIN_POLICY_STATUS);
 
+#define IS_INTOID(x)    (((ULONG_PTR)(x) >> 16) == 0)
+
 
 static void testCreateCertChainEngine(void)
 {
@@ -3883,19 +3885,19 @@ static void checkChainPolicyStatus(LPCSTR policy, const ChainPolicyCheck *check,
         if (check->todo & TODO_POLICY)
             todo_wine ok(ret,
              "%s[%d]: CertVerifyCertificateChainPolicy failed: %08x\n",
-             HIWORD(policy) ? policy : num_to_str(LOWORD(policy)),
+             IS_INTOID(policy) ? num_to_str(LOWORD(policy)) : policy,
              testIndex, GetLastError());
         else
         {
             if (!ret && GetLastError() == ERROR_FILE_NOT_FOUND)
             {
                 skip("%d: missing policy %s, skipping test\n", testIndex,
-                 HIWORD(policy) ? policy : num_to_str(LOWORD(policy)));
+                 IS_INTOID(policy) ? num_to_str(LOWORD(policy)) : policy);
                 pCertFreeCertificateChain(chain);
                 return;
             }
             ok(ret, "%s[%d]: CertVerifyCertificateChainPolicy failed: %08x\n",
-             HIWORD(policy) ? policy : num_to_str(LOWORD(policy)), testIndex,
+             IS_INTOID(policy) ? num_to_str(LOWORD(policy)) : policy, testIndex,
              GetLastError());
         }
         if (ret)
@@ -3906,7 +3908,7 @@ static void checkChainPolicyStatus(LPCSTR policy, const ChainPolicyCheck *check,
                  (check->brokenStatus && broken(policyStatus.dwError ==
                  check->brokenStatus->dwError)),
                  "%s[%d]: expected %08x, got %08x\n",
-                 HIWORD(policy) ? policy : num_to_str(LOWORD(policy)),
+                 IS_INTOID(policy) ? num_to_str(LOWORD(policy)) : policy,
                  testIndex, check->status.dwError, policyStatus.dwError);
             else
                 ok(policyStatus.dwError == check->status.dwError ||
@@ -3914,12 +3916,12 @@ static void checkChainPolicyStatus(LPCSTR policy, const ChainPolicyCheck *check,
                  (check->brokenStatus && broken(policyStatus.dwError ==
                  check->brokenStatus->dwError)),
                  "%s[%d]: expected %08x, got %08x\n",
-                 HIWORD(policy) ? policy : num_to_str(LOWORD(policy)),
+                 IS_INTOID(policy) ? num_to_str(LOWORD(policy)) : policy,
                  testIndex, check->status.dwError, policyStatus.dwError);
             if (policyStatus.dwError != check->status.dwError)
             {
                 skip("%s[%d]: error %08x doesn't match expected %08x, not checking indexes\n",
-                 HIWORD(policy) ? policy : num_to_str(LOWORD(policy)),
+                 IS_INTOID(policy) ? num_to_str(LOWORD(policy)) : policy,
                  testIndex, policyStatus.dwError, check->status.dwError);
                 pCertFreeCertificateChain(chain);
                 return;
@@ -3930,7 +3932,7 @@ static void checkChainPolicyStatus(LPCSTR policy, const ChainPolicyCheck *check,
                  (check->brokenStatus && broken(policyStatus.lChainIndex ==
                  check->brokenStatus->lChainIndex)),
                  "%s[%d]: expected %d, got %d\n",
-                 HIWORD(policy) ? policy : num_to_str(LOWORD(policy)),
+                 IS_INTOID(policy) ? num_to_str(LOWORD(policy)) : policy,
                  testIndex, check->status.lChainIndex,
                  policyStatus.lChainIndex);
             else
@@ -3938,7 +3940,7 @@ static void checkChainPolicyStatus(LPCSTR policy, const ChainPolicyCheck *check,
                  (check->brokenStatus && broken(policyStatus.lChainIndex ==
                  check->brokenStatus->lChainIndex)),
                  "%s[%d]: expected %d, got %d\n",
-                 HIWORD(policy) ? policy : num_to_str(LOWORD(policy)),
+                 IS_INTOID(policy) ? num_to_str(LOWORD(policy)) : policy,
                  testIndex,
                  check->status.lChainIndex, policyStatus.lChainIndex);
             if (check->todo & TODO_ELEMENTS)
@@ -3947,7 +3949,7 @@ static void checkChainPolicyStatus(LPCSTR policy, const ChainPolicyCheck *check,
                  (check->brokenStatus && broken(policyStatus.lElementIndex ==
                  check->brokenStatus->lElementIndex)),
                  "%s[%d]: expected %d, got %d\n",
-                 HIWORD(policy) ? policy : num_to_str(LOWORD(policy)),
+                 IS_INTOID(policy) ? num_to_str(LOWORD(policy)) : policy,
                  testIndex,
                  check->status.lElementIndex, policyStatus.lElementIndex);
             else
@@ -3955,7 +3957,7 @@ static void checkChainPolicyStatus(LPCSTR policy, const ChainPolicyCheck *check,
                  (check->brokenStatus && broken(policyStatus.lElementIndex ==
                  check->brokenStatus->lElementIndex)),
                  "%s[%d]: expected %d, got %d\n",
-                 HIWORD(policy) ? policy : num_to_str(LOWORD(policy)),
+                 IS_INTOID(policy) ? num_to_str(LOWORD(policy)) : policy,
                  testIndex,
                  check->status.lElementIndex, policyStatus.lElementIndex);
         }
index 9b622bb..7c11e8e 100644 (file)
@@ -254,10 +254,8 @@ static void test_cryptTls(void)
         ret = pI_CryptFreeTls(index, 0);
         ok(ret, "I_CryptFreeTls failed: %08x\n", GetLastError());
         ret = pI_CryptFreeTls(index, 0);
-        /* Not sure if this fails because TlsFree should fail, so leave as
-         * todo for now.
-         */
-        todo_wine ok(!ret && GetLastError() == E_INVALIDARG,
+        ok(!ret, "I_CryptFreeTls succeeded\n");
+        ok(GetLastError() == E_INVALIDARG,
          "Expected E_INVALIDARG, got %08x\n", GetLastError());
     }
     /* Similar pass, check I_CryptDetachTls */
index 8ab5625..39662eb 100644 (file)
@@ -2572,8 +2572,8 @@ static void test_decode_msg_get_param(void)
      sizeof(signedKeyIdEmptyContent), TRUE);
     if (!ret && GetLastError() == OSS_DATA_ERROR)
     {
-        /* Subsequent tests crashes on some Win9x, so bail out */
         CryptMsgClose(msg);
+        win_skip("Subsequent tests crash on some Win9x\n");
         return;
     }
     ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
index 0ee4dd4..0effcf4 100644 (file)
@@ -646,6 +646,61 @@ static void test_linelinearblend(void)
     expect(Ok, status);
 }
 
+static void test_gradientsurroundcolorcount(void)
+{
+    GpStatus status;
+    GpPathGradient *grad;
+    ARGB *color;
+    INT count = 3;
+
+    status = GdipCreatePathGradient(blendcount_ptf, 2, WrapModeClamp, &grad);
+    expect(Ok, status);
+
+    color = GdipAlloc(sizeof(ARGB[3]));
+
+    status = GdipSetPathGradientSurroundColorsWithCount(grad, color, &count);
+    expect(InvalidParameter, status);
+    GdipFree(color);
+
+    count = 2;
+
+    color = GdipAlloc(sizeof(ARGB[2]));
+
+    color[0] = 0x00ff0000;
+    color[1] = 0x0000ff00;
+
+    status = GdipSetPathGradientSurroundColorsWithCount(NULL, color, &count);
+    expect(InvalidParameter, status);
+
+    status = GdipSetPathGradientSurroundColorsWithCount(grad, NULL, &count);
+    expect(InvalidParameter, status);
+
+    /* WinXP crashes on this test */
+    if(0)
+    {
+        status = GdipSetPathGradientSurroundColorsWithCount(grad, color, NULL);
+        expect(InvalidParameter, status);
+    }
+
+    status = GdipSetPathGradientSurroundColorsWithCount(grad, color, &count);
+    todo_wine expect(Ok, status);
+    expect(2, count);
+
+    status = GdipGetPathGradientSurroundColorCount(NULL, &count);
+    expect(InvalidParameter, status);
+
+    status = GdipGetPathGradientSurroundColorCount(grad, NULL);
+    expect(InvalidParameter, status);
+
+    count = 0;
+    status = GdipGetPathGradientSurroundColorCount(grad, &count);
+    todo_wine expect(Ok, status);
+    todo_wine expect(2, count);
+
+    GdipFree(color);
+    GdipDeleteBrush((GpBrush*)grad);
+}
+
 START_TEST(brush)
 {
     struct GdiplusStartupInput gdiplusStartupInput;
@@ -669,6 +724,7 @@ START_TEST(brush)
     test_gradientgetrect();
     test_lineblend();
     test_linelinearblend();
+    test_gradientsurroundcolorcount();
 
     GdiplusShutdown(gdiplusToken);
 }
index 7b95d4c..80f11bc 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include <math.h>
+
 #include "windows.h"
 #include "gdiplus.h"
 #include "wine/test.h"
 
 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
+#define expectf(expected, got) ok(fabs(expected - got) < 0.0001, "Expected %.2f, got %.2f\n", expected, got)
 
 static const WCHAR arial[] = {'A','r','i','a','l','\0'};
 static const WCHAR nonexistent[] = {'T','h','i','s','F','o','n','t','s','h','o','u','l','d','N','o','t','E','x','i','s','t','\0'};
@@ -189,12 +192,9 @@ static void test_fontfamily (void)
     expect (FontFamilyNotFound, stat);
 
     /* Bitmap fonts are not found */
-todo_wine
-{
     stat = GdipCreateFontFamilyFromName (MSSansSerif, NULL, &family);
     expect (FontFamilyNotFound, stat);
     if(stat == Ok) GdipDeleteFontFamily(family);
-}
 
     stat = GdipCreateFontFamilyFromName (arial, NULL, &family);
     if(stat == FontFamilyNotFound)
@@ -345,6 +345,78 @@ static void test_installedfonts (void)
     ok (collection != NULL, "got NULL font collection\n");
 }
 
+static void test_heightgivendpi(void)
+{
+    GpStatus stat;
+    GpFont* font = NULL;
+    GpFontFamily* fontfamily = NULL;
+    REAL height;
+
+    stat = GdipCreateFontFamilyFromName(arial, NULL, &fontfamily);
+    if(stat == FontFamilyNotFound)
+    {
+        skip("Arial not installed\n");
+        return;
+    }
+    expect(Ok, stat);
+
+    stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitPixel, &font);
+    expect(Ok, stat);
+
+    stat = GdipGetFontHeightGivenDPI(NULL, 96, &height);
+    expect(InvalidParameter, stat);
+
+    stat = GdipGetFontHeightGivenDPI(font, 96, NULL);
+    expect(InvalidParameter, stat);
+
+    stat = GdipGetFontHeightGivenDPI(font, 96, &height);
+    expect(Ok, stat);
+    expectf((REAL)34.497070, height);
+    GdipDeleteFont(font);
+
+    height = 12345;
+    stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitWorld, &font);
+    expect(Ok, stat);
+    stat = GdipGetFontHeightGivenDPI(font, 96, &height);
+    expect(Ok, stat);
+    expectf((REAL)34.497070, height);
+    GdipDeleteFont(font);
+
+    height = 12345;
+    stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitPoint, &font);
+    expect(Ok, stat);
+    stat = GdipGetFontHeightGivenDPI(font, 96, &height);
+    expect(Ok, stat);
+    expectf((REAL)45.996094, height);
+    GdipDeleteFont(font);
+
+    height = 12345;
+    stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitInch, &font);
+    expect(Ok, stat);
+    stat = GdipGetFontHeightGivenDPI(font, 96, &height);
+    expect(Ok, stat);
+    expectf((REAL)3311.718750, height);
+    GdipDeleteFont(font);
+
+    height = 12345;
+    stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitDocument, &font);
+    expect(Ok, stat);
+    stat = GdipGetFontHeightGivenDPI(font, 96, &height);
+    expect(Ok, stat);
+    expectf((REAL)11.039062, height);
+    GdipDeleteFont(font);
+
+    height = 12345;
+    stat = GdipCreateFont(fontfamily, 30, FontStyleRegular, UnitMillimeter, &font);
+    expect(Ok, stat);
+    stat = GdipGetFontHeightGivenDPI(font, 96, &height);
+    expect(Ok, stat);
+    expectf((REAL)130.382614, height);
+    GdipDeleteFont(font);
+
+    GdipDeleteFontFamily(fontfamily);
+}
+
 START_TEST(font)
 {
     struct GdiplusStartupInput gdiplusStartupInput;
@@ -363,6 +435,7 @@ START_TEST(font)
     test_fontfamily_properties();
     test_getgenerics();
     test_installedfonts();
+    test_heightgivendpi();
 
     GdiplusShutdown(gdiplusToken);
 }
index b2dc9b2..57ce638 100644 (file)
 #include <math.h>
 
 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
-#define expectf(expected, got) ok(fabs(expected - got) < 0.0001, "Expected %.2f, got %.2f\n", expected, got)
+#define expectf_(expected, got, precision) ok(fabs(expected - got) < precision, "Expected %.2f, got %.2f\n", expected, got)
+#define expectf(expected, got) expectf_(expected, got, 0.0001)
 #define TABLE_LEN (23)
 
+static HWND hwnd;
+
 static void test_constructor_destructor(void)
 {
     GpStatus stat;
     GpGraphics *graphics = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
 
     stat = GdipCreateFromHDC(NULL, &graphics);
     expect(OutOfMemory, stat);
@@ -56,7 +59,7 @@ static void test_constructor_destructor(void)
 
     stat = GdipDeleteGraphics(NULL);
     expect(InvalidParameter, stat);
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 typedef struct node{
@@ -115,7 +118,7 @@ static void test_save_restore(void)
     InterpolationMode mode;
     GpGraphics *graphics1, *graphics2;
     node * state_log = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     state_a = state_b = state_c = 0xdeadbeef;
 
     /* Invalid saving. */
@@ -224,7 +227,7 @@ static void test_save_restore(void)
     todo_wine
         check_no_duplicates(state_log);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipDrawArc(void)
@@ -232,7 +235,7 @@ static void test_GdipDrawArc(void)
     GpStatus status;
     GpGraphics *graphics = NULL;
     GpPen *pen = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
 
     /* make a graphics object and pen object */
     ok(hdc != NULL, "Expected HDC to be initialized\n");
@@ -268,7 +271,7 @@ static void test_GdipDrawArc(void)
     GdipDeletePen(pen);
     GdipDeleteGraphics(graphics);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipDrawArcI(void)
@@ -276,7 +279,7 @@ static void test_GdipDrawArcI(void)
     GpStatus status;
     GpGraphics *graphics = NULL;
     GpPen *pen = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
 
     /* make a graphics object and pen object */
     ok(hdc != NULL, "Expected HDC to be initialized\n");
@@ -312,7 +315,7 @@ static void test_GdipDrawArcI(void)
     GdipDeletePen(pen);
     GdipDeleteGraphics(graphics);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_BeginContainer2(void)
@@ -334,7 +337,7 @@ static void test_BeginContainer2(void)
 
     GpStatus status;
     GpGraphics *graphics = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
 
     ok(hdc != NULL, "Expected HDC to be initialized\n");
 
@@ -497,7 +500,7 @@ static void test_BeginContainer2(void)
     expect(Ok, status);
 
     GdipDeleteGraphics(graphics);
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipDrawBezierI(void)
@@ -505,7 +508,7 @@ static void test_GdipDrawBezierI(void)
     GpStatus status;
     GpGraphics *graphics = NULL;
     GpPen *pen = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
 
     /* make a graphics object and pen object */
     ok(hdc != NULL, "Expected HDC to be initialized\n");
@@ -535,7 +538,7 @@ static void test_GdipDrawBezierI(void)
     GdipDeletePen(pen);
     GdipDeleteGraphics(graphics);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipDrawCurve3(void)
@@ -543,7 +546,7 @@ static void test_GdipDrawCurve3(void)
     GpStatus status;
     GpGraphics *graphics = NULL;
     GpPen *pen = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     GpPointF points[3];
 
     points[0].X = 0;
@@ -615,7 +618,7 @@ static void test_GdipDrawCurve3(void)
     GdipDeletePen(pen);
     GdipDeleteGraphics(graphics);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipDrawCurve3I(void)
@@ -623,7 +626,7 @@ static void test_GdipDrawCurve3I(void)
     GpStatus status;
     GpGraphics *graphics = NULL;
     GpPen *pen = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     GpPoint points[3];
 
     points[0].X = 0;
@@ -695,7 +698,7 @@ static void test_GdipDrawCurve3I(void)
     GdipDeletePen(pen);
     GdipDeleteGraphics(graphics);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipDrawCurve2(void)
@@ -703,7 +706,7 @@ static void test_GdipDrawCurve2(void)
     GpStatus status;
     GpGraphics *graphics = NULL;
     GpPen *pen = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     GpPointF points[3];
 
     points[0].X = 0;
@@ -762,7 +765,7 @@ static void test_GdipDrawCurve2(void)
     GdipDeletePen(pen);
     GdipDeleteGraphics(graphics);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipDrawCurve2I(void)
@@ -770,7 +773,7 @@ static void test_GdipDrawCurve2I(void)
     GpStatus status;
     GpGraphics *graphics = NULL;
     GpPen *pen = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     GpPoint points[3];
 
     points[0].X = 0;
@@ -829,7 +832,7 @@ static void test_GdipDrawCurve2I(void)
     GdipDeletePen(pen);
     GdipDeleteGraphics(graphics);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipDrawCurve(void)
@@ -837,7 +840,7 @@ static void test_GdipDrawCurve(void)
     GpStatus status;
     GpGraphics *graphics = NULL;
     GpPen *pen = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     GpPointF points[3];
 
     points[0].X = 0;
@@ -890,7 +893,7 @@ static void test_GdipDrawCurve(void)
     GdipDeletePen(pen);
     GdipDeleteGraphics(graphics);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipDrawCurveI(void)
@@ -898,7 +901,7 @@ static void test_GdipDrawCurveI(void)
     GpStatus status;
     GpGraphics *graphics = NULL;
     GpPen *pen = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     GpPoint points[3];
 
     points[0].X = 0;
@@ -951,7 +954,7 @@ static void test_GdipDrawCurveI(void)
     GdipDeletePen(pen);
     GdipDeleteGraphics(graphics);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipDrawLineI(void)
@@ -959,7 +962,7 @@ static void test_GdipDrawLineI(void)
     GpStatus status;
     GpGraphics *graphics = NULL;
     GpPen *pen = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
 
     /* make a graphics object and pen object */
     ok(hdc != NULL, "Expected HDC to be initialized\n");
@@ -989,7 +992,7 @@ static void test_GdipDrawLineI(void)
     GdipDeletePen(pen);
     GdipDeleteGraphics(graphics);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipDrawLinesI(void)
@@ -998,7 +1001,7 @@ static void test_GdipDrawLinesI(void)
     GpGraphics *graphics = NULL;
     GpPen *pen = NULL;
     GpPoint *ptf = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
 
     /* make a graphics object and pen object */
     ok(hdc != NULL, "Expected HDC to be initialized\n");
@@ -1041,7 +1044,7 @@ static void test_GdipDrawLinesI(void)
     GdipDeletePen(pen);
     GdipDeleteGraphics(graphics);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_Get_Release_DC(void)
@@ -1051,7 +1054,7 @@ static void test_Get_Release_DC(void)
     GpPen *pen;
     GpSolidFill *brush;
     GpPath *path;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     HDC retdc;
     REAL r;
     CompositingQuality quality;
@@ -1345,14 +1348,14 @@ static void test_Get_Release_DC(void)
     GdipDeleteMatrix(m);
     DeleteObject(hrgn);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_transformpoints(void)
 {
     GpStatus status;
     GpGraphics *graphics = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     GpPointF ptf[2];
     GpPoint pt[2];
 
@@ -1465,14 +1468,14 @@ static void test_transformpoints(void)
     expect(18, pt[1].Y);
 
     GdipDeleteGraphics(graphics);
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_get_set_clip(void)
 {
     GpStatus status;
     GpGraphics *graphics = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     GpRegion *clip;
     GpRectF rect;
     BOOL res;
@@ -1544,14 +1547,14 @@ static void test_get_set_clip(void)
     GdipDeleteRegion(clip);
 
     GdipDeleteGraphics(graphics);
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_isempty(void)
 {
     GpStatus status;
     GpGraphics *graphics = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     GpRegion *clip;
     BOOL res;
 
@@ -1578,7 +1581,7 @@ static void test_isempty(void)
     GdipDeleteRegion(clip);
 
     GdipDeleteGraphics(graphics);
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_clear(void)
@@ -1592,7 +1595,7 @@ static void test_clear(void)
 static void test_textcontrast(void)
 {
     GpStatus status;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     GpGraphics *graphics;
     UINT contrast;
 
@@ -1608,7 +1611,7 @@ static void test_textcontrast(void)
     expect(4, contrast);
 
     GdipDeleteGraphics(graphics);
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipDrawString(void)
@@ -1620,7 +1623,7 @@ static void test_GdipDrawString(void)
     GpStringFormat *format;
     GpBrush *brush;
     LOGFONTA logfont;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     static const WCHAR string[] = {'T','e','s','t',0};
 
     memset(&logfont,0,sizeof(logfont));
@@ -1658,7 +1661,7 @@ static void test_GdipDrawString(void)
     GdipDeleteFont(fnt);
     GdipDeleteStringFormat(format);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipGetVisibleClipBounds_screen(void)
@@ -1758,36 +1761,10 @@ static void test_GdipGetVisibleClipBounds_window(void)
     GpGraphics *graphics = NULL;
     GpRectF rectf, window, exp, clipr;
     GpRect recti;
-    HWND hwnd;
-    WNDCLASSA class;
     HDC hdc;
     PAINTSTRUCT ps;
-    HINSTANCE hInstance = GetModuleHandle(NULL);
     RECT wnd_rect;
 
-    window.X = 0;
-    window.Y = 0;
-    window.Width = 200;
-    window.Height = 300;
-
-    class.lpszClassName = "ClipBoundsTestClass";
-    class.style = CS_HREDRAW | CS_VREDRAW;
-    class.lpfnWndProc = DefWindowProcA;
-    class.hInstance = hInstance;
-    class.hIcon = LoadIcon(0, IDI_APPLICATION);
-    class.hCursor = LoadCursor(NULL, IDC_ARROW);
-    class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
-    class.lpszMenuName = 0;
-    class.cbClsExtra = 0;
-    class.cbWndExtra = 0;
-    RegisterClass(&class);
-
-    hwnd = CreateWindow(class.lpszClassName, "ClipboundsTest",
-        WS_OVERLAPPEDWINDOW, window.X, window.Y, window.Width, window.Height,
-        NULL, NULL, hInstance, NULL);
-
-    ok(hwnd != NULL, "Expected window to be created\n");
-
     /* get client area size */
     ok(GetClientRect(hwnd, &wnd_rect), "GetClientRect should have succeeded\n");
     window.X = wnd_rect.left;
@@ -1870,7 +1847,6 @@ static void test_GdipGetVisibleClipBounds_window(void)
 
     GdipDeleteGraphics(graphics);
     EndPaint(hwnd, &ps);
-    DestroyWindow(hwnd);
 }
 
 static void test_GdipGetVisibleClipBounds(void)
@@ -1878,7 +1854,7 @@ static void test_GdipGetVisibleClipBounds(void)
     GpGraphics* graphics = NULL;
     GpRectF rectf;
     GpRect rect;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     GpStatus status;
 
     status = GdipCreateFromHDC(hdc, &graphics);
@@ -1899,7 +1875,7 @@ static void test_GdipGetVisibleClipBounds(void)
     expect(InvalidParameter, status);
 
     GdipDeleteGraphics(graphics);
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 
     test_GdipGetVisibleClipBounds_screen();
     test_GdipGetVisibleClipBounds_window();
@@ -1933,7 +1909,7 @@ static void test_GdipIsVisiblePoint(void)
 {
     GpStatus status;
     GpGraphics *graphics = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     REAL x, y;
     BOOL val;
 
@@ -2105,14 +2081,14 @@ static void test_GdipIsVisiblePoint(void)
     ok(val == FALSE, "After clipping, expected (%.2f, %.2f) not to be visible\n", x, y);
 
     GdipDeleteGraphics(graphics);
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipIsVisibleRect(void)
 {
     GpStatus status;
     GpGraphics *graphics = NULL;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
     REAL x, y, width, height;
     BOOL val;
 
@@ -2267,7 +2243,7 @@ static void test_GdipIsVisibleRect(void)
     ok(val == TRUE, "Expected (%.2f, %.2f, %.2f, %.2f) to be visible\n", x, y, width, height);
 
     GdipDeleteGraphics(graphics);
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
 }
 
 static void test_GdipGetNearestColor(void)
@@ -2276,7 +2252,7 @@ static void test_GdipGetNearestColor(void)
     GpGraphics *graphics;
     GpBitmap *bitmap;
     ARGB color = 0xdeadbeef;
-    HDC hdc = GetDC(0);
+    HDC hdc = GetDC( hwnd );
 
     /* create a graphics object */
     ok(hdc != NULL, "Expected HDC to be initialized\n");
@@ -2415,17 +2391,269 @@ static void test_GdipGetNearestColor(void)
     expect(Ok, status);
     status = GdipGetNearestColor(graphics, &color);
     expect(Ok, status);
-    todo_wine expect(0xffa8b8e8, color);
+    todo_wine
+    ok(color == 0xffa8b8e8 ||
+       broken(color == 0xffa0b8e0), /* Win98/WinMe */
+       "Expected ffa8b8e8, got %.8x\n", color);
     GdipDeleteGraphics(graphics);
     GdipDisposeImage((GpImage*)bitmap);
 
-    ReleaseDC(0, hdc);
+    ReleaseDC(hwnd, hdc);
+}
+
+static void test_string_functions(void)
+{
+    GpStatus status;
+    GpGraphics *graphics;
+    GpFontFamily *family;
+    GpFont *font;
+    RectF rc, char_bounds, bounds;
+    GpBrush *brush;
+    ARGB color = 0xff000000;
+    HDC hdc = GetDC( hwnd );
+    const WCHAR fontname[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
+    const WCHAR fontname2[] = {'C','o','u','r','i','e','r',0};
+    const WCHAR teststring[] = {'o','o',' ','o','\n','o',0};
+    REAL char_width, char_height;
+    INT codepointsfitted, linesfilled;
+    GpStringFormat *format;
+    CharacterRange ranges[3] = {{0, 1}, {1, 3}, {5, 1}};
+    GpRegion *regions[4] = {0};
+    BOOL region_isempty[4];
+    int i;
+
+    ok(hdc != NULL, "Expected HDC to be initialized\n");
+    status = GdipCreateFromHDC(hdc, &graphics);
+    expect(Ok, status);
+    ok(graphics != NULL, "Expected graphics to be initialized\n");
+
+    status = GdipCreateFontFamilyFromName(fontname, NULL, &family);
+
+    if (status != Ok)
+    {
+        /* Wine doesn't have Courier New? */
+        todo_wine expect(Ok, status);
+        status = GdipCreateFontFamilyFromName(fontname2, NULL, &family);
+    }
+
+    expect(Ok, status);
+
+    status = GdipCreateFont(family, 10.0, FontStyleRegular, UnitPixel, &font);
+    expect(Ok, status);
+
+    status = GdipCreateSolidFill(color, (GpSolidFill**)&brush);
+    expect(Ok, status);
+
+    status = GdipCreateStringFormat(0, LANG_NEUTRAL, &format);
+    expect(Ok, status);
+
+    rc.X = 0;
+    rc.Y = 0;
+    rc.Width = 100.0;
+    rc.Height = 100.0;
+
+    status = GdipDrawString(NULL, teststring, 6, font, &rc, NULL, brush);
+    expect(InvalidParameter, status);
+
+    status = GdipDrawString(graphics, NULL, 6, font, &rc, NULL, brush);
+    expect(InvalidParameter, status);
+
+    status = GdipDrawString(graphics, teststring, 6, NULL, &rc, NULL, brush);
+    expect(InvalidParameter, status);
+
+    status = GdipDrawString(graphics, teststring, 6, font, NULL, NULL, brush);
+    expect(InvalidParameter, status);
+
+    status = GdipDrawString(graphics, teststring, 6, font, &rc, NULL, NULL);
+    expect(InvalidParameter, status);
+
+    status = GdipDrawString(graphics, teststring, 6, font, &rc, NULL, brush);
+    expect(Ok, status);
+
+    status = GdipMeasureString(NULL, teststring, 6, font, &rc, NULL, &bounds, &codepointsfitted, &linesfilled);
+    expect(InvalidParameter, status);
+
+    status = GdipMeasureString(graphics, NULL, 6, font, &rc, NULL, &bounds, &codepointsfitted, &linesfilled);
+    expect(InvalidParameter, status);
+
+    status = GdipMeasureString(graphics, teststring, 6, NULL, &rc, NULL, &bounds, &codepointsfitted, &linesfilled);
+    expect(InvalidParameter, status);
+
+    status = GdipMeasureString(graphics, teststring, 6, font, NULL, NULL, &bounds, &codepointsfitted, &linesfilled);
+    expect(InvalidParameter, status);
+
+    status = GdipMeasureString(graphics, teststring, 6, font, &rc, NULL, NULL, &codepointsfitted, &linesfilled);
+    expect(InvalidParameter, status);
+
+    status = GdipMeasureString(graphics, teststring, 6, font, &rc, NULL, &bounds, NULL, &linesfilled);
+    expect(Ok, status);
+
+    status = GdipMeasureString(graphics, teststring, 6, font, &rc, NULL, &bounds, &codepointsfitted, NULL);
+    expect(Ok, status);
+
+    status = GdipMeasureString(graphics, teststring, 1, font, &rc, NULL, &char_bounds, &codepointsfitted, &linesfilled);
+    expect(Ok, status);
+    expectf(0.0, char_bounds.X);
+    expectf(0.0, char_bounds.Y);
+    ok(char_bounds.Width > 0, "got %0.2f\n", bounds.Width);
+    ok(char_bounds.Height > 0, "got %0.2f\n", bounds.Height);
+    expect(1, codepointsfitted);
+    expect(1, linesfilled);
+
+    status = GdipMeasureString(graphics, teststring, 2, font, &rc, NULL, &bounds, &codepointsfitted, &linesfilled);
+    expect(Ok, status);
+    expectf(0.0, bounds.X);
+    expectf(0.0, bounds.Y);
+    ok(bounds.Width > char_bounds.Width, "got %0.2f, expected at least %0.2f\n", bounds.Width, char_bounds.Width);
+    expectf(char_bounds.Height, bounds.Height);
+    expect(2, codepointsfitted);
+    expect(1, linesfilled);
+    char_width = bounds.Width - char_bounds.Width;
+
+    status = GdipMeasureString(graphics, teststring, 6, font, &rc, NULL, &bounds, &codepointsfitted, &linesfilled);
+    expect(Ok, status);
+    expectf(0.0, bounds.X);
+    expectf(0.0, bounds.Y);
+    expectf_(char_bounds.Width + char_width * 3, bounds.Width, 0.01);
+    ok(bounds.Height > char_bounds.Height, "got %0.2f, expected at least %0.2f\n", bounds.Height, char_bounds.Height);
+    expect(6, codepointsfitted);
+    expect(2, linesfilled);
+    char_height = bounds.Height - char_bounds.Height;
+
+    /* Cut off everything after the first space. */
+    rc.Width = char_bounds.Width + char_width * 2.5;
+
+    status = GdipMeasureString(graphics, teststring, 6, font, &rc, NULL, &bounds, &codepointsfitted, &linesfilled);
+    expect(Ok, status);
+    expectf(0.0, bounds.X);
+    expectf(0.0, bounds.Y);
+    expectf_(char_bounds.Width + char_width, bounds.Width, 0.01);
+    expectf_(char_bounds.Height + char_height * 2, bounds.Height, 0.01);
+    expect(6, codepointsfitted);
+    expect(3, linesfilled);
+
+    /* Cut off everything including the first space. */
+    rc.Width = char_bounds.Width + char_width * 1.5;
+
+    status = GdipMeasureString(graphics, teststring, 6, font, &rc, NULL, &bounds, &codepointsfitted, &linesfilled);
+    expect(Ok, status);
+    expectf(0.0, bounds.X);
+    expectf(0.0, bounds.Y);
+    expectf_(char_bounds.Width + char_width, bounds.Width, 0.01);
+    expectf_(char_bounds.Height + char_height * 2, bounds.Height, 0.01);
+    expect(6, codepointsfitted);
+    expect(3, linesfilled);
+
+    /* Cut off everything after the first character. */
+    rc.Width = char_bounds.Width + char_width * 0.5;
+
+    status = GdipMeasureString(graphics, teststring, 6, font, &rc, NULL, &bounds, &codepointsfitted, &linesfilled);
+    expect(Ok, status);
+    expectf(0.0, bounds.X);
+    expectf(0.0, bounds.Y);
+    expectf_(char_bounds.Width, bounds.Width, 0.01);
+    todo_wine expectf_(char_bounds.Height + char_height * 3, bounds.Height, 0.05);
+    expect(6, codepointsfitted);
+    todo_wine expect(4, linesfilled);
+
+    status = GdipSetStringFormatMeasurableCharacterRanges(format, 3, ranges);
+    expect(Ok, status);
+
+    rc.Width = 100.0;
+
+    for (i=0; i<4; i++)
+    {
+        status = GdipCreateRegion(&regions[i]);
+        expect(Ok, status);
+    }
+
+    status = GdipMeasureCharacterRanges(NULL, teststring, 6, font, &rc, format, 3, regions);
+    expect(InvalidParameter, status);
+
+    status = GdipMeasureCharacterRanges(graphics, NULL, 6, font, &rc, format, 3, regions);
+    expect(InvalidParameter, status);
+
+    status = GdipMeasureCharacterRanges(graphics, teststring, 6, NULL, &rc, format, 3, regions);
+    expect(InvalidParameter, status);
+
+    status = GdipMeasureCharacterRanges(graphics, teststring, 6, font, NULL, format, 3, regions);
+    expect(InvalidParameter, status);
+
+    if (0)
+    {
+        /* Crashes on Windows XP */
+        status = GdipMeasureCharacterRanges(graphics, teststring, 6, font, &rc, NULL, 3, regions);
+        expect(InvalidParameter, status);
+    }
+
+    status = GdipMeasureCharacterRanges(graphics, teststring, 6, font, &rc, format, 3, NULL);
+    expect(InvalidParameter, status);
+
+    status = GdipMeasureCharacterRanges(graphics, teststring, 6, font, &rc, format, 2, regions);
+    expect(InvalidParameter, status);
+
+    status = GdipMeasureCharacterRanges(graphics, teststring, 6, font, &rc, format, 4, regions);
+    expect(Ok, status);
+
+    for (i=0; i<4; i++)
+    {
+        status = GdipIsEmptyRegion(regions[i], graphics, &region_isempty[i]);
+        expect(Ok, status);
+    }
+
+    ok(!region_isempty[0], "region shouldn't be empty\n");
+    ok(!region_isempty[1], "region shouldn't be empty\n");
+    ok(!region_isempty[2], "region shouldn't be empty\n");
+    ok(!region_isempty[3], "region shouldn't be empty\n");
+
+    /* Cut off everything after the first space, and the second line. */
+    rc.Width = char_bounds.Width + char_width * 2.5;
+    rc.Height = char_bounds.Height + char_height * 0.5;
+
+    status = GdipMeasureCharacterRanges(graphics, teststring, 6, font, &rc, format, 3, regions);
+    expect(Ok, status);
+
+    for (i=0; i<4; i++)
+    {
+        status = GdipIsEmptyRegion(regions[i], graphics, &region_isempty[i]);
+        expect(Ok, status);
+    }
+
+    ok(!region_isempty[0], "region shouldn't be empty\n");
+    ok(!region_isempty[1], "region shouldn't be empty\n");
+    ok(region_isempty[2], "region should be empty\n");
+    ok(!region_isempty[3], "region shouldn't be empty\n");
+
+    for (i=0; i<4; i++)
+        GdipDeleteRegion(regions[i]);
+
+    GdipDeleteStringFormat(format);
+    GdipDeleteBrush(brush);
+    GdipDeleteFont(font);
+    GdipDeleteFontFamily(family);
+    GdipDeleteGraphics(graphics);
+
+    ReleaseDC(hwnd, hdc);
 }
 
 START_TEST(graphics)
 {
     struct GdiplusStartupInput gdiplusStartupInput;
     ULONG_PTR gdiplusToken;
+    WNDCLASSA class;
+
+    memset( &class, 0, sizeof(class) );
+    class.lpszClassName = "gdiplus_test";
+    class.style = CS_HREDRAW | CS_VREDRAW;
+    class.lpfnWndProc = DefWindowProcA;
+    class.hInstance = GetModuleHandleA(0);
+    class.hIcon = LoadIcon(0, IDI_APPLICATION);
+    class.hCursor = LoadCursor(NULL, IDC_ARROW);
+    class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+    RegisterClassA( &class );
+    hwnd = CreateWindowA( "gdiplus_test", "graphics test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+                          CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 0, 0, GetModuleHandleA(0), 0 );
+    ok(hwnd != NULL, "Expected window to be created\n");
 
     gdiplusStartupInput.GdiplusVersion              = 1;
     gdiplusStartupInput.DebugEventCallback          = NULL;
@@ -2460,6 +2688,8 @@ START_TEST(graphics)
     test_clear();
     test_textcontrast();
     test_fromMemoryBitmap();
+    test_string_functions();
 
     GdiplusShutdown(gdiplusToken);
+    DestroyWindow( hwnd );
 }
index 9085ef2..74e6ee1 100644 (file)
@@ -226,10 +226,23 @@ static void test_GdipImageGetFrameDimensionsCount(void)
     stat = GdipImageGetFrameDimensionsList((GpImage*)bm, &dimension, 0);
     expect(InvalidParameter, stat);
 
+    stat = GdipImageGetFrameCount(NULL, &dimension, &count);
+    expect(InvalidParameter, stat);
+
+    /* WinXP crashes on this test */
+    if(0)
+    {
+        stat = GdipImageGetFrameCount((GpImage*)bm, &dimension, NULL);
+        expect(InvalidParameter, stat);
+    }
+
+    stat = GdipImageGetFrameCount((GpImage*)bm, NULL, &count);
+    expect(Ok, stat);
+
     count = 12345;
     stat = GdipImageGetFrameCount((GpImage*)bm, &dimension, &count);
-    todo_wine expect(Ok, stat);
-    todo_wine expect(1, count);
+    expect(Ok, stat);
+    expect(1, count);
 
     GdipBitmapSetPixel(bm, 0, 0, 0xffffffff);
 
@@ -793,6 +806,26 @@ static const unsigned char jpgimage[285] = {
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
 };
+/* 1x1 pixel tiff */
+static const unsigned char tiffimage[] = {
+0x49,0x49,0x2a,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0xfe,0x00,
+0x04,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x00,0x01,0x00,
+0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x01,0x00,
+0x00,0x00,0x02,0x01,0x03,0x00,0x03,0x00,0x00,0x00,0xd2,0x00,0x00,0x00,0x03,0x01,
+0x03,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x01,0x03,0x00,0x01,0x00,
+0x00,0x00,0x02,0x00,0x00,0x00,0x0d,0x01,0x02,0x00,0x1b,0x00,0x00,0x00,0xd8,0x00,
+0x00,0x00,0x11,0x01,0x04,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x12,0x01,
+0x03,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x15,0x01,0x03,0x00,0x01,0x00,
+0x00,0x00,0x03,0x00,0x00,0x00,0x16,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x40,0x00,
+0x00,0x00,0x17,0x01,0x04,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x1a,0x01,
+0x05,0x00,0x01,0x00,0x00,0x00,0xf4,0x00,0x00,0x00,0x1b,0x01,0x05,0x00,0x01,0x00,
+0x00,0x00,0xfc,0x00,0x00,0x00,0x1c,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x01,0x00,
+0x00,0x00,0x28,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x6d,0x65,
+0x68,0x2f,0x44,0x65,0x73,0x6b,0x74,0x6f,0x70,0x2f,0x74,0x65,0x73,0x74,0x2e,0x74,
+0x69,0x66,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x48,
+0x00,0x00,0x00,0x01
+};
 /* 320x320 twip wmf */
 static const unsigned char wmfimage[180] = {
 0xd7,0xcd,0xc6,0x9a,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x01,0x40,0x01,0xa0,0x05,
@@ -814,6 +847,7 @@ static void test_getrawformat(void)
     test_bufferrawformat((void*)gifimage, sizeof(gifimage), &ImageFormatGIF,  __LINE__, FALSE);
     test_bufferrawformat((void*)bmpimage, sizeof(bmpimage), &ImageFormatBMP,  __LINE__, FALSE);
     test_bufferrawformat((void*)jpgimage, sizeof(jpgimage), &ImageFormatJPEG, __LINE__, FALSE);
+    test_bufferrawformat((void*)tiffimage, sizeof(tiffimage), &ImageFormatTIFF, __LINE__, FALSE);
     test_bufferrawformat((void*)wmfimage, sizeof(wmfimage), &ImageFormatWMF, __LINE__, FALSE);
 }
 
@@ -828,6 +862,7 @@ static void test_loadwmf(void)
     GpRectF bounds;
     GpUnit unit;
     REAL res = 12345.0;
+    MetafileHeader header;
 
     hglob = GlobalAlloc (0, sizeof(wmfimage));
     data = GlobalLock (hglob);
@@ -863,6 +898,27 @@ static void test_loadwmf(void)
     expect(Ok, stat);
     todo_wine expectf(1440.0, res);
 
+    memset(&header, 0, sizeof(header));
+    stat = GdipGetMetafileHeaderFromMetafile((GpMetafile*)img, &header);
+    expect(Ok, stat);
+    if (stat == Ok)
+    {
+        todo_wine expect(MetafileTypeWmfPlaceable, header.Type);
+        todo_wine expect(sizeof(wmfimage)-sizeof(WmfPlaceableFileHeader), header.Size);
+        todo_wine expect(0x300, header.Version);
+        expect(0, header.EmfPlusFlags);
+        todo_wine expectf(1440.0, header.DpiX);
+        todo_wine expectf(1440.0, header.DpiY);
+        expect(0, header.X);
+        expect(0, header.Y);
+        todo_wine expect(320, header.Width);
+        todo_wine expect(320, header.Height);
+        todo_wine expect(1, U(header).WmfHeader.mtType);
+        expect(0, header.EmfPlusHeaderSize);
+        expect(0, header.LogicalDpiX);
+        expect(0, header.LogicalDpiY);
+    }
+
     GdipDisposeImage(img);
 }
 
@@ -874,6 +930,7 @@ static void test_createfromwmf(void)
     GpRectF bounds;
     GpUnit unit;
     REAL res = 12345.0;
+    MetafileHeader header;
 
     hwmf = SetMetaFileBitsEx(sizeof(wmfimage)-sizeof(WmfPlaceableFileHeader),
         wmfimage+sizeof(WmfPlaceableFileHeader));
@@ -885,11 +942,11 @@ static void test_createfromwmf(void)
 
     stat = GdipGetImageBounds(img, &bounds, &unit);
     expect(Ok, stat);
-    todo_wine expect(UnitPixel, unit);
+    expect(UnitPixel, unit);
     expectf(0.0, bounds.X);
     expectf(0.0, bounds.Y);
-    todo_wine expectf(320.0, bounds.Width);
-    todo_wine expectf(320.0, bounds.Height);
+    expectf(320.0, bounds.Width);
+    expectf(320.0, bounds.Height);
 
     stat = GdipGetImageHorizontalResolution(img, &res);
     expect(Ok, stat);
@@ -899,6 +956,27 @@ static void test_createfromwmf(void)
     expect(Ok, stat);
     expectf(1440.0, res);
 
+    memset(&header, 0, sizeof(header));
+    stat = GdipGetMetafileHeaderFromMetafile((GpMetafile*)img, &header);
+    expect(Ok, stat);
+    if (stat == Ok)
+    {
+        todo_wine expect(MetafileTypeWmfPlaceable, header.Type);
+        todo_wine expect(sizeof(wmfimage)-sizeof(WmfPlaceableFileHeader), header.Size);
+        todo_wine expect(0x300, header.Version);
+        expect(0, header.EmfPlusFlags);
+        todo_wine expectf(1440.0, header.DpiX);
+        todo_wine expectf(1440.0, header.DpiY);
+        expect(0, header.X);
+        expect(0, header.Y);
+        todo_wine expect(320, header.Width);
+        todo_wine expect(320, header.Height);
+        todo_wine expect(1, U(header).WmfHeader.mtType);
+        expect(0, header.EmfPlusHeaderSize);
+        expect(0, header.LogicalDpiX);
+        expect(0, header.LogicalDpiY);
+    }
+
     GdipDisposeImage(img);
 }
 
@@ -1544,7 +1622,7 @@ static void test_multiframegif(void)
 
     count = 12345;
     stat = GdipImageGetFrameCount((GpImage*)bmp, &dimension, &count);
-    todo_wine expect(Ok, stat);
+    expect(Ok, stat);
     todo_wine expect(2, count);
 
     /* SelectActiveFrame overwrites our current data */
@@ -1618,8 +1696,8 @@ static void test_multiframegif(void)
 
     count = 12345;
     stat = GdipImageGetFrameCount((GpImage*)bmp, &dimension, &count);
-    todo_wine expect(Ok, stat);
-    todo_wine expect(1, count);
+    expect(Ok, stat);
+    expect(1, count);
 
     GdipDisposeImage((GpImage*)bmp);
     IStream_Release(stream);
@@ -1641,30 +1719,30 @@ static void test_rotateflip(void)
     expect(Ok, stat);
 
     stat = GdipImageRotateFlip(bitmap, Rotate90FlipNone);
-    todo_wine expect(Ok, stat);
+    expect(Ok, stat);
 
     stat = GdipGetImageWidth(bitmap, &width);
     expect(Ok, stat);
     stat = GdipGetImageHeight(bitmap, &height);
     expect(Ok, stat);
-    todo_wine expect(2, width);
-    todo_wine expect(3, height);
+    expect(2, width);
+    expect(3, height);
 
     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 0, 0, &color);
     expect(Ok, stat);
-    todo_wine expect(0xff00ffff, color);
+    expect(0xff00ffff, color);
 
     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 1, 0, &color);
     expect(Ok, stat);
-    todo_wine expect(0xffff0000, color);
+    expect(0xffff0000, color);
 
     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 0, 2, &color);
-    todo_wine expect(Ok, stat);
-    todo_wine expect(0xffffff00, color);
+    expect(Ok, stat);
+    expect(0xffffff00, color);
 
     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 1, 2, &color);
-    todo_wine expect(Ok, stat);
-    todo_wine expect(0xff0000ff, color);
+    expect(Ok, stat);
+    expect(0xff0000ff, color);
 
     expect(0, bits[0]);
     expect(0, bits[1]);
@@ -1677,7 +1755,7 @@ static void test_rotateflip(void)
     expect(Ok, stat);
 
     stat = GdipImageRotateFlip(bitmap, RotateNoneFlipX);
-    todo_wine expect(Ok, stat);
+    expect(Ok, stat);
 
     stat = GdipGetImageWidth(bitmap, &width);
     expect(Ok, stat);
@@ -1688,19 +1766,19 @@ static void test_rotateflip(void)
 
     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 0, 0, &color);
     expect(Ok, stat);
-    todo_wine expect(0xff0000ff, color);
+    expect(0xff0000ff, color);
 
     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 2, 0, &color);
     expect(Ok, stat);
-    todo_wine expect(0xffff0000, color);
+    expect(0xffff0000, color);
 
     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 0, 1, &color);
     expect(Ok, stat);
-    todo_wine expect(0xffffff00, color);
+    expect(0xffffff00, color);
 
     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 2, 1, &color);
     expect(Ok, stat);
-    todo_wine expect(0xff00ffff, color);
+    expect(0xff00ffff, color);
 
     expect(0, bits[0]);
     expect(0, bits[1]);
@@ -1713,7 +1791,7 @@ static void test_rotateflip(void)
     expect(Ok, stat);
 
     stat = GdipImageRotateFlip(bitmap, RotateNoneFlipY);
-    todo_wine expect(Ok, stat);
+    expect(Ok, stat);
 
     stat = GdipGetImageWidth(bitmap, &width);
     expect(Ok, stat);
@@ -1724,19 +1802,19 @@ static void test_rotateflip(void)
 
     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 0, 0, &color);
     expect(Ok, stat);
-    todo_wine expect(0xff00ffff, color);
+    expect(0xff00ffff, color);
 
     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 2, 0, &color);
     expect(Ok, stat);
-    todo_wine expect(0xffffff00, color);
+    expect(0xffffff00, color);
 
     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 0, 1, &color);
     expect(Ok, stat);
-    todo_wine expect(0xffff0000, color);
+    expect(0xffff0000, color);
 
     stat = GdipBitmapGetPixel((GpBitmap*)bitmap, 2, 1, &color);
     expect(Ok, stat);
-    todo_wine expect(0xff0000ff, color);
+    expect(0xff0000ff, color);
 
     expect(0, bits[0]);
     expect(0, bits[1]);
@@ -1801,7 +1879,7 @@ static void test_remaptable(void)
 
     stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
     expect(Ok, stat);
-    todo_wine ok(color_match(0xffff00ff, color, 1), "Expected ffff00ff, got %.8x\n", color);
+    ok(color_match(0xffff00ff, color, 1), "Expected ffff00ff, got %.8x\n", color);
 
     GdipDeleteGraphics(graphics);
     GdipDisposeImage((GpImage*)bitmap1);
index 563943f..f64d7d9 100644 (file)
@@ -156,7 +156,7 @@ static void test_charset(void)
     hr = MimeOleGetInternat(&internat);
     ok(hr == S_OK, "ret %08x\n", hr);
 
-    hr = IMimeInternational_FindCharset(internat, "non-existent", &hcs);
+    hr = IMimeInternational_FindCharset(internat, "nonexistent", &hcs);
     ok(hr == MIME_E_NOT_FOUND, "got %08x\n", hr);
 
     hr = IMimeInternational_FindCharset(internat, "windows-1252", &hcs_windows_1252);
index fac1112..7b74cb1 100644 (file)
@@ -113,6 +113,7 @@ ok(typeof(m) === "object", "typeof m is not object");
 ok(m.length === 2, "m.length is not 2");
 ok(m["0"] === "ab", "m[0] is not \"ab\"");
 ok(m["1"] === "ab", "m[1] is not \"ab\"");
+/* ok(m.input === "abcabc", "m.input = " + m.input); */
 
 m = "abcabc".match(/Ab/g);
 ok(typeof(m) === "object", "typeof m is not object");
@@ -167,6 +168,32 @@ ok(m["0"] === "ab", "m[0] is not \"ab\"");
 m = "abcabc".match();
 ok(m === null, "m is not null");
 
+m = "abcabc".match(/(a)(b)cabc/);
+ok(typeof(m) === "object", "typeof m is not object");
+ok(m.length === 3, "m.length is not 3");
+ok(m[0] === "abcabc", "m[0] is not \"abc\"");
+ok(m[1] === "a", "m[1] is not \"a\"");
+ok(m[2] === "b", "m[2] is not \"b\"");
+
+re = /(a)bcabc/;
+re.lastIndex = -3;
+m = "abcabc".match(re);
+ok(typeof(m) === "object", "typeof m is not object");
+ok(m.length === 2, "m.length = " + m.length + "expected 3");
+ok(m[0] === "abcabc", "m[0] is not \"abc\"");
+ok(m[1] === "a", "m[1] is not \"a\"");
+ok(re.lastIndex === 6, "re.lastIndex = " + re.lastIndex);
+
+re = /(a)bcabc/;
+re.lastIndex = 2;
+m = "abcabcxxx".match(re);
+ok(typeof(m) === "object", "typeof m is not object");
+ok(m.length === 2, "m.length = " + m.length + "expected 3");
+ok(m[0] === "abcabc", "m[0] is not \"abc\"");
+ok(m[1] === "a", "m[1] is not \"a\"");
+ok(m.input === "abcabcxxx", "m.input = " + m.input);
+ok(re.lastIndex === 6, "re.lastIndex = " + re.lastIndex);
+
 r = "- [test] -".replace(re = /\[([^\[]+)\]/g, "success");
 ok(r === "- success -", "r = " + r + " expected '- success -'");
 ok(re.lastIndex === 8, "re.lastIndex = " + re.lastIndex);
@@ -410,6 +437,19 @@ m = re.exec("  ");
 ok(re.lastIndex === 0, "re.lastIndex = " + re.lastIndex + " expected 0");
 ok(m === null, "m = " + m + " expected null");
 
+re = /a/;
+re.lastIndex = -3;
+ok(re.lastIndex === -3, "re.lastIndex = " + re.lastIndex + " expected -3");
+m = re.exec(" a a ");
+ok(re.lastIndex === 2, "re.lastIndex = " + re.lastIndex + " expected 0");
+ok(m.index === 1, "m = " + m + " expected 1");
+
+re.lastIndex = -1;
+ok(re.lastIndex === -1, "re.lastIndex = " + re.lastIndex + " expected -1");
+m = re.exec("  ");
+ok(re.lastIndex === 0, "re.lastIndex = " + re.lastIndex + " expected 0");
+ok(m === null, "m = " + m + " expected null");
+
 re = /aa/g;
 i = 'baacd'.search(re);
 ok(i === 1, "'baacd'.search(re) = " + i);
index 7ba9140..c445b41 100644 (file)
@@ -38,15 +38,28 @@ static ITfDocumentMgr *g_dm = NULL;
 static TfClientId cid = 0;
 static TfClientId tid = 0;
 
+static ITextStoreACPSink *ACPSink;
+
 #define SINK_UNEXPECTED 0
 #define SINK_EXPECTED 1
 #define SINK_FIRED 2
+#define SINK_IGNORE 3
+#define SINK_OPTIONAL 4
+
+#define SINK_ACTION_MASK 0xff
+#define SINK_OPTION_MASK 0xff00
+#define SINK_EXPECTED_COUNT_MASK 0xff0000
+
+#define SINK_OPTION_TODO      0x0100
+
+#define FOCUS_IGNORE    (ITfDocumentMgr*)0xffffffff
 
 static BOOL test_ShouldActivate = FALSE;
 static BOOL test_ShouldDeactivate = FALSE;
 
 static DWORD tmSinkCookie;
 static DWORD tmSinkRefCount;
+static DWORD documentStatus;
 static ITfDocumentMgr *test_CurrentFocus = NULL;
 static ITfDocumentMgr *test_PrevFocus = NULL;
 static INT  test_OnSetFocus = SINK_UNEXPECTED;
@@ -54,236 +67,103 @@ static INT  test_OnInitDocumentMgr = SINK_UNEXPECTED;
 static INT  test_OnPushContext = SINK_UNEXPECTED;
 static INT  test_OnPopContext = SINK_UNEXPECTED;
 static INT  test_KEV_OnSetFocus = SINK_UNEXPECTED;
+static INT  test_ACP_AdviseSink = SINK_UNEXPECTED;
+static INT  test_ACP_GetStatus = SINK_UNEXPECTED;
+static INT  test_ACP_RequestLock = SINK_UNEXPECTED;
+static INT  test_ACP_GetEndACP = SINK_UNEXPECTED;
+static INT  test_ACP_GetSelection = SINK_UNEXPECTED;
+static INT  test_DoEditSession = SINK_UNEXPECTED;
+static INT  test_ACP_InsertTextAtSelection = SINK_UNEXPECTED;
+static INT  test_ACP_SetSelection = SINK_UNEXPECTED;
+static INT  test_OnEndEdit = SINK_UNEXPECTED;
 
-HRESULT RegisterTextService(REFCLSID rclsid);
-HRESULT UnregisterTextService();
-HRESULT ThreadMgrEventSink_Constructor(IUnknown **ppOut);
-HRESULT TextStoreACP_Constructor(IUnknown **ppOut);
-
-DEFINE_GUID(CLSID_FakeService, 0xEDE1A7AD,0x66DE,0x47E0,0xB6,0x20,0x3E,0x92,0xF8,0x24,0x6B,0xF3);
-DEFINE_GUID(CLSID_TF_InputProcessorProfiles, 0x33c53a50,0xf456,0x4884,0xb0,0x49,0x85,0xfd,0x64,0x3e,0xcf,0xed);
-DEFINE_GUID(CLSID_TF_CategoryMgr,         0xA4B544A1,0x438D,0x4B41,0x93,0x25,0x86,0x95,0x23,0xE2,0xD6,0xC7);
-DEFINE_GUID(GUID_TFCAT_TIP_KEYBOARD,     0x34745c63,0xb2f0,0x4784,0x8b,0x67,0x5e,0x12,0xc8,0x70,0x1a,0x31);
-DEFINE_GUID(GUID_TFCAT_TIP_SPEECH,       0xB5A73CD1,0x8355,0x426B,0xA1,0x61,0x25,0x98,0x08,0xF2,0x6B,0x14);
-DEFINE_GUID(GUID_TFCAT_TIP_HANDWRITING,  0x246ecb87,0xc2f2,0x4abe,0x90,0x5b,0xc8,0xb3,0x8a,0xdd,0x2c,0x43);
-DEFINE_GUID (GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER,  0x046B8C80,0x1647,0x40F7,0x9B,0x21,0xB9,0x3B,0x81,0xAA,0xBC,0x1B);
-DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
-DEFINE_GUID(CLSID_TF_ThreadMgr,           0x529a9e6b,0x6587,0x4f23,0xab,0x9e,0x9c,0x7d,0x68,0x3e,0x3c,0x50);
-DEFINE_GUID(CLSID_PreservedKey,           0xA0ED8E55,0xCD3B,0x4274,0xB2,0x95,0xF6,0xC9,0xBA,0x2B,0x84,0x72);
-
-
-static HRESULT initialize(void)
-{
-    HRESULT hr;
-    CoInitialize(NULL);
-    hr = CoCreateInstance (&CLSID_TF_InputProcessorProfiles, NULL,
-          CLSCTX_INPROC_SERVER, &IID_ITfInputProcessorProfiles, (void**)&g_ipp);
-    if (SUCCEEDED(hr))
-        hr = CoCreateInstance (&CLSID_TF_CategoryMgr, NULL,
-          CLSCTX_INPROC_SERVER, &IID_ITfCategoryMgr, (void**)&g_cm);
-    if (SUCCEEDED(hr))
-        hr = CoCreateInstance (&CLSID_TF_ThreadMgr, NULL,
-          CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, (void**)&g_tm);
-    return hr;
-}
-
-static void cleanup(void)
-{
-    if (g_ipp)
-        ITfInputProcessorProfiles_Release(g_ipp);
-    if (g_cm)
-        ITfCategoryMgr_Release(g_cm);
-    if (g_tm)
-        ITfThreadMgr_Release(g_tm);
-    CoUninitialize();
-}
-
-static void test_Register(void)
-{
-    HRESULT hr;
-
-    static const WCHAR szDesc[] = {'F','a','k','e',' ','W','i','n','e',' ','S','e','r','v','i','c','e',0};
-    static const WCHAR szFile[] = {'F','a','k','e',' ','W','i','n','e',' ','S','e','r','v','i','c','e',' ','F','i','l','e',0};
-
-    hr = ITfInputProcessorProfiles_GetCurrentLanguage(g_ipp,&gLangid);
-    ok(SUCCEEDED(hr),"Unable to get current language id\n");
-    trace("Current Language %x\n",gLangid);
-
-    hr = RegisterTextService(&CLSID_FakeService);
-    ok(SUCCEEDED(hr),"Unable to register COM for TextService\n");
-    hr = ITfInputProcessorProfiles_Register(g_ipp, &CLSID_FakeService);
-    ok(SUCCEEDED(hr),"Unable to register text service(%x)\n",hr);
-    hr = ITfInputProcessorProfiles_AddLanguageProfile(g_ipp, &CLSID_FakeService, gLangid, &CLSID_FakeService, szDesc, sizeof(szDesc)/sizeof(WCHAR), szFile, sizeof(szFile)/sizeof(WCHAR), 1);
-    ok(SUCCEEDED(hr),"Unable to add Language Profile (%x)\n",hr);
-}
 
-static void test_Unregister(void)
+static inline int expected_count(int *sink)
 {
-    HRESULT hr;
-    hr = ITfInputProcessorProfiles_Unregister(g_ipp, &CLSID_FakeService);
-    ok(SUCCEEDED(hr),"Unable to unregister text service(%x)\n",hr);
-    UnregisterTextService();
+    return (*sink & SINK_EXPECTED_COUNT_MASK)>>16;
 }
 
-static void test_EnumInputProcessorInfo(void)
+static inline void _sink_fire_ok(INT *sink, const CHAR* name)
 {
-    IEnumGUID *ppEnum;
-    BOOL found = FALSE;
+    int count;
+    int todo = *sink & SINK_OPTION_TODO;
+    int action = *sink & SINK_ACTION_MASK;
 
-    if (SUCCEEDED(ITfInputProcessorProfiles_EnumInputProcessorInfo(g_ipp, &ppEnum)))
-    {
-        ULONG fetched;
-        GUID g;
-        while (IEnumGUID_Next(ppEnum, 1, &g, &fetched) == S_OK)
-        {
-            if(IsEqualGUID(&g,&CLSID_FakeService))
-                found = TRUE;
-        }
-    }
-    ok(found,"Did not find registered text service\n");
-}
+    if (winetest_interactive)
+        winetest_trace("firing %s\n",name);
 
-static void test_EnumLanguageProfiles(void)
-{
-    BOOL found = FALSE;
-    IEnumTfLanguageProfiles *ppEnum;
-    if (SUCCEEDED(ITfInputProcessorProfiles_EnumLanguageProfiles(g_ipp,gLangid,&ppEnum)))
+    switch (action)
     {
-        TF_LANGUAGEPROFILE profile;
-        while (IEnumTfLanguageProfiles_Next(ppEnum,1,&profile,NULL)==S_OK)
-        {
-            if (IsEqualGUID(&profile.clsid,&CLSID_FakeService))
+        case SINK_OPTIONAL:
+        case SINK_EXPECTED:
+            count = expected_count(sink);
+            if (count > 1)
             {
-                found = TRUE;
-                ok(profile.langid == gLangid, "LangId Incorrect\n");
-                ok(IsEqualGUID(&profile.catid,&GUID_TFCAT_TIP_KEYBOARD), "CatId Incorrect\n");
-                ok(IsEqualGUID(&profile.guidProfile,&CLSID_FakeService), "guidProfile Incorrect\n");
+                count --;
+                *sink = (*sink & ~SINK_EXPECTED_COUNT_MASK) + (count << 16);
+                return;
             }
-        }
+            break;
+        case SINK_IGNORE:
+            winetest_trace("Ignoring %s\n",name);
+            return;
+        default:
+            if (todo)
+                todo_wine winetest_ok(0, "Unexpected %s sink\n",name);
+            else
+                winetest_ok(0, "Unexpected %s sink\n",name);
     }
-    ok(found,"Registered text service not found\n");
-}
-
-static void test_RegisterCategory(void)
-{
-    HRESULT hr;
-    hr = ITfCategoryMgr_RegisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_TIP_KEYBOARD, &CLSID_FakeService);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterCategory failed\n");
-    hr = ITfCategoryMgr_RegisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &CLSID_FakeService);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterCategory failed\n");
-}
-
-static void test_UnregisterCategory(void)
-{
-    HRESULT hr;
-    hr = ITfCategoryMgr_UnregisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_TIP_KEYBOARD, &CLSID_FakeService);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_UnregisterCategory failed\n");
-    hr = ITfCategoryMgr_UnregisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &CLSID_FakeService);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_UnregisterCategory failed\n");
-}
-
-static void test_FindClosestCategory(void)
-{
-    GUID output;
-    HRESULT hr;
-    const GUID *list[3] = {&GUID_TFCAT_TIP_SPEECH, &GUID_TFCAT_TIP_KEYBOARD, &GUID_TFCAT_TIP_HANDWRITING};
-
-    hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, NULL, 0);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr);
-    ok(IsEqualGUID(&output,&GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER),"Wrong GUID\n");
-
-    hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, list, 1);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr);
-    ok(IsEqualGUID(&output,&GUID_NULL),"Wrong GUID\n");
-
-    hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, list, 3);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr);
-    ok(IsEqualGUID(&output,&GUID_TFCAT_TIP_KEYBOARD),"Wrong GUID\n");
-}
-
-static void test_Enable(void)
-{
-    HRESULT hr;
-    BOOL enabled = FALSE;
-
-    hr = ITfInputProcessorProfiles_EnableLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, TRUE);
-    ok(SUCCEEDED(hr),"Failed to enable text service\n");
-    hr = ITfInputProcessorProfiles_IsEnabledLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, &enabled);
-    ok(SUCCEEDED(hr),"Failed to get enabled state\n");
-    ok(enabled == TRUE,"enabled state incorrect\n");
+    *sink = SINK_FIRED;
 }
 
-static void test_Disable(void)
-{
-    HRESULT hr;
-
-    trace("Disabling\n");
-    hr = ITfInputProcessorProfiles_EnableLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, FALSE);
-    ok(SUCCEEDED(hr),"Failed to disable text service\n");
-}
+#define sink_fire_ok(a,b) (winetest_set_location(__FILE__,__LINE__), 0) ? 0 : _sink_fire_ok(a,b)
 
-static void test_ThreadMgrAdviseSinks(void)
+static inline void _sink_check_ok(INT *sink, const CHAR* name)
 {
-    ITfSource *source = NULL;
-    HRESULT hr;
-    IUnknown *sink;
-
-    hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfSource, (LPVOID*)&source);
-    ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for ThreadMgr\n");
-    if (!source)
-        return;
-
-    ThreadMgrEventSink_Constructor(&sink);
-
-    tmSinkRefCount = 1;
-    tmSinkCookie = 0;
-    hr = ITfSource_AdviseSink(source,&IID_ITfThreadMgrEventSink, sink, &tmSinkCookie);
-    ok(SUCCEEDED(hr),"Failed to Advise Sink\n");
-    ok(tmSinkCookie!=0,"Failed to get sink cookie\n");
+    int action = *sink & SINK_ACTION_MASK;
+    int todo = *sink & SINK_OPTION_TODO;
 
-    /* Advising the sink adds a ref, Relesing here lets the object be deleted
-       when unadvised */
-    tmSinkRefCount = 2;
-    IUnknown_Release(sink);
-    ITfSource_Release(source);
+    switch (action)
+    {
+        case SINK_OPTIONAL:
+            if (winetest_interactive)
+                winetest_trace("optional sink %s not fired\n",name);
+        case SINK_FIRED:
+            break;
+        case SINK_IGNORE:
+            return;
+        default:
+            if (todo)
+                todo_wine winetest_ok(0, "%s not fired as expected, in state %x\n",name,*sink);
+            else
+                winetest_ok(0, "%s not fired as expected, in state %x\n",name,*sink);
+    }
+    *sink = SINK_UNEXPECTED;
 }
 
-static void test_ThreadMgrUnadviseSinks(void)
-{
-    ITfSource *source = NULL;
-    HRESULT hr;
-
-    hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfSource, (LPVOID*)&source);
-    ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for ThreadMgr\n");
-    if (!source)
-        return;
-
-    tmSinkRefCount = 1;
-    hr = ITfSource_UnadviseSink(source, tmSinkCookie);
-    ok(SUCCEEDED(hr),"Failed to unadvise Sink\n");
-    ITfSource_Release(source);
-}
+#define sink_check_ok(a,b) (winetest_set_location(__FILE__,__LINE__), 0) ? 0 : _sink_check_ok(a,b)
 
 /**********************************************************************
- * ITfKeyEventSink
+ * ITextStoreACP
  **********************************************************************/
-typedef struct tagKeyEventSink
+typedef struct tagTextStoreACP
 {
-    const ITfKeyEventSinkVtbl *KeyEventSinkVtbl;
+    const ITextStoreACPVtbl *TextStoreACPVtbl;
     LONG refCount;
-} KeyEventSink;
 
-static void KeyEventSink_Destructor(KeyEventSink *This)
+} TextStoreACP;
+
+static void TextStoreACP_Destructor(TextStoreACP *This)
 {
     HeapFree(GetProcessHeap(),0,This);
 }
 
-static HRESULT WINAPI KeyEventSink_QueryInterface(ITfKeyEventSink *iface, REFIID iid, LPVOID *ppvOut)
+static HRESULT WINAPI TextStoreACP_QueryInterface(ITextStoreACP *iface, REFIID iid, LPVOID *ppvOut)
 {
-    KeyEventSink *This = (KeyEventSink *)iface;
+    TextStoreACP *This = (TextStoreACP *)iface;
     *ppvOut = NULL;
 
-    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfKeyEventSink))
+    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACP))
     {
         *ppvOut = This;
     }
@@ -297,718 +177,1097 @@ static HRESULT WINAPI KeyEventSink_QueryInterface(ITfKeyEventSink *iface, REFIID
     return E_NOINTERFACE;
 }
 
-static ULONG WINAPI KeyEventSink_AddRef(ITfKeyEventSink *iface)
+static ULONG WINAPI TextStoreACP_AddRef(ITextStoreACP *iface)
 {
-    KeyEventSink *This = (KeyEventSink *)iface;
+    TextStoreACP *This = (TextStoreACP *)iface;
     return InterlockedIncrement(&This->refCount);
 }
 
-static ULONG WINAPI KeyEventSink_Release(ITfKeyEventSink *iface)
+static ULONG WINAPI TextStoreACP_Release(ITextStoreACP *iface)
 {
-    KeyEventSink *This = (KeyEventSink *)iface;
+    TextStoreACP *This = (TextStoreACP *)iface;
     ULONG ret;
 
     ret = InterlockedDecrement(&This->refCount);
     if (ret == 0)
-        KeyEventSink_Destructor(This);
+        TextStoreACP_Destructor(This);
     return ret;
 }
 
-static HRESULT WINAPI KeyEventSink_OnSetFocus(ITfKeyEventSink *iface,
-        BOOL fForeground)
+static HRESULT WINAPI TextStoreACP_AdviseSink(ITextStoreACP *iface,
+    REFIID riid, IUnknown *punk, DWORD dwMask)
 {
-    ok(test_KEV_OnSetFocus == SINK_EXPECTED,"Unexpected KeyEventSink_OnSetFocus\n");
-    test_KEV_OnSetFocus = SINK_FIRED;
+    HRESULT hr;
+
+    sink_fire_ok(&test_ACP_AdviseSink,"TextStoreACP_AdviseSink");
+
+    hr = IUnknown_QueryInterface(punk, &IID_ITextStoreACPSink,(LPVOID*)(&ACPSink));
+    ok(SUCCEEDED(hr),"Unable to QueryInterface on sink\n");
     return S_OK;
 }
 
-static HRESULT WINAPI KeyEventSink_OnTestKeyDown(ITfKeyEventSink *iface,
-        ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
+static HRESULT WINAPI TextStoreACP_UnadviseSink(ITextStoreACP *iface,
+    IUnknown *punk)
 {
     trace("\n");
     return S_OK;
 }
 
-static HRESULT WINAPI KeyEventSink_OnTestKeyUp(ITfKeyEventSink *iface,
-        ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
+static HRESULT WINAPI TextStoreACP_RequestLock(ITextStoreACP *iface,
+    DWORD dwLockFlags, HRESULT *phrSession)
 {
-    trace("\n");
+    sink_fire_ok(&test_ACP_RequestLock,"TextStoreACP_RequestLock");
+    *phrSession = ITextStoreACPSink_OnLockGranted(ACPSink, dwLockFlags);
     return S_OK;
 }
-
-static HRESULT WINAPI KeyEventSink_OnKeyDown(ITfKeyEventSink *iface,
-        ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
+static HRESULT WINAPI TextStoreACP_GetStatus(ITextStoreACP *iface,
+    TS_STATUS *pdcs)
 {
-    trace("\n");
+    sink_fire_ok(&test_ACP_GetStatus,"TextStoreACP_GetStatus");
+    pdcs->dwDynamicFlags = documentStatus;
     return S_OK;
 }
-
-static HRESULT WINAPI KeyEventSink_OnKeyUp(ITfKeyEventSink *iface,
-        ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
+static HRESULT WINAPI TextStoreACP_QueryInsert(ITextStoreACP *iface,
+    LONG acpTestStart, LONG acpTestEnd, ULONG cch, LONG *pacpResultStart,
+    LONG *pacpResultEnd)
 {
     trace("\n");
     return S_OK;
 }
-
-static HRESULT WINAPI KeyEventSink_OnPreservedKey(ITfKeyEventSink *iface,
-    ITfContext *pic, REFGUID rguid, BOOL *pfEaten)
+static HRESULT WINAPI TextStoreACP_GetSelection(ITextStoreACP *iface,
+    ULONG ulIndex, ULONG ulCount, TS_SELECTION_ACP *pSelection, ULONG *pcFetched)
 {
-    trace("\n");
+    sink_fire_ok(&test_ACP_GetSelection,"TextStoreACP_GetSelection");
+
+    pSelection->acpStart = 10;
+    pSelection->acpEnd = 20;
+    pSelection->style.fInterimChar = 0;
+    pSelection->style.ase = TS_AE_NONE;
+    *pcFetched = 1;
+
     return S_OK;
 }
-
-static const ITfKeyEventSinkVtbl KeyEventSink_KeyEventSinkVtbl =
+static HRESULT WINAPI TextStoreACP_SetSelection(ITextStoreACP *iface,
+    ULONG ulCount, const TS_SELECTION_ACP *pSelection)
 {
-    KeyEventSink_QueryInterface,
-    KeyEventSink_AddRef,
-    KeyEventSink_Release,
+    sink_fire_ok(&test_ACP_SetSelection,"TextStoreACP_SetSelection");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_GetText(ITextStoreACP *iface,
+    LONG acpStart, LONG acpEnd, WCHAR *pchPlain, ULONG cchPlainReq,
+    ULONG *pcchPlainRet, TS_RUNINFO *prgRunInfo, ULONG cRunInfoReq,
+    ULONG *pcRunInfoRet, LONG *pacpNext)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_SetText(ITextStoreACP *iface,
+    DWORD dwFlags, LONG acpStart, LONG acpEnd, const WCHAR *pchText,
+    ULONG cch, TS_TEXTCHANGE *pChange)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_GetFormattedText(ITextStoreACP *iface,
+    LONG acpStart, LONG acpEnd, IDataObject **ppDataObject)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_GetEmbedded(ITextStoreACP *iface,
+    LONG acpPos, REFGUID rguidService, REFIID riid, IUnknown **ppunk)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_QueryInsertEmbedded(ITextStoreACP *iface,
+    const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_InsertEmbedded(ITextStoreACP *iface,
+    DWORD dwFlags, LONG acpStart, LONG acpEnd, IDataObject *pDataObject,
+    TS_TEXTCHANGE *pChange)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_InsertTextAtSelection(ITextStoreACP *iface,
+    DWORD dwFlags, const WCHAR *pchText, ULONG cch, LONG *pacpStart,
+    LONG *pacpEnd, TS_TEXTCHANGE *pChange)
+{
+    sink_fire_ok(&test_ACP_InsertTextAtSelection,"TextStoreACP_InsertTextAtSelection");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_InsertEmbeddedAtSelection(ITextStoreACP *iface,
+    DWORD dwFlags, IDataObject *pDataObject, LONG *pacpStart, LONG *pacpEnd,
+    TS_TEXTCHANGE *pChange)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_RequestSupportedAttrs(ITextStoreACP *iface,
+    DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_RequestAttrsAtPosition(ITextStoreACP *iface,
+    LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs,
+    DWORD dwFlags)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_RequestAttrsTransitioningAtPosition(ITextStoreACP *iface,
+    LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs,
+    DWORD dwFlags)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_FindNextAttrTransition(ITextStoreACP *iface,
+    LONG acpStart, LONG acpHalt, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs,
+    DWORD dwFlags, LONG *pacpNext, BOOL *pfFound, LONG *plFoundOffset)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_RetrieveRequestedAttrs(ITextStoreACP *iface,
+    ULONG ulCount, TS_ATTRVAL *paAttrVals, ULONG *pcFetched)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_GetEndACP(ITextStoreACP *iface,
+    LONG *pacp)
+{
+    sink_fire_ok(&test_ACP_GetEndACP,"TextStoreACP_GetEndACP");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_GetActiveView(ITextStoreACP *iface,
+    TsViewCookie *pvcView)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_GetACPFromPoint(ITextStoreACP *iface,
+    TsViewCookie vcView, const POINT *ptScreen, DWORD dwFlags,
+    LONG *pacp)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_GetTextExt(ITextStoreACP *iface,
+    TsViewCookie vcView, LONG acpStart, LONG acpEnd, RECT *prc,
+    BOOL *pfClipped)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_GetScreenExt(ITextStoreACP *iface,
+    TsViewCookie vcView, RECT *prc)
+{
+    trace("\n");
+    return S_OK;
+}
+static HRESULT WINAPI TextStoreACP_GetWnd(ITextStoreACP *iface,
+    TsViewCookie vcView, HWND *phwnd)
+{
+    trace("\n");
+    return S_OK;
+}
 
-    KeyEventSink_OnSetFocus,
-    KeyEventSink_OnTestKeyDown,
-    KeyEventSink_OnTestKeyUp,
-    KeyEventSink_OnKeyDown,
-    KeyEventSink_OnKeyUp,
-    KeyEventSink_OnPreservedKey
+static const ITextStoreACPVtbl TextStoreACP_TextStoreACPVtbl =
+{
+    TextStoreACP_QueryInterface,
+    TextStoreACP_AddRef,
+    TextStoreACP_Release,
+
+    TextStoreACP_AdviseSink,
+    TextStoreACP_UnadviseSink,
+    TextStoreACP_RequestLock,
+    TextStoreACP_GetStatus,
+    TextStoreACP_QueryInsert,
+    TextStoreACP_GetSelection,
+    TextStoreACP_SetSelection,
+    TextStoreACP_GetText,
+    TextStoreACP_SetText,
+    TextStoreACP_GetFormattedText,
+    TextStoreACP_GetEmbedded,
+    TextStoreACP_QueryInsertEmbedded,
+    TextStoreACP_InsertEmbedded,
+    TextStoreACP_InsertTextAtSelection,
+    TextStoreACP_InsertEmbeddedAtSelection,
+    TextStoreACP_RequestSupportedAttrs,
+    TextStoreACP_RequestAttrsAtPosition,
+    TextStoreACP_RequestAttrsTransitioningAtPosition,
+    TextStoreACP_FindNextAttrTransition,
+    TextStoreACP_RetrieveRequestedAttrs,
+    TextStoreACP_GetEndACP,
+    TextStoreACP_GetActiveView,
+    TextStoreACP_GetACPFromPoint,
+    TextStoreACP_GetTextExt,
+    TextStoreACP_GetScreenExt,
+    TextStoreACP_GetWnd
 };
 
-HRESULT KeyEventSink_Constructor(ITfKeyEventSink **ppOut)
+static HRESULT TextStoreACP_Constructor(IUnknown **ppOut)
 {
-    KeyEventSink *This;
+    TextStoreACP *This;
 
-    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(KeyEventSink));
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextStoreACP));
     if (This == NULL)
         return E_OUTOFMEMORY;
 
-    This->KeyEventSinkVtbl = &KeyEventSink_KeyEventSinkVtbl;
+    This->TextStoreACPVtbl = &TextStoreACP_TextStoreACPVtbl;
     This->refCount = 1;
 
-    *ppOut = (ITfKeyEventSink*)This;
+    *ppOut = (IUnknown *)This;
     return S_OK;
 }
 
-
-static void test_KeystrokeMgr(void)
+/**********************************************************************
+ * ITfThreadMgrEventSink
+ **********************************************************************/
+typedef struct tagThreadMgrEventSink
 {
-    ITfKeystrokeMgr *keymgr= NULL;
-    HRESULT hr;
-    TF_PRESERVEDKEY tfpk;
-    BOOL preserved;
-    ITfKeyEventSink *sink;
-
-    KeyEventSink_Constructor(&sink);
-
-    hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfKeystrokeMgr, (LPVOID*)&keymgr);
-    ok(SUCCEEDED(hr),"Failed to get IID_ITfKeystrokeMgr for ThreadMgr\n");
-
-    tfpk.uVKey = 'A';
-    tfpk.uModifiers = TF_MOD_SHIFT;
-
-    test_KEV_OnSetFocus = SINK_EXPECTED;
-    hr = ITfKeystrokeMgr_AdviseKeyEventSink(keymgr,tid,sink,TRUE);
-    todo_wine ok(SUCCEEDED(hr),"ITfKeystrokeMgr_AdviseKeyEventSink failed\n");
-    todo_wine ok(test_KEV_OnSetFocus == SINK_FIRED, "KeyEventSink_OnSetFocus not fired as expected\n");
-
-    hr =ITfKeystrokeMgr_PreserveKey(keymgr, 0, &CLSID_PreservedKey, &tfpk, NULL, 0);
-    ok(hr==E_INVALIDARG,"ITfKeystrokeMgr_PreserveKey inproperly succeeded\n");
+    const ITfThreadMgrEventSinkVtbl *ThreadMgrEventSinkVtbl;
+    LONG refCount;
+} ThreadMgrEventSink;
 
-    hr =ITfKeystrokeMgr_PreserveKey(keymgr, tid, &CLSID_PreservedKey, &tfpk, NULL, 0);
-    ok(SUCCEEDED(hr),"ITfKeystrokeMgr_PreserveKey failed\n");
+static void ThreadMgrEventSink_Destructor(ThreadMgrEventSink *This)
+{
+    HeapFree(GetProcessHeap(),0,This);
+}
 
-    hr =ITfKeystrokeMgr_PreserveKey(keymgr, tid, &CLSID_PreservedKey, &tfpk, NULL, 0);
-    ok(hr == TF_E_ALREADY_EXISTS,"ITfKeystrokeMgr_PreserveKey inproperly succeeded\n");
+static HRESULT WINAPI ThreadMgrEventSink_QueryInterface(ITfThreadMgrEventSink *iface, REFIID iid, LPVOID *ppvOut)
+{
+    ThreadMgrEventSink *This = (ThreadMgrEventSink *)iface;
+    *ppvOut = NULL;
 
-    preserved = FALSE;
-    hr = ITfKeystrokeMgr_IsPreservedKey(keymgr, &CLSID_PreservedKey, &tfpk, &preserved);
-    ok(hr == S_OK, "ITfKeystrokeMgr_IsPreservedKey failed\n");
-    if (hr == S_OK) ok(preserved == TRUE,"misreporting preserved key\n");
+    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfThreadMgrEventSink))
+    {
+        *ppvOut = This;
+    }
 
-    hr = ITfKeystrokeMgr_UnpreserveKey(keymgr, &CLSID_PreservedKey,&tfpk);
-    ok(SUCCEEDED(hr),"ITfKeystrokeMgr_UnpreserveKey failed\n");
+    if (*ppvOut)
+    {
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
 
-    hr = ITfKeystrokeMgr_IsPreservedKey(keymgr, &CLSID_PreservedKey, &tfpk, &preserved);
-    ok(hr == S_FALSE, "ITfKeystrokeMgr_IsPreservedKey failed\n");
-    if (hr == S_FALSE) ok(preserved == FALSE,"misreporting preserved key\n");
+    return E_NOINTERFACE;
+}
 
-    hr = ITfKeystrokeMgr_UnpreserveKey(keymgr, &CLSID_PreservedKey,&tfpk);
-    ok(hr==CONNECT_E_NOCONNECTION,"ITfKeystrokeMgr_UnpreserveKey inproperly succeeded\n");
+static ULONG WINAPI ThreadMgrEventSink_AddRef(ITfThreadMgrEventSink *iface)
+{
+    ThreadMgrEventSink *This = (ThreadMgrEventSink *)iface;
+    ok (tmSinkRefCount == This->refCount,"ThreadMgrEventSink refcount off %i vs %i\n",This->refCount,tmSinkRefCount);
+    return InterlockedIncrement(&This->refCount);
+}
 
-    hr = ITfKeystrokeMgr_UnadviseKeyEventSink(keymgr,tid);
-    todo_wine ok(SUCCEEDED(hr),"ITfKeystrokeMgr_UnadviseKeyEventSink failed\n");
+static ULONG WINAPI ThreadMgrEventSink_Release(ITfThreadMgrEventSink *iface)
+{
+    ThreadMgrEventSink *This = (ThreadMgrEventSink *)iface;
+    ULONG ret;
 
-    ITfKeystrokeMgr_Release(keymgr);
-    ITfKeyEventSink_Release(sink);
+    ok (tmSinkRefCount == This->refCount,"ThreadMgrEventSink refcount off %i vs %i\n",This->refCount,tmSinkRefCount);
+    ret = InterlockedDecrement(&This->refCount);
+    if (ret == 0)
+        ThreadMgrEventSink_Destructor(This);
+    return ret;
 }
 
-static void test_Activate(void)
+static HRESULT WINAPI ThreadMgrEventSink_OnInitDocumentMgr(ITfThreadMgrEventSink *iface,
+ITfDocumentMgr *pdim)
 {
-    HRESULT hr;
+    sink_fire_ok(&test_OnInitDocumentMgr,"ThreadMgrEventSink_OnInitDocumentMgr");
+    return S_OK;
+}
 
-    hr = ITfInputProcessorProfiles_ActivateLanguageProfile(g_ipp,&CLSID_FakeService,gLangid,&CLSID_FakeService);
-    ok(SUCCEEDED(hr),"Failed to Activate text service\n");
+static HRESULT WINAPI ThreadMgrEventSink_OnUninitDocumentMgr(ITfThreadMgrEventSink *iface,
+ITfDocumentMgr *pdim)
+{
+    trace("\n");
+    return S_OK;
 }
 
-static inline int check_context_refcount(ITfContext *iface)
+static HRESULT WINAPI ThreadMgrEventSink_OnSetFocus(ITfThreadMgrEventSink *iface,
+ITfDocumentMgr *pdimFocus, ITfDocumentMgr *pdimPrevFocus)
 {
-    IUnknown_AddRef(iface);
-    return IUnknown_Release(iface);
+    sink_fire_ok(&test_OnSetFocus,"ThreadMgrEventSink_OnSetFocus");
+    if (test_CurrentFocus != FOCUS_IGNORE)
+        ok(pdimFocus == test_CurrentFocus,"Sink reports wrong focus\n");
+    if (test_PrevFocus != FOCUS_IGNORE)
+        ok(pdimPrevFocus == test_PrevFocus,"Sink reports wrong previous focus\n");
+    return S_OK;
 }
 
-static void test_startSession(void)
+static HRESULT WINAPI ThreadMgrEventSink_OnPushContext(ITfThreadMgrEventSink *iface,
+ITfContext *pic)
 {
     HRESULT hr;
-    DWORD cnt;
-    DWORD editCookie;
-    ITfDocumentMgr *dmtest;
-    ITfContext *cxt,*cxt2,*cxt3,*cxtTest;
-    ITextStoreACP *ts;
-    TfClientId cid2 = 0;
-
-    hr = ITfThreadMgr_Deactivate(g_tm);
-    ok(hr == E_UNEXPECTED,"Deactivate should have failed with E_UNEXPECTED\n");
-
-    test_ShouldActivate = TRUE;
-    hr  = ITfThreadMgr_Activate(g_tm,&cid);
-    ok(SUCCEEDED(hr),"Failed to Activate\n");
-    ok(cid != tid,"TextService id mistakenly matches Client id\n");
-
-    test_ShouldActivate = FALSE;
-    hr = ITfThreadMgr_Activate(g_tm,&cid2);
-    ok(SUCCEEDED(hr),"Failed to Activate\n");
-    ok (cid == cid2, "Second activate client ID does not match\n");
-
-    hr = ITfThreadMgr_Deactivate(g_tm);
-    ok(SUCCEEDED(hr),"Failed to Deactivate\n");
+    ITfDocumentMgr *docmgr;
+    ITfContext *test;
+
+    hr = ITfContext_GetDocumentMgr(pic,&docmgr);
+    ok(SUCCEEDED(hr),"GetDocumenMgr failed\n");
+    test = (ITfContext*)0xdeadbeef;
+    ITfDocumentMgr_Release(docmgr);
+    hr = ITfDocumentMgr_GetTop(docmgr,&test);
+    ok(SUCCEEDED(hr),"GetTop failed\n");
+    ok(test == pic, "Wrong context is on top\n");
+    if (test)
+        ITfContext_Release(test);
+
+    sink_fire_ok(&test_OnPushContext,"ThreadMgrEventSink_OnPushContext");
+    return S_OK;
+}
 
-    hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&g_dm);
-    ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n");
+static HRESULT WINAPI ThreadMgrEventSink_OnPopContext(ITfThreadMgrEventSink *iface,
+ITfContext *pic)
+{
+    HRESULT hr;
+    ITfDocumentMgr *docmgr;
+    ITfContext *test;
+
+    hr = ITfContext_GetDocumentMgr(pic,&docmgr);
+    ok(SUCCEEDED(hr),"GetDocumenMgr failed\n");
+    ITfDocumentMgr_Release(docmgr);
+    test = (ITfContext*)0xdeadbeef;
+    hr = ITfDocumentMgr_GetTop(docmgr,&test);
+    ok(SUCCEEDED(hr),"GetTop failed\n");
+    ok(test == pic, "Wrong context is on top\n");
+    if (test)
+        ITfContext_Release(test);
+
+    sink_fire_ok(&test_OnPopContext,"ThreadMgrEventSink_OnPopContext");
+    return S_OK;
+}
 
-    hr = ITfThreadMgr_GetFocus(g_tm,&dmtest);
-    ok(SUCCEEDED(hr),"GetFocus Failed\n");
-    ok(dmtest == NULL,"Initial focus not null\n");
+static const ITfThreadMgrEventSinkVtbl ThreadMgrEventSink_ThreadMgrEventSinkVtbl =
+{
+    ThreadMgrEventSink_QueryInterface,
+    ThreadMgrEventSink_AddRef,
+    ThreadMgrEventSink_Release,
 
-    test_CurrentFocus = g_dm;
-    test_PrevFocus = NULL;
-    test_OnSetFocus  = SINK_EXPECTED;
-    hr = ITfThreadMgr_SetFocus(g_tm,g_dm);
-    ok(SUCCEEDED(hr),"SetFocus Failed\n");
-    ok(test_OnSetFocus == SINK_FIRED, "OnSetFocus sink not called\n");
-    test_OnSetFocus  = SINK_UNEXPECTED;
+    ThreadMgrEventSink_OnInitDocumentMgr,
+    ThreadMgrEventSink_OnUninitDocumentMgr,
+    ThreadMgrEventSink_OnSetFocus,
+    ThreadMgrEventSink_OnPushContext,
+    ThreadMgrEventSink_OnPopContext
+};
 
-    hr = ITfThreadMgr_GetFocus(g_tm,&dmtest);
-    ok(SUCCEEDED(hr),"GetFocus Failed\n");
-    ok(g_dm == dmtest,"Expected DocumentMgr not focused\n");
+static HRESULT ThreadMgrEventSink_Constructor(IUnknown **ppOut)
+{
+    ThreadMgrEventSink *This;
 
-    cnt = ITfDocumentMgr_Release(g_dm);
-    ok(cnt == 2,"DocumentMgr refcount not expected (2 vs %i)\n",cnt);
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgrEventSink));
+    if (This == NULL)
+        return E_OUTOFMEMORY;
 
-    hr = ITfThreadMgr_GetFocus(g_tm,&dmtest);
-    ok(SUCCEEDED(hr),"GetFocus Failed\n");
-    ok(g_dm == dmtest,"Expected DocumentMgr not focused\n");
+    This->ThreadMgrEventSinkVtbl = &ThreadMgrEventSink_ThreadMgrEventSinkVtbl;
+    This->refCount = 1;
 
-    TextStoreACP_Constructor((IUnknown**)&ts);
+    *ppOut = (IUnknown *)This;
+    return S_OK;
+}
 
-    hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, (IUnknown*)ts, &cxt, &editCookie);
-    ok(SUCCEEDED(hr),"CreateContext Failed\n");
 
-    hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, NULL, &cxt2, &editCookie);
-    ok(SUCCEEDED(hr),"CreateContext Failed\n");
+/********************************************************************************************
+ * Stub text service for testing
+ ********************************************************************************************/
 
-    hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, NULL, &cxt3, &editCookie);
-    ok(SUCCEEDED(hr),"CreateContext Failed\n");
+static LONG TS_refCount;
+static IClassFactory *cf;
+static DWORD regid;
 
-    cnt = check_context_refcount(cxt);
-    test_OnPushContext = SINK_EXPECTED;
-    test_OnInitDocumentMgr = SINK_EXPECTED;
-    hr = ITfDocumentMgr_Push(g_dm, cxt);
-    ok(SUCCEEDED(hr),"Push Failed\n");
-    ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n");
-    ok(test_OnPushContext == SINK_FIRED, "OnPushContext sink not fired\n");
-    ok(test_OnInitDocumentMgr == SINK_FIRED, "OnInitDocumentMgr sink not fired\n");
+typedef HRESULT (*LPFNCONSTRUCTOR)(IUnknown *pUnkOuter, IUnknown **ppvOut);
 
-    hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest);
-    ok(SUCCEEDED(hr),"GetTop Failed\n");
-    ok(cxtTest == cxt, "Wrong context on top\n");
-    ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n");
-    cnt = ITfContext_Release(cxtTest);
+typedef struct tagClassFactory
+{
+    const IClassFactoryVtbl *vtbl;
+    LONG   ref;
+    LPFNCONSTRUCTOR ctor;
+} ClassFactory;
 
-    hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest);
-    ok(SUCCEEDED(hr),"GetBase Failed\n");
-    ok(cxtTest == cxt, "Wrong context on Base\n");
-    ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n");
-    ITfContext_Release(cxtTest);
+typedef struct tagTextService
+{
+    const ITfTextInputProcessorVtbl *TextInputProcessorVtbl;
+    LONG refCount;
+} TextService;
 
-    check_context_refcount(cxt2);
-    test_OnPushContext = SINK_EXPECTED;
-    hr = ITfDocumentMgr_Push(g_dm, cxt2);
-    ok(SUCCEEDED(hr),"Push Failed\n");
-    ok(test_OnPushContext == SINK_FIRED, "OnPushContext sink not fired\n");
+static void ClassFactory_Destructor(ClassFactory *This)
+{
+    HeapFree(GetProcessHeap(),0,This);
+    TS_refCount--;
+}
 
-    cnt = check_context_refcount(cxt2);
-    hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest);
-    ok(SUCCEEDED(hr),"GetTop Failed\n");
-    ok(cxtTest == cxt2, "Wrong context on top\n");
-    ok(check_context_refcount(cxt2) > cnt, "Ref count did not increase\n");
-    ITfContext_Release(cxtTest);
+static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppvOut)
+{
+    *ppvOut = NULL;
+    if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown))
+    {
+        IClassFactory_AddRef(iface);
+        *ppvOut = iface;
+        return S_OK;
+    }
 
-    cnt = check_context_refcount(cxt);
-    hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest);
-    ok(SUCCEEDED(hr),"GetBase Failed\n");
-    ok(cxtTest == cxt, "Wrong context on Base\n");
-    ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n");
-    ITfContext_Release(cxtTest);
+    return E_NOINTERFACE;
+}
 
-    cnt = check_context_refcount(cxt3);
-    hr = ITfDocumentMgr_Push(g_dm, cxt3);
-    ok(!SUCCEEDED(hr),"Push Succeeded\n");
-    ok(check_context_refcount(cxt3) == cnt, "Ref changed\n");
+static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
+{
+    ClassFactory *This = (ClassFactory *)iface;
+    return InterlockedIncrement(&This->ref);
+}
 
-    cnt = check_context_refcount(cxt2);
-    hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest);
-    ok(SUCCEEDED(hr),"GetTop Failed\n");
-    ok(cxtTest == cxt2, "Wrong context on top\n");
-    ok(check_context_refcount(cxt2) > cnt, "Ref count did not increase\n");
-    ITfContext_Release(cxtTest);
+static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
+{
+    ClassFactory *This = (ClassFactory *)iface;
+    ULONG ret = InterlockedDecrement(&This->ref);
 
-    cnt = check_context_refcount(cxt);
-    hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest);
-    ok(SUCCEEDED(hr),"GetBase Failed\n");
-    ok(cxtTest == cxt, "Wrong context on Base\n");
-    ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n");
-    ITfContext_Release(cxtTest);
+    if (ret == 0)
+        ClassFactory_Destructor(This);
+    return ret;
+}
 
-    cnt = check_context_refcount(cxt2);
-    test_OnPopContext = SINK_EXPECTED;
-    hr = ITfDocumentMgr_Pop(g_dm, 0);
-    ok(SUCCEEDED(hr),"Pop Failed\n");
-    ok(check_context_refcount(cxt2) < cnt, "Ref count did not decrease\n");
-    ok(test_OnPopContext == SINK_FIRED, "OnPopContext sink not fired\n");
+static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *punkOuter, REFIID iid, LPVOID *ppvOut)
+{
+    ClassFactory *This = (ClassFactory *)iface;
+    HRESULT ret;
+    IUnknown *obj;
 
-    hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest);
-    ok(SUCCEEDED(hr),"GetTop Failed\n");
-    ok(cxtTest == cxt, "Wrong context on top\n");
-    ITfContext_Release(cxtTest);
+    ret = This->ctor(punkOuter, &obj);
+    if (FAILED(ret))
+        return ret;
+    ret = IUnknown_QueryInterface(obj, iid, ppvOut);
+    IUnknown_Release(obj);
+    return ret;
+}
 
-    hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest);
-    ok(SUCCEEDED(hr),"GetBase Failed\n");
-    ok(cxtTest == cxt, "Wrong context on base\n");
-    ITfContext_Release(cxtTest);
+static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock)
+{
+    if(fLock)
+        InterlockedIncrement(&TS_refCount);
+    else
+        InterlockedDecrement(&TS_refCount);
 
-    hr = ITfDocumentMgr_Pop(g_dm, 0);
-    ok(!SUCCEEDED(hr),"Pop Succeeded\n");
+    return S_OK;
+}
 
-    hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest);
-    ok(SUCCEEDED(hr),"GetTop Failed\n");
-    ok(cxtTest == cxt, "Wrong context on top\n");
-    ITfContext_Release(cxtTest);
+static const IClassFactoryVtbl ClassFactoryVtbl = {
+    /* IUnknown */
+    ClassFactory_QueryInterface,
+    ClassFactory_AddRef,
+    ClassFactory_Release,
 
-    hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest);
-    ok(SUCCEEDED(hr),"GetBase Failed\n");
-    ok(cxtTest == cxt, "Wrong context on base\n");
-    ITfContext_Release(cxtTest);
+    /* IClassFactory*/
+    ClassFactory_CreateInstance,
+    ClassFactory_LockServer
+};
 
-    ITfContext_Release(cxt);
-    ITfContext_Release(cxt2);
-    ITfContext_Release(cxt3);
+static HRESULT ClassFactory_Constructor(LPFNCONSTRUCTOR ctor, LPVOID *ppvOut)
+{
+    ClassFactory *This = HeapAlloc(GetProcessHeap(),0,sizeof(ClassFactory));
+    This->vtbl = &ClassFactoryVtbl;
+    This->ref = 1;
+    This->ctor = ctor;
+    *ppvOut = (LPVOID)This;
+    TS_refCount++;
+    return S_OK;
 }
 
-static void test_endSession(void)
+static void TextService_Destructor(TextService *This)
 {
-    HRESULT hr;
-    test_ShouldDeactivate = TRUE;
-    test_CurrentFocus = NULL;
-    test_PrevFocus = g_dm;
-    test_OnSetFocus  = SINK_EXPECTED;
-    hr = ITfThreadMgr_Deactivate(g_tm);
-    ok(SUCCEEDED(hr),"Failed to Deactivate\n");
-    ok(test_OnSetFocus == SINK_FIRED, "OnSetFocus sink not called\n");
-    test_OnSetFocus  = SINK_UNEXPECTED;
+    HeapFree(GetProcessHeap(),0,This);
 }
 
-static void test_TfGuidAtom(void)
+static HRESULT WINAPI TextService_QueryInterface(ITfTextInputProcessor *iface, REFIID iid, LPVOID *ppvOut)
 {
-    GUID gtest,g1;
-    HRESULT hr;
-    TfGuidAtom atom1,atom2;
-    BOOL equal;
+    TextService *This = (TextService *)iface;
+    *ppvOut = NULL;
 
-    CoCreateGuid(&gtest);
+    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfTextInputProcessor))
+    {
+        *ppvOut = This;
+    }
 
-    /* msdn reports this should return E_INVALIDARG.  However my test show it crashing (winxp)*/
-    /*
-    hr = ITfCategoryMgr_RegisterGUID(g_cm,&gtest,NULL);
-    ok(hr==E_INVALIDARG,"ITfCategoryMgr_RegisterGUID should have failed\n");
-    */
-    hr = ITfCategoryMgr_RegisterGUID(g_cm,&gtest,&atom1);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterGUID failed\n");
-    hr = ITfCategoryMgr_RegisterGUID(g_cm,&gtest,&atom2);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterGUID failed\n");
-    ok(atom1 == atom2,"atoms do not match\n");
-    hr = ITfCategoryMgr_GetGUID(g_cm,atom2,NULL);
-    ok(hr==E_INVALIDARG,"ITfCategoryMgr_GetGUID should have failed\n");
-    hr = ITfCategoryMgr_GetGUID(g_cm,atom2,&g1);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_GetGUID failed\n");
-    ok(IsEqualGUID(&g1,&gtest),"guids do not match\n");
-    hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,atom1,&gtest,NULL);
-    ok(hr==E_INVALIDARG,"ITfCategoryMgr_IsEqualTfGuidAtom should have failed\n");
-    hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,atom1,&gtest,&equal);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_IsEqualTfGuidAtom failed\n");
-    ok(equal == TRUE,"Equal value invalid\n");
+    if (*ppvOut)
+    {
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
 
-    /* show that cid and tid TfClientIds are also TfGuidAtoms */
-    hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,tid,&CLSID_FakeService,&equal);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_IsEqualTfGuidAtom failed\n");
-    ok(equal == TRUE,"Equal value invalid\n");
-    hr = ITfCategoryMgr_GetGUID(g_cm,cid,&g1);
-    ok(SUCCEEDED(hr),"ITfCategoryMgr_GetGUID failed\n");
-    ok(!IsEqualGUID(&g1,&GUID_NULL),"guid should not be NULL\n");
+    return E_NOINTERFACE;
 }
 
-static void test_ClientId(void)
+static ULONG WINAPI TextService_AddRef(ITfTextInputProcessor *iface)
 {
-    ITfClientId *pcid;
-    TfClientId id1,id2;
-    HRESULT hr;
-    GUID g2;
-
-    hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfClientId, (LPVOID*)&pcid);
-    ok(SUCCEEDED(hr),"Unable to aquire ITfClientId interface\n");
+    TextService *This = (TextService *)iface;
+    return InterlockedIncrement(&This->refCount);
+}
 
-    CoCreateGuid(&g2);
+static ULONG WINAPI TextService_Release(ITfTextInputProcessor *iface)
+{
+    TextService *This = (TextService *)iface;
+    ULONG ret;
 
-    hr = ITfClientId_GetClientId(pcid,&GUID_NULL,&id1);
-    ok(SUCCEEDED(hr),"GetClientId failed\n");
-    hr = ITfClientId_GetClientId(pcid,&GUID_NULL,&id2);
-    ok(SUCCEEDED(hr),"GetClientId failed\n");
-    ok(id1==id2,"Id's for GUID_NULL do not match\n");
-    hr = ITfClientId_GetClientId(pcid,&CLSID_FakeService,&id2);
-    ok(SUCCEEDED(hr),"GetClientId failed\n");
-    ok(id2!=id1,"Id matches GUID_NULL\n");
-    ok(id2==tid,"Id for CLSID_FakeService not matching tid\n");
-    ok(id2!=cid,"Id for CLSID_FakeService matching cid\n");
-    hr = ITfClientId_GetClientId(pcid,&g2,&id2);
-    ok(SUCCEEDED(hr),"GetClientId failed\n");
-    ok(id2!=id1,"Id matches GUID_NULL\n");
-    ok(id2!=tid,"Id for random guid matching tid\n");
-    ok(id2!=cid,"Id for random guid matching cid\n");
-    ITfClientId_Release(pcid);
+    ret = InterlockedDecrement(&This->refCount);
+    if (ret == 0)
+        TextService_Destructor(This);
+    return ret;
 }
 
-START_TEST(inputprocessor)
+static HRESULT WINAPI TextService_Activate(ITfTextInputProcessor *iface,
+        ITfThreadMgr *ptim, TfClientId id)
 {
-    if (SUCCEEDED(initialize()))
-    {
-        test_Register();
-        test_RegisterCategory();
-        test_EnumInputProcessorInfo();
-        test_Enable();
-        test_ThreadMgrAdviseSinks();
-        test_Activate();
-        test_startSession();
-        test_TfGuidAtom();
-        test_ClientId();
-        test_KeystrokeMgr();
-        test_endSession();
-        test_EnumLanguageProfiles();
-        test_FindClosestCategory();
-        test_Disable();
-        test_ThreadMgrUnadviseSinks();
-        test_UnregisterCategory();
-        test_Unregister();
-    }
-    else
-        skip("Unable to create InputProcessor\n");
-    cleanup();
+    trace("TextService_Activate\n");
+    ok(test_ShouldActivate,"Activation came unexpectedly\n");
+    tid = id;
+    return S_OK;
 }
 
-/**********************************************************************
- * ITextStoreACP
- **********************************************************************/
-typedef struct tagTextStoreACP
+static HRESULT WINAPI TextService_Deactivate(ITfTextInputProcessor *iface)
 {
-    const ITextStoreACPVtbl *TextStoreACPVtbl;
-    LONG refCount;
-} TextStoreACP;
+    trace("TextService_Deactivate\n");
+    ok(test_ShouldDeactivate,"Deactivation came unexpectedly\n");
+    return S_OK;
+}
 
-static void TextStoreACP_Destructor(TextStoreACP *This)
+static const ITfTextInputProcessorVtbl TextService_TextInputProcessorVtbl=
 {
-    HeapFree(GetProcessHeap(),0,This);
-}
+    TextService_QueryInterface,
+    TextService_AddRef,
+    TextService_Release,
 
-static HRESULT WINAPI TextStoreACP_QueryInterface(ITextStoreACP *iface, REFIID iid, LPVOID *ppvOut)
+    TextService_Activate,
+    TextService_Deactivate
+};
+
+static HRESULT TextService_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
 {
-    TextStoreACP *This = (TextStoreACP *)iface;
-    *ppvOut = NULL;
+    TextService *This;
+    if (pUnkOuter)
+        return CLASS_E_NOAGGREGATION;
 
-    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACP))
-    {
-        *ppvOut = This;
-    }
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextService));
+    if (This == NULL)
+        return E_OUTOFMEMORY;
 
-    if (*ppvOut)
-    {
-        IUnknown_AddRef(iface);
-        return S_OK;
-    }
+    This->TextInputProcessorVtbl= &TextService_TextInputProcessorVtbl;
+    This->refCount = 1;
 
-    return E_NOINTERFACE;
+    *ppOut = (IUnknown *)This;
+    return S_OK;
 }
 
-static ULONG WINAPI TextStoreACP_AddRef(ITextStoreACP *iface)
+static HRESULT RegisterTextService(REFCLSID rclsid)
 {
-    TextStoreACP *This = (TextStoreACP *)iface;
-    return InterlockedIncrement(&This->refCount);
+    ClassFactory_Constructor( TextService_Constructor ,(LPVOID*)&cf);
+    return CoRegisterClassObject(rclsid, (IUnknown*) cf, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &regid);
 }
 
-static ULONG WINAPI TextStoreACP_Release(ITextStoreACP *iface)
+static HRESULT UnregisterTextService(void)
 {
-    TextStoreACP *This = (TextStoreACP *)iface;
-    ULONG ret;
-
-    ret = InterlockedDecrement(&This->refCount);
-    if (ret == 0)
-        TextStoreACP_Destructor(This);
-    return ret;
+    return CoRevokeClassObject(regid);
 }
 
-static HRESULT WINAPI TextStoreACP_AdviseSink(ITextStoreACP *iface,
-    REFIID riid, IUnknown *punk, DWORD dwMask)
+/*
+ * The tests
+ */
+
+DEFINE_GUID(CLSID_FakeService, 0xEDE1A7AD,0x66DE,0x47E0,0xB6,0x20,0x3E,0x92,0xF8,0x24,0x6B,0xF3);
+DEFINE_GUID(CLSID_TF_InputProcessorProfiles, 0x33c53a50,0xf456,0x4884,0xb0,0x49,0x85,0xfd,0x64,0x3e,0xcf,0xed);
+DEFINE_GUID(CLSID_TF_CategoryMgr,         0xA4B544A1,0x438D,0x4B41,0x93,0x25,0x86,0x95,0x23,0xE2,0xD6,0xC7);
+DEFINE_GUID(GUID_TFCAT_TIP_KEYBOARD,     0x34745c63,0xb2f0,0x4784,0x8b,0x67,0x5e,0x12,0xc8,0x70,0x1a,0x31);
+DEFINE_GUID(GUID_TFCAT_TIP_SPEECH,       0xB5A73CD1,0x8355,0x426B,0xA1,0x61,0x25,0x98,0x08,0xF2,0x6B,0x14);
+DEFINE_GUID(GUID_TFCAT_TIP_HANDWRITING,  0x246ecb87,0xc2f2,0x4abe,0x90,0x5b,0xc8,0xb3,0x8a,0xdd,0x2c,0x43);
+DEFINE_GUID (GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER,  0x046B8C80,0x1647,0x40F7,0x9B,0x21,0xB9,0x3B,0x81,0xAA,0xBC,0x1B);
+DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
+DEFINE_GUID(CLSID_TF_ThreadMgr,           0x529a9e6b,0x6587,0x4f23,0xab,0x9e,0x9c,0x7d,0x68,0x3e,0x3c,0x50);
+DEFINE_GUID(CLSID_PreservedKey,           0xA0ED8E55,0xCD3B,0x4274,0xB2,0x95,0xF6,0xC9,0xBA,0x2B,0x84,0x72);
+DEFINE_GUID(GUID_COMPARTMENT_KEYBOARD_DISABLED,     0x71a5b253,0x1951,0x466b,0x9f,0xbc,0x9c,0x88,0x08,0xfa,0x84,0xf2);
+DEFINE_GUID(GUID_COMPARTMENT_KEYBOARD_OPENCLOSE,    0x58273aad,0x01bb,0x4164,0x95,0xc6,0x75,0x5b,0xa0,0xb5,0x16,0x2d);
+DEFINE_GUID(GUID_COMPARTMENT_HANDWRITING_OPENCLOSE, 0xf9ae2c6b,0x1866,0x4361,0xaf,0x72,0x7a,0xa3,0x09,0x48,0x89,0x0e);
+DEFINE_GUID(GUID_COMPARTMENT_SPEECH_DISABLED,       0x56c5c607,0x0703,0x4e59,0x8e,0x52,0xcb,0xc8,0x4e,0x8b,0xbe,0x35);
+DEFINE_GUID(GUID_COMPARTMENT_SPEECH_OPENCLOSE,      0x544d6a63,0xe2e8,0x4752,0xbb,0xd1,0x00,0x09,0x60,0xbc,0xa0,0x83);
+DEFINE_GUID(GUID_COMPARTMENT_SPEECH_GLOBALSTATE,    0x2a54fe8e,0x0d08,0x460c,0xa7,0x5d,0x87,0x03,0x5f,0xf4,0x36,0xc5);
+DEFINE_GUID(GUID_COMPARTMENT_PERSISTMENUENABLED,    0x575f3783,0x70c8,0x47c8,0xae,0x5d,0x91,0xa0,0x1a,0x1f,0x75,0x92);
+DEFINE_GUID(GUID_COMPARTMENT_EMPTYCONTEXT,          0xd7487dbf,0x804e,0x41c5,0x89,0x4d,0xad,0x96,0xfd,0x4e,0xea,0x13);
+DEFINE_GUID(GUID_COMPARTMENT_TIPUISTATUS,           0x148ca3ec,0x0366,0x401c,0x8d,0x75,0xed,0x97,0x8d,0x85,0xfb,0xc9);
+
+static HRESULT initialize(void)
 {
-    trace("\n");
-    return S_OK;
+    HRESULT hr;
+    CoInitialize(NULL);
+    hr = CoCreateInstance (&CLSID_TF_InputProcessorProfiles, NULL,
+          CLSCTX_INPROC_SERVER, &IID_ITfInputProcessorProfiles, (void**)&g_ipp);
+    if (SUCCEEDED(hr))
+        hr = CoCreateInstance (&CLSID_TF_CategoryMgr, NULL,
+          CLSCTX_INPROC_SERVER, &IID_ITfCategoryMgr, (void**)&g_cm);
+    if (SUCCEEDED(hr))
+        hr = CoCreateInstance (&CLSID_TF_ThreadMgr, NULL,
+          CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, (void**)&g_tm);
+    return hr;
 }
 
-static HRESULT WINAPI TextStoreACP_UnadviseSink(ITextStoreACP *iface,
-    IUnknown *punk)
+static void cleanup(void)
 {
-    trace("\n");
-    return S_OK;
+    if (g_ipp)
+        ITfInputProcessorProfiles_Release(g_ipp);
+    if (g_cm)
+        ITfCategoryMgr_Release(g_cm);
+    if (g_tm)
+        ITfThreadMgr_Release(g_tm);
+    CoUninitialize();
 }
-static HRESULT WINAPI TextStoreACP_RequestLock(ITextStoreACP *iface,
-    DWORD dwLockFlags, HRESULT *phrSession)
+
+static void test_Register(void)
 {
-    trace("\n");
-    return S_OK;
+    HRESULT hr;
+
+    static const WCHAR szDesc[] = {'F','a','k','e',' ','W','i','n','e',' ','S','e','r','v','i','c','e',0};
+    static const WCHAR szFile[] = {'F','a','k','e',' ','W','i','n','e',' ','S','e','r','v','i','c','e',' ','F','i','l','e',0};
+
+    hr = ITfInputProcessorProfiles_GetCurrentLanguage(g_ipp,&gLangid);
+    ok(SUCCEEDED(hr),"Unable to get current language id\n");
+    trace("Current Language %x\n",gLangid);
+
+    hr = RegisterTextService(&CLSID_FakeService);
+    ok(SUCCEEDED(hr),"Unable to register COM for TextService\n");
+    hr = ITfInputProcessorProfiles_Register(g_ipp, &CLSID_FakeService);
+    ok(SUCCEEDED(hr),"Unable to register text service(%x)\n",hr);
+    hr = ITfInputProcessorProfiles_AddLanguageProfile(g_ipp, &CLSID_FakeService, gLangid, &CLSID_FakeService, szDesc, sizeof(szDesc)/sizeof(WCHAR), szFile, sizeof(szFile)/sizeof(WCHAR), 1);
+    ok(SUCCEEDED(hr),"Unable to add Language Profile (%x)\n",hr);
 }
-static HRESULT WINAPI TextStoreACP_GetStatus(ITextStoreACP *iface,
-    TS_STATUS *pdcs)
+
+static void test_Unregister(void)
 {
-    trace("\n");
-    return S_OK;
+    HRESULT hr;
+    hr = ITfInputProcessorProfiles_Unregister(g_ipp, &CLSID_FakeService);
+    ok(SUCCEEDED(hr),"Unable to unregister text service(%x)\n",hr);
+    UnregisterTextService();
 }
-static HRESULT WINAPI TextStoreACP_QueryInsert(ITextStoreACP *iface,
-    LONG acpTestStart, LONG acpTestEnd, ULONG cch, LONG *pacpResultStart,
-    LONG *pacpResultEnd)
+
+static void test_EnumInputProcessorInfo(void)
 {
-    trace("\n");
-    return S_OK;
+    IEnumGUID *ppEnum;
+    BOOL found = FALSE;
+
+    if (SUCCEEDED(ITfInputProcessorProfiles_EnumInputProcessorInfo(g_ipp, &ppEnum)))
+    {
+        ULONG fetched;
+        GUID g;
+        while (IEnumGUID_Next(ppEnum, 1, &g, &fetched) == S_OK)
+        {
+            if(IsEqualGUID(&g,&CLSID_FakeService))
+                found = TRUE;
+        }
+    }
+    ok(found,"Did not find registered text service\n");
 }
-static HRESULT WINAPI TextStoreACP_GetSelection(ITextStoreACP *iface,
-    ULONG ulIndex, ULONG ulCount, TS_SELECTION_ACP *pSelection, ULONG *pcFetched)
+
+static void test_EnumLanguageProfiles(void)
 {
-    trace("\n");
-    return S_OK;
+    BOOL found = FALSE;
+    IEnumTfLanguageProfiles *ppEnum;
+    if (SUCCEEDED(ITfInputProcessorProfiles_EnumLanguageProfiles(g_ipp,gLangid,&ppEnum)))
+    {
+        TF_LANGUAGEPROFILE profile;
+        while (IEnumTfLanguageProfiles_Next(ppEnum,1,&profile,NULL)==S_OK)
+        {
+            if (IsEqualGUID(&profile.clsid,&CLSID_FakeService))
+            {
+                found = TRUE;
+                ok(profile.langid == gLangid, "LangId Incorrect\n");
+                ok(IsEqualGUID(&profile.catid,&GUID_TFCAT_TIP_KEYBOARD), "CatId Incorrect\n");
+                ok(IsEqualGUID(&profile.guidProfile,&CLSID_FakeService), "guidProfile Incorrect\n");
+            }
+        }
+    }
+    ok(found,"Registered text service not found\n");
 }
-static HRESULT WINAPI TextStoreACP_SetSelection(ITextStoreACP *iface,
-    ULONG ulCount, const TS_SELECTION_ACP *pSelection)
+
+static void test_RegisterCategory(void)
 {
-    trace("\n");
-    return S_OK;
+    HRESULT hr;
+    hr = ITfCategoryMgr_RegisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_TIP_KEYBOARD, &CLSID_FakeService);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterCategory failed\n");
+    hr = ITfCategoryMgr_RegisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &CLSID_FakeService);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterCategory failed\n");
 }
-static HRESULT WINAPI TextStoreACP_GetText(ITextStoreACP *iface,
-    LONG acpStart, LONG acpEnd, WCHAR *pchPlain, ULONG cchPlainReq,
-    ULONG *pcchPlainRet, TS_RUNINFO *prgRunInfo, ULONG cRunInfoReq,
-    ULONG *pcRunInfoRet, LONG *pacpNext)
+
+static void test_UnregisterCategory(void)
 {
-    trace("\n");
-    return S_OK;
+    HRESULT hr;
+    hr = ITfCategoryMgr_UnregisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_TIP_KEYBOARD, &CLSID_FakeService);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_UnregisterCategory failed\n");
+    hr = ITfCategoryMgr_UnregisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &CLSID_FakeService);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_UnregisterCategory failed\n");
 }
-static HRESULT WINAPI TextStoreACP_SetText(ITextStoreACP *iface,
-    DWORD dwFlags, LONG acpStart, LONG acpEnd, const WCHAR *pchText,
-    ULONG cch, TS_TEXTCHANGE *pChange)
+
+static void test_FindClosestCategory(void)
 {
-    trace("\n");
-    return S_OK;
+    GUID output;
+    HRESULT hr;
+    const GUID *list[3] = {&GUID_TFCAT_TIP_SPEECH, &GUID_TFCAT_TIP_KEYBOARD, &GUID_TFCAT_TIP_HANDWRITING};
+
+    hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, NULL, 0);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr);
+    ok(IsEqualGUID(&output,&GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER),"Wrong GUID\n");
+
+    hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, list, 1);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr);
+    ok(IsEqualGUID(&output,&GUID_NULL),"Wrong GUID\n");
+
+    hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, list, 3);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr);
+    ok(IsEqualGUID(&output,&GUID_TFCAT_TIP_KEYBOARD),"Wrong GUID\n");
 }
-static HRESULT WINAPI TextStoreACP_GetFormattedText(ITextStoreACP *iface,
-    LONG acpStart, LONG acpEnd, IDataObject **ppDataObject)
+
+static void test_Enable(void)
 {
-    trace("\n");
-    return S_OK;
+    HRESULT hr;
+    BOOL enabled = FALSE;
+
+    hr = ITfInputProcessorProfiles_EnableLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, TRUE);
+    ok(SUCCEEDED(hr),"Failed to enable text service\n");
+    hr = ITfInputProcessorProfiles_IsEnabledLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, &enabled);
+    ok(SUCCEEDED(hr),"Failed to get enabled state\n");
+    ok(enabled == TRUE,"enabled state incorrect\n");
 }
-static HRESULT WINAPI TextStoreACP_GetEmbedded(ITextStoreACP *iface,
-    LONG acpPos, REFGUID rguidService, REFIID riid, IUnknown **ppunk)
+
+static void test_Disable(void)
 {
-    trace("\n");
-    return S_OK;
+    HRESULT hr;
+
+    trace("Disabling\n");
+    hr = ITfInputProcessorProfiles_EnableLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, FALSE);
+    ok(SUCCEEDED(hr),"Failed to disable text service\n");
 }
-static HRESULT WINAPI TextStoreACP_QueryInsertEmbedded(ITextStoreACP *iface,
-    const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable)
+
+static void test_ThreadMgrAdviseSinks(void)
 {
-    trace("\n");
-    return S_OK;
+    ITfSource *source = NULL;
+    HRESULT hr;
+    IUnknown *sink;
+
+    hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfSource, (LPVOID*)&source);
+    ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for ThreadMgr\n");
+    if (!source)
+        return;
+
+    hr = ThreadMgrEventSink_Constructor(&sink);
+    ok(hr == S_OK, "got %08x\n", hr);
+    if(FAILED(hr)) return;
+
+    tmSinkRefCount = 1;
+    tmSinkCookie = 0;
+    hr = ITfSource_AdviseSink(source,&IID_ITfThreadMgrEventSink, sink, &tmSinkCookie);
+    ok(SUCCEEDED(hr),"Failed to Advise Sink\n");
+    ok(tmSinkCookie!=0,"Failed to get sink cookie\n");
+
+    /* Advising the sink adds a ref, Relesing here lets the object be deleted
+       when unadvised */
+    tmSinkRefCount = 2;
+    IUnknown_Release(sink);
+    ITfSource_Release(source);
 }
-static HRESULT WINAPI TextStoreACP_InsertEmbedded(ITextStoreACP *iface,
-    DWORD dwFlags, LONG acpStart, LONG acpEnd, IDataObject *pDataObject,
-    TS_TEXTCHANGE *pChange)
+
+static void test_ThreadMgrUnadviseSinks(void)
 {
-    trace("\n");
-    return S_OK;
+    ITfSource *source = NULL;
+    HRESULT hr;
+
+    hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfSource, (LPVOID*)&source);
+    ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for ThreadMgr\n");
+    if (!source)
+        return;
+
+    tmSinkRefCount = 1;
+    hr = ITfSource_UnadviseSink(source, tmSinkCookie);
+    ok(SUCCEEDED(hr),"Failed to unadvise Sink\n");
+    ITfSource_Release(source);
 }
-static HRESULT WINAPI TextStoreACP_InsertTextAtSelection(ITextStoreACP *iface,
-    DWORD dwFlags, const WCHAR *pchText, ULONG cch, LONG *pacpStart,
-    LONG *pacpEnd, TS_TEXTCHANGE *pChange)
+
+/**********************************************************************
+ * ITfKeyEventSink
+ **********************************************************************/
+typedef struct tagKeyEventSink
 {
-    trace("\n");
-    return S_OK;
-}
-static HRESULT WINAPI TextStoreACP_InsertEmbeddedAtSelection(ITextStoreACP *iface,
-    DWORD dwFlags, IDataObject *pDataObject, LONG *pacpStart, LONG *pacpEnd,
-    TS_TEXTCHANGE *pChange)
+    const ITfKeyEventSinkVtbl *KeyEventSinkVtbl;
+    LONG refCount;
+} KeyEventSink;
+
+static void KeyEventSink_Destructor(KeyEventSink *This)
 {
-    trace("\n");
-    return S_OK;
+    HeapFree(GetProcessHeap(),0,This);
 }
-static HRESULT WINAPI TextStoreACP_RequestSupportedAttrs(ITextStoreACP *iface,
-    DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs)
+
+static HRESULT WINAPI KeyEventSink_QueryInterface(ITfKeyEventSink *iface, REFIID iid, LPVOID *ppvOut)
 {
-    trace("\n");
-    return S_OK;
+    KeyEventSink *This = (KeyEventSink *)iface;
+    *ppvOut = NULL;
+
+    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfKeyEventSink))
+    {
+        *ppvOut = This;
+    }
+
+    if (*ppvOut)
+    {
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
 }
-static HRESULT WINAPI TextStoreACP_RequestAttrsAtPosition(ITextStoreACP *iface,
-    LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs,
-    DWORD dwFlags)
+
+static ULONG WINAPI KeyEventSink_AddRef(ITfKeyEventSink *iface)
 {
-    trace("\n");
-    return S_OK;
+    KeyEventSink *This = (KeyEventSink *)iface;
+    return InterlockedIncrement(&This->refCount);
 }
-static HRESULT WINAPI TextStoreACP_RequestAttrsTransitioningAtPosition(ITextStoreACP *iface,
-    LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs,
-    DWORD dwFlags)
+
+static ULONG WINAPI KeyEventSink_Release(ITfKeyEventSink *iface)
 {
-    trace("\n");
-    return S_OK;
+    KeyEventSink *This = (KeyEventSink *)iface;
+    ULONG ret;
+
+    ret = InterlockedDecrement(&This->refCount);
+    if (ret == 0)
+        KeyEventSink_Destructor(This);
+    return ret;
 }
-static HRESULT WINAPI TextStoreACP_FindNextAttrTransition(ITextStoreACP *iface,
-    LONG acpStart, LONG acpHalt, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs,
-    DWORD dwFlags, LONG *pacpNext, BOOL *pfFound, LONG *plFoundOffset)
+
+static HRESULT WINAPI KeyEventSink_OnSetFocus(ITfKeyEventSink *iface,
+        BOOL fForeground)
 {
-    trace("\n");
+    sink_fire_ok(&test_KEV_OnSetFocus,"KeyEventSink_OnSetFocus");
     return S_OK;
 }
-static HRESULT WINAPI TextStoreACP_RetrieveRequestedAttrs(ITextStoreACP *iface,
-    ULONG ulCount, TS_ATTRVAL *paAttrVals, ULONG *pcFetched)
+
+static HRESULT WINAPI KeyEventSink_OnTestKeyDown(ITfKeyEventSink *iface,
+        ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
 {
     trace("\n");
     return S_OK;
 }
-static HRESULT WINAPI TextStoreACP_GetEndACP(ITextStoreACP *iface,
-    LONG *pacp)
+
+static HRESULT WINAPI KeyEventSink_OnTestKeyUp(ITfKeyEventSink *iface,
+        ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
 {
     trace("\n");
     return S_OK;
 }
-static HRESULT WINAPI TextStoreACP_GetActiveView(ITextStoreACP *iface,
-    TsViewCookie *pvcView)
+
+static HRESULT WINAPI KeyEventSink_OnKeyDown(ITfKeyEventSink *iface,
+        ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
 {
     trace("\n");
     return S_OK;
 }
-static HRESULT WINAPI TextStoreACP_GetACPFromPoint(ITextStoreACP *iface,
-    TsViewCookie vcView, const POINT *ptScreen, DWORD dwFlags,
-    LONG *pacp)
+
+static HRESULT WINAPI KeyEventSink_OnKeyUp(ITfKeyEventSink *iface,
+        ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
 {
     trace("\n");
     return S_OK;
 }
-static HRESULT WINAPI TextStoreACP_GetTextExt(ITextStoreACP *iface,
-    TsViewCookie vcView, LONG acpStart, LONG acpEnd, RECT *prc,
-    BOOL *pfClipped)
+
+static HRESULT WINAPI KeyEventSink_OnPreservedKey(ITfKeyEventSink *iface,
+    ITfContext *pic, REFGUID rguid, BOOL *pfEaten)
 {
     trace("\n");
     return S_OK;
 }
-static HRESULT WINAPI TextStoreACP_GetScreenExt(ITextStoreACP *iface,
-    TsViewCookie vcView, RECT *prc)
+
+static const ITfKeyEventSinkVtbl KeyEventSink_KeyEventSinkVtbl =
 {
-    trace("\n");
+    KeyEventSink_QueryInterface,
+    KeyEventSink_AddRef,
+    KeyEventSink_Release,
+
+    KeyEventSink_OnSetFocus,
+    KeyEventSink_OnTestKeyDown,
+    KeyEventSink_OnTestKeyUp,
+    KeyEventSink_OnKeyDown,
+    KeyEventSink_OnKeyUp,
+    KeyEventSink_OnPreservedKey
+};
+
+static HRESULT KeyEventSink_Constructor(ITfKeyEventSink **ppOut)
+{
+    KeyEventSink *This;
+
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(KeyEventSink));
+    if (This == NULL)
+        return E_OUTOFMEMORY;
+
+    This->KeyEventSinkVtbl = &KeyEventSink_KeyEventSinkVtbl;
+    This->refCount = 1;
+
+    *ppOut = (ITfKeyEventSink*)This;
     return S_OK;
 }
-static HRESULT WINAPI TextStoreACP_GetWnd(ITextStoreACP *iface,
-    TsViewCookie vcView, HWND *phwnd)
+
+
+static void test_KeystrokeMgr(void)
 {
-    trace("\n");
-    return S_OK;
+    ITfKeystrokeMgr *keymgr= NULL;
+    HRESULT hr;
+    TF_PRESERVEDKEY tfpk;
+    BOOL preserved;
+    ITfKeyEventSink *sink = NULL;
+
+    KeyEventSink_Constructor(&sink);
+
+    hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfKeystrokeMgr, (LPVOID*)&keymgr);
+    ok(SUCCEEDED(hr),"Failed to get IID_ITfKeystrokeMgr for ThreadMgr\n");
+
+    tfpk.uVKey = 'A';
+    tfpk.uModifiers = TF_MOD_SHIFT;
+
+    test_KEV_OnSetFocus = SINK_EXPECTED;
+    hr = ITfKeystrokeMgr_AdviseKeyEventSink(keymgr,tid,sink,TRUE);
+    ok(SUCCEEDED(hr),"ITfKeystrokeMgr_AdviseKeyEventSink failed\n");
+    sink_check_ok(&test_KEV_OnSetFocus,"KeyEventSink_OnSetFocus");
+    hr = ITfKeystrokeMgr_AdviseKeyEventSink(keymgr,tid,sink,TRUE);
+    ok(hr == CONNECT_E_ADVISELIMIT,"Wrong return, expected CONNECT_E_ADVISELIMIT\n");
+    hr = ITfKeystrokeMgr_AdviseKeyEventSink(keymgr,cid,sink,TRUE);
+    ok(hr == E_INVALIDARG,"Wrong return, expected E_INVALIDARG\n");
+
+    hr =ITfKeystrokeMgr_PreserveKey(keymgr, 0, &CLSID_PreservedKey, &tfpk, NULL, 0);
+    ok(hr==E_INVALIDARG,"ITfKeystrokeMgr_PreserveKey inproperly succeeded\n");
+
+    hr =ITfKeystrokeMgr_PreserveKey(keymgr, tid, &CLSID_PreservedKey, &tfpk, NULL, 0);
+    ok(SUCCEEDED(hr),"ITfKeystrokeMgr_PreserveKey failed\n");
+
+    hr =ITfKeystrokeMgr_PreserveKey(keymgr, tid, &CLSID_PreservedKey, &tfpk, NULL, 0);
+    ok(hr == TF_E_ALREADY_EXISTS,"ITfKeystrokeMgr_PreserveKey inproperly succeeded\n");
+
+    preserved = FALSE;
+    hr = ITfKeystrokeMgr_IsPreservedKey(keymgr, &CLSID_PreservedKey, &tfpk, &preserved);
+    ok(hr == S_OK, "ITfKeystrokeMgr_IsPreservedKey failed\n");
+    if (hr == S_OK) ok(preserved == TRUE,"misreporting preserved key\n");
+
+    hr = ITfKeystrokeMgr_UnpreserveKey(keymgr, &CLSID_PreservedKey,&tfpk);
+    ok(SUCCEEDED(hr),"ITfKeystrokeMgr_UnpreserveKey failed\n");
+
+    hr = ITfKeystrokeMgr_IsPreservedKey(keymgr, &CLSID_PreservedKey, &tfpk, &preserved);
+    ok(hr == S_FALSE, "ITfKeystrokeMgr_IsPreservedKey failed\n");
+    if (hr == S_FALSE) ok(preserved == FALSE,"misreporting preserved key\n");
+
+    hr = ITfKeystrokeMgr_UnpreserveKey(keymgr, &CLSID_PreservedKey,&tfpk);
+    ok(hr==CONNECT_E_NOCONNECTION,"ITfKeystrokeMgr_UnpreserveKey inproperly succeeded\n");
+
+    hr = ITfKeystrokeMgr_UnadviseKeyEventSink(keymgr,tid);
+    ok(SUCCEEDED(hr),"ITfKeystrokeMgr_UnadviseKeyEventSink failed\n");
+
+    ITfKeystrokeMgr_Release(keymgr);
+    ITfKeyEventSink_Release(sink);
 }
 
-static const ITextStoreACPVtbl TextStoreACP_TextStoreACPVtbl =
+static void test_Activate(void)
 {
-    TextStoreACP_QueryInterface,
-    TextStoreACP_AddRef,
-    TextStoreACP_Release,
+    HRESULT hr;
 
-    TextStoreACP_AdviseSink,
-    TextStoreACP_UnadviseSink,
-    TextStoreACP_RequestLock,
-    TextStoreACP_GetStatus,
-    TextStoreACP_QueryInsert,
-    TextStoreACP_GetSelection,
-    TextStoreACP_SetSelection,
-    TextStoreACP_GetText,
-    TextStoreACP_SetText,
-    TextStoreACP_GetFormattedText,
-    TextStoreACP_GetEmbedded,
-    TextStoreACP_QueryInsertEmbedded,
-    TextStoreACP_InsertEmbedded,
-    TextStoreACP_InsertTextAtSelection,
-    TextStoreACP_InsertEmbeddedAtSelection,
-    TextStoreACP_RequestSupportedAttrs,
-    TextStoreACP_RequestAttrsAtPosition,
-    TextStoreACP_RequestAttrsTransitioningAtPosition,
-    TextStoreACP_FindNextAttrTransition,
-    TextStoreACP_RetrieveRequestedAttrs,
-    TextStoreACP_GetEndACP,
-    TextStoreACP_GetActiveView,
-    TextStoreACP_GetACPFromPoint,
-    TextStoreACP_GetTextExt,
-    TextStoreACP_GetScreenExt,
-    TextStoreACP_GetWnd
-};
+    hr = ITfInputProcessorProfiles_ActivateLanguageProfile(g_ipp,&CLSID_FakeService,gLangid,&CLSID_FakeService);
+    ok(SUCCEEDED(hr),"Failed to Activate text service\n");
+}
 
-HRESULT TextStoreACP_Constructor(IUnknown **ppOut)
+
+static void test_EnumContexts(ITfDocumentMgr *dm, ITfContext *search)
 {
-    TextStoreACP *This;
+    HRESULT hr;
+    IEnumTfContexts* pEnum;
+    BOOL found = FALSE;
 
-    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextStoreACP));
-    if (This == NULL)
-        return E_OUTOFMEMORY;
+    hr = ITfDocumentMgr_EnumContexts(dm,&pEnum);
+    ok(SUCCEEDED(hr),"EnumContexts failed\n");
+    if (SUCCEEDED(hr))
+    {
+        ULONG fetched;
+        ITfContext *cxt;
+        while (IEnumTfContexts_Next(pEnum, 1, &cxt, &fetched) == S_OK)
+        {
+            if (!search)
+                found = TRUE;
+            else if (search == cxt)
+                found = TRUE;
+            ITfContext_Release(cxt);
+        }
+        IEnumTfContexts_Release(pEnum);
+    }
+    if (search)
+        ok(found,"Did not find proper ITfContext\n");
+    else
+        ok(!found,"Found an ITfContext we should should not have\n");
+}
+
+static void test_EnumDocumentMgr(ITfThreadMgr *tm, ITfDocumentMgr *search, ITfDocumentMgr *absent)
+{
+    HRESULT hr;
+    IEnumTfDocumentMgrs* pEnum;
+    BOOL found = FALSE;
+    BOOL notfound = TRUE;
 
-    This->TextStoreACPVtbl = &TextStoreACP_TextStoreACPVtbl;
-    This->refCount = 1;
+    hr = ITfThreadMgr_EnumDocumentMgrs(tm,&pEnum);
+    ok(SUCCEEDED(hr),"EnumDocumentMgrs failed\n");
+    if (SUCCEEDED(hr))
+    {
+        ULONG fetched;
+        ITfDocumentMgr *dm;
+        while (IEnumTfDocumentMgrs_Next(pEnum, 1, &dm, &fetched) == S_OK)
+        {
+            if (!search)
+                found = TRUE;
+            else if (search == dm)
+                found = TRUE;
+            if (absent && dm == absent)
+                notfound = FALSE;
+            ITfDocumentMgr_Release(dm);
+        }
+        IEnumTfDocumentMgrs_Release(pEnum);
+    }
+    if (search)
+        ok(found,"Did not find proper ITfDocumentMgr\n");
+    else
+        ok(!found,"Found an ITfDocumentMgr we should should not have\n");
+    if (absent)
+        ok(notfound,"Found an ITfDocumentMgr we believe should be absent\n");
+}
 
-    *ppOut = (IUnknown *)This;
-    return S_OK;
+static inline int check_context_refcount(ITfContext *iface)
+{
+    IUnknown_AddRef(iface);
+    return IUnknown_Release(iface);
 }
 
+
 /**********************************************************************
- * ITfThreadMgrEventSink
+ * ITfTextEditSink
  **********************************************************************/
-typedef struct tagThreadMgrEventSink
+typedef struct tagTextEditSink
 {
-    const ITfThreadMgrEventSinkVtbl *ThreadMgrEventSinkVtbl;
+    const ITfTextEditSinkVtbl *TextEditSinkVtbl;
     LONG refCount;
-} ThreadMgrEventSink;
+} TextEditSink;
 
-static void ThreadMgrEventSink_Destructor(ThreadMgrEventSink *This)
+static void TextEditSink_Destructor(TextEditSink *This)
 {
     HeapFree(GetProcessHeap(),0,This);
 }
 
-static HRESULT WINAPI ThreadMgrEventSink_QueryInterface(ITfThreadMgrEventSink *iface, REFIID iid, LPVOID *ppvOut)
+static HRESULT WINAPI TextEditSink_QueryInterface(ITfTextEditSink *iface, REFIID iid, LPVOID *ppvOut)
 {
-    ThreadMgrEventSink *This = (ThreadMgrEventSink *)iface;
+    TextEditSink *This = (TextEditSink *)iface;
     *ppvOut = NULL;
 
-    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfThreadMgrEventSink))
+    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfTextEditSink))
     {
         *ppvOut = This;
     }
@@ -1022,290 +1281,822 @@ static HRESULT WINAPI ThreadMgrEventSink_QueryInterface(ITfThreadMgrEventSink *i
     return E_NOINTERFACE;
 }
 
-static ULONG WINAPI ThreadMgrEventSink_AddRef(ITfThreadMgrEventSink *iface)
+static ULONG WINAPI TextEditSink_AddRef(ITfTextEditSink *iface)
 {
-    ThreadMgrEventSink *This = (ThreadMgrEventSink *)iface;
-    ok (tmSinkRefCount == This->refCount,"ThreadMgrEventSink refcount off %i vs %i\n",This->refCount,tmSinkRefCount);
+    TextEditSink *This = (TextEditSink *)iface;
     return InterlockedIncrement(&This->refCount);
 }
 
-static ULONG WINAPI ThreadMgrEventSink_Release(ITfThreadMgrEventSink *iface)
+static ULONG WINAPI TextEditSink_Release(ITfTextEditSink *iface)
 {
-    ThreadMgrEventSink *This = (ThreadMgrEventSink *)iface;
+    TextEditSink *This = (TextEditSink *)iface;
     ULONG ret;
 
-    ok (tmSinkRefCount == This->refCount,"ThreadMgrEventSink refcount off %i vs %i\n",This->refCount,tmSinkRefCount);
     ret = InterlockedDecrement(&This->refCount);
     if (ret == 0)
-        ThreadMgrEventSink_Destructor(This);
+        TextEditSink_Destructor(This);
     return ret;
 }
 
-static HRESULT WINAPI ThreadMgrEventSink_OnInitDocumentMgr(ITfThreadMgrEventSink *iface,
-ITfDocumentMgr *pdim)
+static HRESULT WINAPI TextEditSink_OnEndEdit(ITfTextEditSink *iface,
+    ITfContext *pic, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord)
 {
-    ok(test_OnInitDocumentMgr == SINK_EXPECTED, "Unexpected OnInitDocumentMgr sink\n");
-    test_OnInitDocumentMgr = SINK_FIRED;
+    sink_fire_ok(&test_OnEndEdit,"TextEditSink_OnEndEdit");
     return S_OK;
 }
 
-static HRESULT WINAPI ThreadMgrEventSink_OnUninitDocumentMgr(ITfThreadMgrEventSink *iface,
-ITfDocumentMgr *pdim)
+static const ITfTextEditSinkVtbl TextEditSink_TextEditSinkVtbl =
 {
-    trace("\n");
-    return S_OK;
-}
+    TextEditSink_QueryInterface,
+    TextEditSink_AddRef,
+    TextEditSink_Release,
 
-static HRESULT WINAPI ThreadMgrEventSink_OnSetFocus(ITfThreadMgrEventSink *iface,
-ITfDocumentMgr *pdimFocus, ITfDocumentMgr *pdimPrevFocus)
+    TextEditSink_OnEndEdit
+};
+
+static HRESULT TextEditSink_Constructor(ITfTextEditSink **ppOut)
 {
-    ok(test_OnSetFocus == SINK_EXPECTED, "Unexpected OnSetFocus sink\n");
-    ok(pdimFocus == test_CurrentFocus,"Sink reports wrong focus\n");
-    ok(pdimPrevFocus == test_PrevFocus,"Sink reports wrong previous focus\n");
-    test_OnSetFocus = SINK_FIRED;
+    TextEditSink *This;
+
+    *ppOut = NULL;
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextEditSink));
+    if (This == NULL)
+        return E_OUTOFMEMORY;
+
+    This->TextEditSinkVtbl = &TextEditSink_TextEditSinkVtbl;
+    This->refCount = 1;
+
+    *ppOut = (ITfTextEditSink*)This;
     return S_OK;
 }
 
-static HRESULT WINAPI ThreadMgrEventSink_OnPushContext(ITfThreadMgrEventSink *iface,
-ITfContext *pic)
+static void test_startSession(void)
 {
-    ok(test_OnPushContext == SINK_EXPECTED, "Unexpected OnPushContext sink\n");
-    test_OnPushContext = SINK_FIRED;
-    return S_OK;
+    HRESULT hr;
+    DWORD cnt;
+    DWORD editCookie;
+    ITfDocumentMgr *dmtest;
+    ITfContext *cxt,*cxt2,*cxt3,*cxtTest;
+    ITextStoreACP *ts;
+    TfClientId cid2 = 0;
+
+    hr = ITfThreadMgr_Deactivate(g_tm);
+    ok(hr == E_UNEXPECTED,"Deactivate should have failed with E_UNEXPECTED\n");
+
+    test_ShouldActivate = TRUE;
+    hr  = ITfThreadMgr_Activate(g_tm,&cid);
+    ok(SUCCEEDED(hr),"Failed to Activate\n");
+    ok(cid != tid,"TextService id mistakenly matches Client id\n");
+
+    test_ShouldActivate = FALSE;
+    hr = ITfThreadMgr_Activate(g_tm,&cid2);
+    ok(SUCCEEDED(hr),"Failed to Activate\n");
+    ok (cid == cid2, "Second activate client ID does not match\n");
+
+    hr = ITfThreadMgr_Deactivate(g_tm);
+    ok(SUCCEEDED(hr),"Failed to Deactivate\n");
+
+    test_EnumDocumentMgr(g_tm,NULL,NULL);
+
+    hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&g_dm);
+    ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n");
+
+    test_EnumDocumentMgr(g_tm,g_dm,NULL);
+
+    hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&dmtest);
+    ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n");
+
+    test_EnumDocumentMgr(g_tm,dmtest,NULL);
+
+    ITfDocumentMgr_Release(dmtest);
+    test_EnumDocumentMgr(g_tm,g_dm,dmtest);
+
+    hr = ITfThreadMgr_GetFocus(g_tm,&dmtest);
+    ok(SUCCEEDED(hr),"GetFocus Failed\n");
+    ok(dmtest == NULL,"Initial focus not null\n");
+
+    test_CurrentFocus = g_dm;
+    test_PrevFocus = NULL;
+    test_OnSetFocus  = SINK_EXPECTED;
+    hr = ITfThreadMgr_SetFocus(g_tm,g_dm);
+    ok(SUCCEEDED(hr),"SetFocus Failed\n");
+    sink_check_ok(&test_OnSetFocus,"OnSetFocus");
+
+    hr = ITfThreadMgr_GetFocus(g_tm,&dmtest);
+    ok(SUCCEEDED(hr),"GetFocus Failed\n");
+    ok(g_dm == dmtest,"Expected DocumentMgr not focused\n");
+
+    cnt = ITfDocumentMgr_Release(g_dm);
+    ok(cnt == 2,"DocumentMgr refcount not expected (2 vs %i)\n",cnt);
+
+    hr = ITfThreadMgr_GetFocus(g_tm,&dmtest);
+    ok(SUCCEEDED(hr),"GetFocus Failed\n");
+    ok(g_dm == dmtest,"Expected DocumentMgr not focused\n");
+    ITfDocumentMgr_Release(dmtest);
+
+    TextStoreACP_Constructor((IUnknown**)&ts);
+
+    hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, (IUnknown*)ts, &cxt, &editCookie);
+    ok(SUCCEEDED(hr),"CreateContext Failed\n");
+
+    hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, NULL, &cxt2, &editCookie);
+    ok(SUCCEEDED(hr),"CreateContext Failed\n");
+
+    hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, NULL, &cxt3, &editCookie);
+    ok(SUCCEEDED(hr),"CreateContext Failed\n");
+
+    test_EnumContexts(g_dm, NULL);
+
+    hr = ITfContext_GetDocumentMgr(cxt,&dmtest);
+    ok(hr == S_OK, "ITfContext_GetDocumentMgr failed with %x\n",hr);
+    ok(dmtest == g_dm, "Wrong documentmgr\n");
+    ITfDocumentMgr_Release(dmtest);
+
+    cnt = check_context_refcount(cxt);
+    test_OnPushContext = SINK_EXPECTED;
+    test_ACP_AdviseSink = SINK_EXPECTED;
+    test_OnInitDocumentMgr = SINK_EXPECTED;
+    hr = ITfDocumentMgr_Push(g_dm, cxt);
+    ok(SUCCEEDED(hr),"Push Failed\n");
+    ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n");
+    sink_check_ok(&test_OnPushContext,"OnPushContext");
+    sink_check_ok(&test_OnInitDocumentMgr,"OnInitDocumentMgr");
+    sink_check_ok(&test_ACP_AdviseSink,"TextStoreACP_AdviseSink");
+
+    test_EnumContexts(g_dm, cxt);
+
+    hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest);
+    ok(SUCCEEDED(hr),"GetTop Failed\n");
+    ok(cxtTest == cxt, "Wrong context on top\n");
+    ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n");
+    cnt = ITfContext_Release(cxtTest);
+
+    hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest);
+    ok(SUCCEEDED(hr),"GetBase Failed\n");
+    ok(cxtTest == cxt, "Wrong context on Base\n");
+    ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n");
+    ITfContext_Release(cxtTest);
+
+    check_context_refcount(cxt2);
+    test_OnPushContext = SINK_EXPECTED;
+    hr = ITfDocumentMgr_Push(g_dm, cxt2);
+    ok(SUCCEEDED(hr),"Push Failed\n");
+    sink_check_ok(&test_OnPushContext,"OnPushContext");
+
+    cnt = check_context_refcount(cxt2);
+    hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest);
+    ok(SUCCEEDED(hr),"GetTop Failed\n");
+    ok(cxtTest == cxt2, "Wrong context on top\n");
+    ok(check_context_refcount(cxt2) > cnt, "Ref count did not increase\n");
+    ITfContext_Release(cxtTest);
+
+    cnt = check_context_refcount(cxt);
+    hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest);
+    ok(SUCCEEDED(hr),"GetBase Failed\n");
+    ok(cxtTest == cxt, "Wrong context on Base\n");
+    ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n");
+    ITfContext_Release(cxtTest);
+
+    cnt = check_context_refcount(cxt3);
+    hr = ITfDocumentMgr_Push(g_dm, cxt3);
+    ok(FAILED(hr),"Push Succeeded\n");
+    ok(check_context_refcount(cxt3) == cnt, "Ref changed\n");
+
+    cnt = check_context_refcount(cxt2);
+    hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest);
+    ok(SUCCEEDED(hr),"GetTop Failed\n");
+    ok(cxtTest == cxt2, "Wrong context on top\n");
+    ok(check_context_refcount(cxt2) > cnt, "Ref count did not increase\n");
+    ITfContext_Release(cxtTest);
+
+    cnt = check_context_refcount(cxt);
+    hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest);
+    ok(SUCCEEDED(hr),"GetBase Failed\n");
+    ok(cxtTest == cxt, "Wrong context on Base\n");
+    ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n");
+    ITfContext_Release(cxtTest);
+
+    cnt = check_context_refcount(cxt2);
+    test_OnPopContext = SINK_EXPECTED;
+    hr = ITfDocumentMgr_Pop(g_dm, 0);
+    ok(SUCCEEDED(hr),"Pop Failed\n");
+    ok(check_context_refcount(cxt2) < cnt, "Ref count did not decrease\n");
+    sink_check_ok(&test_OnPopContext,"OnPopContext");
+
+    dmtest = (void *)0xfeedface;
+    hr = ITfContext_GetDocumentMgr(cxt2,&dmtest);
+    ok(hr == S_FALSE, "ITfContext_GetDocumentMgr wrong rc %x\n",hr);
+    ok(dmtest == NULL,"returned documentmgr should be null\n");
+
+    hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest);
+    ok(SUCCEEDED(hr),"GetTop Failed\n");
+    ok(cxtTest == cxt, "Wrong context on top\n");
+    ITfContext_Release(cxtTest);
+
+    hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest);
+    ok(SUCCEEDED(hr),"GetBase Failed\n");
+    ok(cxtTest == cxt, "Wrong context on base\n");
+    ITfContext_Release(cxtTest);
+
+    hr = ITfDocumentMgr_Pop(g_dm, 0);
+    ok(FAILED(hr),"Pop Succeeded\n");
+
+    hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest);
+    ok(SUCCEEDED(hr),"GetTop Failed\n");
+    ok(cxtTest == cxt, "Wrong context on top\n");
+    ITfContext_Release(cxtTest);
+
+    hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest);
+    ok(SUCCEEDED(hr),"GetBase Failed\n");
+    ok(cxtTest == cxt, "Wrong context on base\n");
+    ITfContext_Release(cxtTest);
+
+    ITfContext_Release(cxt);
+    ITfContext_Release(cxt2);
+    ITfContext_Release(cxt3);
 }
 
-static HRESULT WINAPI ThreadMgrEventSink_OnPopContext(ITfThreadMgrEventSink *iface,
-ITfContext *pic)
+static void test_endSession(void)
 {
-    ok(test_OnPopContext == SINK_EXPECTED, "Unexpected OnPopContext sink\n");
-    test_OnPopContext = SINK_FIRED;
-    return S_OK;
+    HRESULT hr;
+    test_ShouldDeactivate = TRUE;
+    test_CurrentFocus = NULL;
+    test_PrevFocus = g_dm;
+    test_OnSetFocus  = SINK_EXPECTED;
+    hr = ITfThreadMgr_Deactivate(g_tm);
+    ok(SUCCEEDED(hr),"Failed to Deactivate\n");
+    sink_check_ok(&test_OnSetFocus,"OnSetFocus");
+    test_OnSetFocus  = SINK_UNEXPECTED;
 }
 
-static const ITfThreadMgrEventSinkVtbl ThreadMgrEventSink_ThreadMgrEventSinkVtbl =
+static void test_TfGuidAtom(void)
 {
-    ThreadMgrEventSink_QueryInterface,
-    ThreadMgrEventSink_AddRef,
-    ThreadMgrEventSink_Release,
+    GUID gtest,g1;
+    HRESULT hr;
+    TfGuidAtom atom1,atom2;
+    BOOL equal;
+
+    CoCreateGuid(&gtest);
+
+    /* msdn reports this should return E_INVALIDARG.  However my test show it crashing (winxp)*/
+    /*
+    hr = ITfCategoryMgr_RegisterGUID(g_cm,&gtest,NULL);
+    ok(hr==E_INVALIDARG,"ITfCategoryMgr_RegisterGUID should have failed\n");
+    */
+    hr = ITfCategoryMgr_RegisterGUID(g_cm,&gtest,&atom1);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterGUID failed\n");
+    hr = ITfCategoryMgr_RegisterGUID(g_cm,&gtest,&atom2);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterGUID failed\n");
+    ok(atom1 == atom2,"atoms do not match\n");
+    hr = ITfCategoryMgr_GetGUID(g_cm,atom2,NULL);
+    ok(hr==E_INVALIDARG,"ITfCategoryMgr_GetGUID should have failed\n");
+    hr = ITfCategoryMgr_GetGUID(g_cm,atom2,&g1);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_GetGUID failed\n");
+    ok(IsEqualGUID(&g1,&gtest),"guids do not match\n");
+    hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,atom1,&gtest,NULL);
+    ok(hr==E_INVALIDARG,"ITfCategoryMgr_IsEqualTfGuidAtom should have failed\n");
+    hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,atom1,&gtest,&equal);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_IsEqualTfGuidAtom failed\n");
+    ok(equal == TRUE,"Equal value invalid\n");
 
-    ThreadMgrEventSink_OnInitDocumentMgr,
-    ThreadMgrEventSink_OnUninitDocumentMgr,
-    ThreadMgrEventSink_OnSetFocus,
-    ThreadMgrEventSink_OnPushContext,
-    ThreadMgrEventSink_OnPopContext
-};
+    /* show that cid and tid TfClientIds are also TfGuidAtoms */
+    hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,tid,&CLSID_FakeService,&equal);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_IsEqualTfGuidAtom failed\n");
+    ok(equal == TRUE,"Equal value invalid\n");
+    hr = ITfCategoryMgr_GetGUID(g_cm,cid,&g1);
+    ok(SUCCEEDED(hr),"ITfCategoryMgr_GetGUID failed\n");
+    ok(!IsEqualGUID(&g1,&GUID_NULL),"guid should not be NULL\n");
+}
 
-HRESULT ThreadMgrEventSink_Constructor(IUnknown **ppOut)
+static void test_ClientId(void)
 {
-    ThreadMgrEventSink *This;
+    ITfClientId *pcid;
+    TfClientId id1,id2;
+    HRESULT hr;
+    GUID g2;
 
-    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgrEventSink));
-    if (This == NULL)
-        return E_OUTOFMEMORY;
+    hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfClientId, (LPVOID*)&pcid);
+    ok(SUCCEEDED(hr),"Unable to acquire ITfClientId interface\n");
 
-    This->ThreadMgrEventSinkVtbl = &ThreadMgrEventSink_ThreadMgrEventSinkVtbl;
-    This->refCount = 1;
+    CoCreateGuid(&g2);
 
-    *ppOut = (IUnknown *)This;
-    return S_OK;
+    hr = ITfClientId_GetClientId(pcid,&GUID_NULL,&id1);
+    ok(SUCCEEDED(hr),"GetClientId failed\n");
+    hr = ITfClientId_GetClientId(pcid,&GUID_NULL,&id2);
+    ok(SUCCEEDED(hr),"GetClientId failed\n");
+    ok(id1==id2,"Id's for GUID_NULL do not match\n");
+    hr = ITfClientId_GetClientId(pcid,&CLSID_FakeService,&id2);
+    ok(SUCCEEDED(hr),"GetClientId failed\n");
+    ok(id2!=id1,"Id matches GUID_NULL\n");
+    ok(id2==tid,"Id for CLSID_FakeService not matching tid\n");
+    ok(id2!=cid,"Id for CLSID_FakeService matching cid\n");
+    hr = ITfClientId_GetClientId(pcid,&g2,&id2);
+    ok(SUCCEEDED(hr),"GetClientId failed\n");
+    ok(id2!=id1,"Id matches GUID_NULL\n");
+    ok(id2!=tid,"Id for random guid matching tid\n");
+    ok(id2!=cid,"Id for random guid matching cid\n");
+    ITfClientId_Release(pcid);
 }
 
-
-/********************************************************************************************
- * Stub text service for testing
- ********************************************************************************************/
-
-static LONG TS_refCount;
-static IClassFactory *cf;
-static DWORD regid;
-
-typedef HRESULT (*LPFNCONSTRUCTOR)(IUnknown *pUnkOuter, IUnknown **ppvOut);
-
-typedef struct tagClassFactory
-{
-    const IClassFactoryVtbl *vtbl;
-    LONG   ref;
-    LPFNCONSTRUCTOR ctor;
-} ClassFactory;
-
-typedef struct tagTextService
+/**********************************************************************
+ * ITfEditSession
+ **********************************************************************/
+typedef struct tagEditSession
 {
-    const ITfTextInputProcessorVtbl *TextInputProcessorVtbl;
+    const ITfEditSessionVtbl *EditSessionVtbl;
     LONG refCount;
-} TextService;
+} EditSession;
 
-static void ClassFactory_Destructor(ClassFactory *This)
+static void EditSession_Destructor(EditSession *This)
 {
     HeapFree(GetProcessHeap(),0,This);
-    TS_refCount--;
 }
 
-static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppvOut)
+static HRESULT WINAPI EditSession_QueryInterface(ITfEditSession *iface, REFIID iid, LPVOID *ppvOut)
 {
+    EditSession *This = (EditSession *)iface;
     *ppvOut = NULL;
-    if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown))
+
+    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfEditSession))
     {
-        IClassFactory_AddRef(iface);
-        *ppvOut = iface;
+        *ppvOut = This;
+    }
+
+    if (*ppvOut)
+    {
+        IUnknown_AddRef(iface);
         return S_OK;
     }
 
     return E_NOINTERFACE;
 }
 
-static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
+static ULONG WINAPI EditSession_AddRef(ITfEditSession *iface)
 {
-    ClassFactory *This = (ClassFactory *)iface;
-    return InterlockedIncrement(&This->ref);
+    EditSession *This = (EditSession *)iface;
+    return InterlockedIncrement(&This->refCount);
 }
 
-static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
+static ULONG WINAPI EditSession_Release(ITfEditSession *iface)
 {
-    ClassFactory *This = (ClassFactory *)iface;
-    ULONG ret = InterlockedDecrement(&This->ref);
+    EditSession *This = (EditSession *)iface;
+    ULONG ret;
 
+    ret = InterlockedDecrement(&This->refCount);
     if (ret == 0)
-        ClassFactory_Destructor(This);
+        EditSession_Destructor(This);
     return ret;
 }
 
-static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *punkOuter, REFIID iid, LPVOID *ppvOut)
+static void test_InsertAtSelection(TfEditCookie ec, ITfContext *cxt)
 {
-    ClassFactory *This = (ClassFactory *)iface;
-    HRESULT ret;
-    IUnknown *obj;
+    HRESULT hr;
+    ITfInsertAtSelection *iis;
+    ITfRange *range=NULL;
+    static const WCHAR txt[] = {'H','e','l','l','o',' ','W','o','r','l','d',0};
+
+    hr = ITfContext_QueryInterface(cxt, &IID_ITfInsertAtSelection , (LPVOID*)&iis);
+    ok(SUCCEEDED(hr),"Failed to get ITfInsertAtSelection interface\n");
+    test_ACP_InsertTextAtSelection = SINK_EXPECTED;
+    hr = ITfInsertAtSelection_InsertTextAtSelection(iis, ec, 0, txt, 11, &range);
+    ok(SUCCEEDED(hr),"ITfInsertAtSelection_InsertTextAtSelection failed %x\n",hr);
+    sink_check_ok(&test_ACP_InsertTextAtSelection,"InsertTextAtSelection");
+    ok(range != NULL,"No range returned\n");
+    ITfRange_Release(range);
+    ITfInsertAtSelection_Release(iis);
+}
+
+static HRESULT WINAPI EditSession_DoEditSession(ITfEditSession *iface,
+TfEditCookie ec)
+{
+    ITfContext *cxt;
+    ITfDocumentMgr *dm;
+    ITfRange *range;
+    TF_SELECTION selection;
+    ULONG fetched;
+    HRESULT hr;
 
-    ret = This->ctor(punkOuter, &obj);
-    if (FAILED(ret))
-        return ret;
-    ret = IUnknown_QueryInterface(obj, iid, ppvOut);
-    IUnknown_Release(obj);
-    return ret;
-}
+    sink_fire_ok(&test_DoEditSession,"EditSession_DoEditSession");
+    sink_check_ok(&test_ACP_RequestLock,"RequestLock");
 
-static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock)
-{
-    if(fLock)
-        InterlockedIncrement(&TS_refCount);
-    else
-        InterlockedDecrement(&TS_refCount);
+    ITfThreadMgr_GetFocus(g_tm, &dm);
+    ITfDocumentMgr_GetTop(dm,&cxt);
 
-    return S_OK;
+    hr = ITfContext_GetStart(cxt,ec,NULL);
+    ok(hr == E_INVALIDARG,"Unexpected return code %x\n",hr);
+
+    range = (ITfRange*)0xdeaddead;
+    hr = ITfContext_GetStart(cxt,0xdeadcafe,&range);
+    ok(hr == TF_E_NOLOCK,"Unexpected return code %x\n",hr);
+    ok(range == NULL,"Range not set to NULL\n");
+
+    hr = ITfContext_GetStart(cxt,ec,&range);
+    ok(SUCCEEDED(hr),"Unexpected return code %x\n",hr);
+    ok(range != NULL,"Range set to NULL\n");
+
+    ITfRange_Release(range);
+
+    hr = ITfContext_GetEnd(cxt,ec,NULL);
+    ok(hr == E_INVALIDARG,"Unexpected return code %x\n",hr);
+
+    range = (ITfRange*)0xdeaddead;
+    hr = ITfContext_GetEnd(cxt,0xdeadcafe,&range);
+    ok(hr == TF_E_NOLOCK,"Unexpected return code %x\n",hr);
+    ok(range == NULL,"Range not set to NULL\n");
+
+    test_ACP_GetEndACP = SINK_EXPECTED;
+    hr = ITfContext_GetEnd(cxt,ec,&range);
+    ok(SUCCEEDED(hr),"Unexpected return code %x\n",hr);
+    ok(range != NULL,"Range set to NULL\n");
+    sink_check_ok(&test_ACP_GetEndACP,"GetEndACP");
+
+    ITfRange_Release(range);
+
+    selection.range = NULL;
+    test_ACP_GetSelection = SINK_EXPECTED;
+    hr = ITfContext_GetSelection(cxt, ec, TF_DEFAULT_SELECTION, 1, &selection, &fetched);
+    ok(SUCCEEDED(hr),"ITfContext_GetSelection failed\n");
+    ok(fetched == 1,"fetched incorrect\n");
+    ok(selection.range != NULL,"NULL range\n");
+    sink_check_ok(&test_ACP_GetSelection,"ACP_GetSepection");
+    ITfRange_Release(selection.range);
+
+    test_InsertAtSelection(ec, cxt);
+
+    test_ACP_GetEndACP = SINK_EXPECTED;
+    hr = ITfContext_GetEnd(cxt,ec,&range);
+    ok(SUCCEEDED(hr),"Unexpected return code %x\n",hr);
+    ok(range != NULL,"Range set to NULL\n");
+    sink_check_ok(&test_ACP_GetEndACP,"GetEndACP");
+
+    selection.range = range;
+    selection.style.ase = TF_AE_NONE;
+    selection.style.fInterimChar = FALSE;
+    test_ACP_SetSelection = SINK_EXPECTED;
+    hr = ITfContext_SetSelection(cxt, ec, 1, &selection);
+    sink_check_ok(&test_ACP_SetSelection,"SetSelection");
+    ITfRange_Release(range);
+
+    ITfContext_Release(cxt);
+    ITfDocumentMgr_Release(dm);
+    return 0xdeadcafe;
 }
 
-static const IClassFactoryVtbl ClassFactoryVtbl = {
-    /* IUnknown */
-    ClassFactory_QueryInterface,
-    ClassFactory_AddRef,
-    ClassFactory_Release,
+static const ITfEditSessionVtbl EditSession_EditSessionVtbl =
+{
+    EditSession_QueryInterface,
+    EditSession_AddRef,
+    EditSession_Release,
 
-    /* IClassFactory*/
-    ClassFactory_CreateInstance,
-    ClassFactory_LockServer
+    EditSession_DoEditSession
 };
 
-static HRESULT ClassFactory_Constructor(LPFNCONSTRUCTOR ctor, LPVOID *ppvOut)
+static HRESULT EditSession_Constructor(ITfEditSession **ppOut)
 {
-    ClassFactory *This = HeapAlloc(GetProcessHeap(),0,sizeof(ClassFactory));
-    This->vtbl = &ClassFactoryVtbl;
-    This->ref = 1;
-    This->ctor = ctor;
-    *ppvOut = (LPVOID)This;
-    TS_refCount++;
+    EditSession *This;
+
+    *ppOut = NULL;
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EditSession));
+    if (This == NULL)
+        return E_OUTOFMEMORY;
+
+    This->EditSessionVtbl = &EditSession_EditSessionVtbl;
+    This->refCount = 1;
+
+    *ppOut = (ITfEditSession*)This;
     return S_OK;
 }
 
-static void TextService_Destructor(TextService *This)
+static void test_TStoApplicationText(void)
 {
-    HeapFree(GetProcessHeap(),0,This);
-}
+    HRESULT hr, hrSession;
+    ITfEditSession *es;
+    ITfContext *cxt;
+    ITfDocumentMgr *dm;
+    ITfTextEditSink *sink;
+    ITfSource *source = NULL;
+    DWORD editSinkCookie = -1;
 
-static HRESULT WINAPI TextService_QueryInterface(ITfTextInputProcessor *iface, REFIID iid, LPVOID *ppvOut)
-{
-    TextService *This = (TextService *)iface;
-    *ppvOut = NULL;
+    ITfThreadMgr_GetFocus(g_tm, &dm);
+    EditSession_Constructor(&es);
+    ITfDocumentMgr_GetTop(dm,&cxt);
 
-    if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfTextInputProcessor))
+    TextEditSink_Constructor(&sink);
+    hr = ITfContext_QueryInterface(cxt,&IID_ITfSource,(LPVOID*)&source);
+    ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for Context\n");
+    if (source)
     {
-        *ppvOut = This;
+        hr = ITfSource_AdviseSink(source, &IID_ITfTextEditSink, (LPVOID)sink, &editSinkCookie);
+        ok(SUCCEEDED(hr),"Failed to advise Sink\n");
+        ok(editSinkCookie != -1,"Failed to get sink cookie\n");
     }
 
-    if (*ppvOut)
+    hrSession = 0xfeedface;
+    /* Test no premissions flags */
+    hr = ITfContext_RequestEditSession(cxt, tid, es, TF_ES_SYNC, &hrSession);
+    ok(hr == E_INVALIDARG,"RequestEditSession should have failed with %x not %x\n",E_INVALIDARG,hr);
+    ok(hrSession == E_FAIL,"hrSession should be %x not %x\n",E_FAIL,hrSession);
+
+    documentStatus = TS_SD_READONLY;
+    hrSession = 0xfeedface;
+    test_ACP_GetStatus = SINK_EXPECTED;
+    hr = ITfContext_RequestEditSession(cxt, tid, es, TF_ES_SYNC|TF_ES_READWRITE, &hrSession);
+    ok(SUCCEEDED(hr),"ITfContext_RequestEditSession failed\n");
+    ok(hrSession == TS_E_READONLY,"Unexpected hrSession (%x)\n",hrSession);
+    sink_check_ok(&test_ACP_GetStatus,"GetStatus");
+
+    /* signal a change to allow readwrite sessions */
+    documentStatus = 0;
+    test_ACP_RequestLock = SINK_EXPECTED;
+    ITextStoreACPSink_OnStatusChange(ACPSink,documentStatus);
+    sink_check_ok(&test_ACP_RequestLock,"RequestLock");
+
+    test_ACP_GetStatus = SINK_EXPECTED;
+    test_ACP_RequestLock = SINK_EXPECTED;
+    test_DoEditSession = SINK_EXPECTED;
+    hrSession = 0xfeedface;
+    test_OnEndEdit = SINK_EXPECTED;
+    hr = ITfContext_RequestEditSession(cxt, tid, es, TF_ES_SYNC|TF_ES_READWRITE, &hrSession);
+    ok(SUCCEEDED(hr),"ITfContext_RequestEditSession failed\n");
+    sink_check_ok(&test_OnEndEdit,"OnEndEdit");
+    sink_check_ok(&test_DoEditSession,"DoEditSession");
+    sink_check_ok(&test_ACP_GetStatus,"GetStatus");
+    ok(hrSession == 0xdeadcafe,"Unexpected hrSession (%x)\n",hrSession);
+
+    if (source)
     {
-        IUnknown_AddRef(iface);
-        return S_OK;
+        hr = ITfSource_UnadviseSink(source, editSinkCookie);
+        ok(SUCCEEDED(hr),"Failed to unadvise Sink\n");
+        ITfTextEditSink_Release(sink);
+        ITfSource_Release(source);
     }
 
-    return E_NOINTERFACE;
+    ITfContext_Release(cxt);
+    ITfDocumentMgr_Release(dm);
+    ITfEditSession_Release(es);
 }
 
-static ULONG WINAPI TextService_AddRef(ITfTextInputProcessor *iface)
+static void enum_compartments(ITfCompartmentMgr *cmpmgr, REFGUID present, REFGUID absent)
 {
-    TextService *This = (TextService *)iface;
-    return InterlockedIncrement(&This->refCount);
+    BOOL found,found2;
+    IEnumGUID *ppEnum;
+    found = FALSE;
+    found2 = FALSE;
+    if (SUCCEEDED(ITfCompartmentMgr_EnumCompartments(cmpmgr, &ppEnum)))
+    {
+        ULONG fetched;
+        GUID g;
+        while (IEnumGUID_Next(ppEnum, 1, &g, &fetched) == S_OK)
+        {
+            WCHAR str[50];
+            CHAR strA[50];
+            StringFromGUID2(&g,str,sizeof(str)/sizeof(str[0]));
+            WideCharToMultiByte(CP_ACP,0,str,-1,strA,sizeof(strA),0,0);
+            trace("found %s\n",strA);
+            if (present && IsEqualGUID(present,&g))
+                found = TRUE;
+            if (absent && IsEqualGUID(absent, &g))
+                found2 = TRUE;
+        }
+        IEnumGUID_Release(ppEnum);
+    }
+    if (present)
+        ok(found,"Did not find compartment\n");
+    if (absent)
+        ok(!found2,"Found compartment that should be absent\n");
 }
 
-static ULONG WINAPI TextService_Release(ITfTextInputProcessor *iface)
+static void test_Compartments(void)
 {
-    TextService *This = (TextService *)iface;
-    ULONG ret;
+    ITfContext *cxt;
+    ITfDocumentMgr *dm;
+    ITfCompartmentMgr *cmpmgr;
+    ITfCompartment *cmp;
+    HRESULT hr;
 
-    ret = InterlockedDecrement(&This->refCount);
-    if (ret == 0)
-        TextService_Destructor(This);
-    return ret;
-}
+    ITfThreadMgr_GetFocus(g_tm, &dm);
+    ITfDocumentMgr_GetTop(dm,&cxt);
+
+    /* Global */
+    hr = ITfThreadMgr_GetGlobalCompartment(g_tm, &cmpmgr);
+    ok(SUCCEEDED(hr),"GetGlobalCompartment failed\n");
+    hr = ITfCompartmentMgr_GetCompartment(cmpmgr, &GUID_COMPARTMENT_SPEECH_OPENCLOSE, &cmp);
+    ok(SUCCEEDED(hr),"GetCompartment failed\n");
+    ITfCompartment_Release(cmp);
+    enum_compartments(cmpmgr,&GUID_COMPARTMENT_SPEECH_OPENCLOSE,NULL);
+    ITfCompartmentMgr_Release(cmpmgr);
+
+    /* Thread */
+    hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfCompartmentMgr, (LPVOID*)&cmpmgr);
+    ok(SUCCEEDED(hr),"ThreadMgr QI for IID_ITfCompartmentMgr failed\n");
+    hr = ITfCompartmentMgr_GetCompartment(cmpmgr, &CLSID_FakeService, &cmp);
+    ok(SUCCEEDED(hr),"GetCompartment failed\n");
+    enum_compartments(cmpmgr,&CLSID_FakeService,&GUID_COMPARTMENT_SPEECH_OPENCLOSE);
+    ITfCompartmentMgr_ClearCompartment(cmpmgr,tid,&CLSID_FakeService);
+    enum_compartments(cmpmgr,NULL,&CLSID_FakeService);
+    ITfCompartmentMgr_Release(cmpmgr);
+    ITfCompartment_Release(cmp);
+
+    /* DocumentMgr */
+    hr = ITfDocumentMgr_QueryInterface(dm, &IID_ITfCompartmentMgr, (LPVOID*)&cmpmgr);
+    ok(SUCCEEDED(hr),"DocumentMgr QI for IID_ITfCompartmentMgr failed\n");
+
+    hr = ITfCompartmentMgr_GetCompartment(cmpmgr, &GUID_COMPARTMENT_PERSISTMENUENABLED, &cmp);
+    ok(SUCCEEDED(hr),"GetCompartment failed\n");
+    enum_compartments(cmpmgr,&GUID_COMPARTMENT_PERSISTMENUENABLED,&GUID_COMPARTMENT_SPEECH_OPENCLOSE);
+    ITfCompartmentMgr_Release(cmpmgr);
+
+    /* Context */
+    hr = ITfContext_QueryInterface(cxt, &IID_ITfCompartmentMgr, (LPVOID*)&cmpmgr);
+    ok(SUCCEEDED(hr),"Context QI for IID_ITfCompartmentMgr failed\n");
+    enum_compartments(cmpmgr,NULL,&GUID_COMPARTMENT_PERSISTMENUENABLED);
+    ITfCompartmentMgr_Release(cmpmgr);
 
-static HRESULT WINAPI TextService_Activate(ITfTextInputProcessor *iface,
-        ITfThreadMgr *ptim, TfClientId id)
-{
-    trace("TextService_Activate\n");
-    ok(test_ShouldActivate,"Activation came unexpectedly\n");
-    tid = id;
-    return S_OK;
+    ITfContext_Release(cxt);
+    ITfDocumentMgr_Release(dm);
 }
 
-static HRESULT WINAPI TextService_Deactivate(ITfTextInputProcessor *iface)
+static void processPendingMessages(void)
 {
-    trace("TextService_Deactivate\n");
-    ok(test_ShouldDeactivate,"Deactivation came unexpectedly\n");
-    return S_OK;
+    MSG msg;
+    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+    }
 }
 
-static const ITfTextInputProcessorVtbl TextService_TextInputProcessorVtbl=
+static void test_AssociateFocus(void)
 {
-    TextService_QueryInterface,
-    TextService_AddRef,
-    TextService_Release,
+    ITfDocumentMgr *dm1, *dm2, *olddm, *dmcheck, *dmorig;
+    HWND wnd1, wnd2, wnd3;
+    HRESULT hr;
 
-    TextService_Activate,
-    TextService_Deactivate
-};
+    ITfThreadMgr_GetFocus(g_tm, &dmorig);
+    test_CurrentFocus = NULL;
+    test_PrevFocus = dmorig;
+    test_OnSetFocus  = SINK_EXPECTED;
+    hr = ITfThreadMgr_SetFocus(g_tm,NULL);
+    sink_check_ok(&test_OnSetFocus,"OnSetFocus");
+    ITfDocumentMgr_Release(dmorig);
 
-HRESULT TextService_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
-{
-    TextService *This;
-    if (pUnkOuter)
-        return CLASS_E_NOAGGREGATION;
+    hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&dm1);
+    ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n");
 
-    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextService));
-    if (This == NULL)
-        return E_OUTOFMEMORY;
+    hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&dm2);
+    ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n");
 
-    This->TextInputProcessorVtbl= &TextService_TextInputProcessorVtbl;
-    This->refCount = 1;
+    wnd1 = CreateWindow("edit",NULL,WS_POPUP,0,0,200,60,NULL,NULL,NULL,NULL);
+    ok(wnd1!=NULL,"Unable to create window 1\n");
+    wnd2 = CreateWindow("edit",NULL,WS_POPUP,0,65,200,60,NULL,NULL,NULL,NULL);
+    ok(wnd2!=NULL,"Unable to create window 2\n");
+    wnd3 = CreateWindow("edit",NULL,WS_POPUP,0,130,200,60,NULL,NULL,NULL,NULL);
+    ok(wnd3!=NULL,"Unable to create window 3\n");
 
-    *ppOut = (IUnknown *)This;
-    return S_OK;
-}
+    processPendingMessages();
 
-HRESULT RegisterTextService(REFCLSID rclsid)
-{
-    ClassFactory_Constructor( TextService_Constructor ,(LPVOID*)&cf);
-    return CoRegisterClassObject(rclsid, (IUnknown*) cf, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &regid);
+    test_OnInitDocumentMgr = SINK_OPTIONAL; /* Vista and greater */
+    test_OnPushContext = SINK_OPTIONAL; /* Vista and greater */
+
+    ShowWindow(wnd1,SW_SHOWNORMAL);
+    SetFocus(wnd1);
+    sink_check_ok(&test_OnInitDocumentMgr,"OnInitDocumentMgr");
+    sink_check_ok(&test_OnPushContext,"OnPushContext");
+
+    test_OnSetFocus  = SINK_OPTIONAL; /* Vista and greater */
+    ITfThreadMgr_GetFocus(g_tm, &test_PrevFocus);
+    test_CurrentFocus = FOCUS_IGNORE; /* This is a default system context */
+    processPendingMessages();
+    sink_check_ok(&test_OnSetFocus,"OnSetFocus");
+
+    test_CurrentFocus = dm1;
+    test_PrevFocus = FOCUS_IGNORE;
+    test_OnSetFocus  = SINK_EXPECTED;
+    hr = ITfThreadMgr_AssociateFocus(g_tm,wnd1,dm1,&olddm);
+    ok(SUCCEEDED(hr),"AssociateFocus failed\n");
+    sink_check_ok(&test_OnSetFocus,"OnSetFocus");
+
+    processPendingMessages();
+
+    ITfThreadMgr_GetFocus(g_tm, &dmcheck);
+    ok(dmcheck == dm1, "Expected DocumentMgr not focused\n");
+    ITfDocumentMgr_Release(dmcheck);
+
+    hr = ITfThreadMgr_AssociateFocus(g_tm,wnd2,dm2,&olddm);
+    ok(SUCCEEDED(hr),"AssociateFocus failed\n");
+    processPendingMessages();
+    ITfThreadMgr_GetFocus(g_tm, &dmcheck);
+    ok(dmcheck == dm1, "Expected DocumentMgr not focused\n");
+    ITfDocumentMgr_Release(dmcheck);
+
+    hr = ITfThreadMgr_AssociateFocus(g_tm,wnd3,dm2,&olddm);
+    ok(SUCCEEDED(hr),"AssociateFocus failed\n");
+    processPendingMessages();
+    ITfThreadMgr_GetFocus(g_tm, &dmcheck);
+    ok(dmcheck == dm1, "Expected DocumentMgr not focused\n");
+    ITfDocumentMgr_Release(dmcheck);
+
+    test_CurrentFocus = dm2;
+    test_PrevFocus = dm1;
+    test_OnSetFocus  = SINK_OPTIONAL; /* wine and Winxp */
+    ShowWindow(wnd2,SW_SHOWNORMAL);
+    SetFocus(wnd2);
+    sink_check_ok(&test_OnSetFocus,"OnSetFocus");
+    test_CurrentFocus = FOCUS_IGNORE; /* occasional wine race */
+    test_PrevFocus = FOCUS_IGNORE; /* occasional wine race */
+    test_OnSetFocus = SINK_IGNORE; /* occasional wine race */
+    processPendingMessages();
+
+    ShowWindow(wnd3,SW_SHOWNORMAL);
+    SetFocus(wnd3);
+    processPendingMessages();
+
+    test_CurrentFocus = dm1;
+    test_PrevFocus = dm2;
+    test_OnSetFocus = SINK_EXPECTED;
+    SetFocus(wnd1);
+    processPendingMessages();
+    sink_check_ok(&test_OnSetFocus,"OnSetFocus");
+
+    hr = ITfThreadMgr_AssociateFocus(g_tm,wnd3,NULL,&olddm);
+    ok(SUCCEEDED(hr),"AssociateFocus failed\n");
+    ok(olddm == dm2, "incorrect old DocumentMgr returned\n");
+    ITfDocumentMgr_Release(olddm);
+
+    test_CurrentFocus = dmorig;
+    test_PrevFocus = dm1;
+    test_OnSetFocus  = SINK_EXPECTED;
+    test_ACP_GetStatus = SINK_EXPECTED;
+    ITfThreadMgr_SetFocus(g_tm,dmorig);
+    sink_check_ok(&test_OnSetFocus,"OnSetFocus");
+
+    test_CurrentFocus = FOCUS_IGNORE; /* NULL on XP, system default on Vista */
+    test_PrevFocus = dmorig;
+    test_OnSetFocus  = SINK_EXPECTED;
+    SetFocus(wnd3);
+    processPendingMessages();
+    sink_check_ok(&test_OnSetFocus,"OnSetFocus");
+
+    hr = ITfThreadMgr_AssociateFocus(g_tm,wnd2,NULL,&olddm);
+    ok(SUCCEEDED(hr),"AssociateFocus failed\n");
+    ok(olddm == dm2, "incorrect old DocumentMgr returned\n");
+    ITfDocumentMgr_Release(olddm);
+    hr = ITfThreadMgr_AssociateFocus(g_tm,wnd1,NULL,&olddm);
+    ok(SUCCEEDED(hr),"AssociateFocus failed\n");
+    ok(olddm == dm1, "incorrect old DocumentMgr returned\n");
+    ITfDocumentMgr_Release(olddm);
+
+    SetFocus(wnd2);
+    processPendingMessages();
+    SetFocus(wnd1);
+    processPendingMessages();
+
+    ITfDocumentMgr_Release(dm1);
+    ITfDocumentMgr_Release(dm2);
+
+    test_CurrentFocus = dmorig;
+    test_PrevFocus = FOCUS_IGNORE;
+    test_OnSetFocus  = SINK_EXPECTED;
+    test_ACP_GetStatus = SINK_IGNORE;
+    ITfThreadMgr_SetFocus(g_tm,dmorig);
+    sink_check_ok(&test_OnSetFocus,"OnSetFocus");
+
+    DestroyWindow(wnd1);
+    DestroyWindow(wnd2);
+    test_OnPopContext = SINK_OPTIONAL; /* Vista and greater */
+    test_OnSetFocus = SINK_OPTIONAL; /* Vista and greater */
+    ITfThreadMgr_GetFocus(g_tm, &test_PrevFocus);
+    test_CurrentFocus = NULL;
+    DestroyWindow(wnd3);
+    sink_check_ok(&test_OnSetFocus,"OnSetFocus");
+    sink_check_ok(&test_OnPopContext,"OnPopContext");
 }
 
-HRESULT UnregisterTextService()
+START_TEST(inputprocessor)
 {
-    return CoRevokeClassObject(regid);
+    if (SUCCEEDED(initialize()))
+    {
+        test_Register();
+        test_RegisterCategory();
+        test_EnumLanguageProfiles();
+        test_EnumInputProcessorInfo();
+        test_Enable();
+        test_ThreadMgrAdviseSinks();
+        test_Activate();
+        test_startSession();
+        test_TfGuidAtom();
+        test_ClientId();
+        test_KeystrokeMgr();
+        test_TStoApplicationText();
+        test_Compartments();
+        test_AssociateFocus();
+        test_endSession();
+        test_FindClosestCategory();
+        test_Disable();
+        test_ThreadMgrUnadviseSinks();
+        test_UnregisterCategory();
+        test_Unregister();
+    }
+    else
+        skip("Unable to create InputProcessor\n");
+    cleanup();
 }
index 25bf764..c6f5479 100644 (file)
@@ -3173,6 +3173,16 @@ static void test_navigator(IHTMLDocument2 *doc)
     ok(!strcmp_wa(bstr, buf), "userAgent returned %s, expected \"%s\"\n", wine_dbgstr_w(bstr), buf);
     SysFreeString(bstr);
 
+    if(!strncmp(buf, "Mozilla/", 8)) {
+        bstr = NULL;
+        hres = IOmNavigator_get_appVersion(navigator, &bstr);
+        ok(hres == S_OK, "get_appVersion failed: %08x\n", hres);
+        ok(!strcmp_wa(bstr, buf+8), "appVersion returned %s, expected \"%s\"\n", wine_dbgstr_w(bstr), buf+8);
+        SysFreeString(bstr);
+    }else {
+        skip("nonstandard user agent\n");
+    }
+
     ref = IOmNavigator_Release(navigator);
     ok(!ref, "navigator should be destroyed here\n");
 }
@@ -3185,8 +3195,6 @@ static void test_screen(IHTMLWindow2 *window)
     HDC hdc;
     HRESULT hres;
 
-    static const WCHAR displayW[] = {'D','I','S','P','L','A','Y',0};
-
     screen = NULL;
     hres = IHTMLWindow2_get_screen(window, &screen);
     ok(hres == S_OK, "get_screen failed: %08x\n", hres);
@@ -3206,7 +3214,7 @@ static void test_screen(IHTMLWindow2 *window)
         IDispatchEx_Release(dispex);
     }
 
-    hdc = CreateICW(displayW, NULL, NULL, NULL);
+    hdc = CreateICA("DISPLAY", NULL, NULL, NULL);
 
     exl = GetDeviceCaps(hdc, HORZRES);
     l = 0xdeadbeef;
index 16f727f..d62df7a 100644 (file)
@@ -67,6 +67,8 @@ DEFINE_EXPECT(div_onclick_disp);
 DEFINE_EXPECT(iframe_onreadystatechange_loading);
 DEFINE_EXPECT(iframe_onreadystatechange_interactive);
 DEFINE_EXPECT(iframe_onreadystatechange_complete);
+DEFINE_EXPECT(iframedoc_onreadystatechange);
+DEFINE_EXPECT(img_onload);
 
 static HWND container_hwnd = NULL;
 static IHTMLWindow2 *window;
@@ -92,7 +94,10 @@ static const char click_doc_str[] =
     "</body></html>";
 
 static const char readystate_doc_str[] =
-    "<<html><body><iframe id=\"iframe\"></iframe></body></html>";
+    "<html><body><iframe id=\"iframe\"></iframe></body></html>";
+
+static const char img_doc_str[] =
+    "<html><body><img id=\"imgid\"></img></body></html>";
 
 static const char *debugstr_guid(REFIID riid)
 {
@@ -879,14 +884,46 @@ static HRESULT WINAPI body_onclick(IDispatchEx *iface, DISPID id, LCID lcid, WOR
 
 EVENT_HANDLER_FUNC_OBJ(body_onclick);
 
+static HRESULT WINAPI img_onload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
+        VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
+{
+    CHECK_EXPECT(img_onload);
+    test_event_args(&DIID_DispHTMLImg, id, wFlags, pdp, pvarRes, pei, pspCaller);
+    test_event_src("IMG");
+    return S_OK;
+}
+
+EVENT_HANDLER_FUNC_OBJ(img_onload);
+
+static HRESULT WINAPI iframedoc_onreadystatechange(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
+        VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
+{
+    IHTMLEventObj *event = NULL;
+    HRESULT hres;
+
+    CHECK_EXPECT2(iframedoc_onreadystatechange);
+    test_event_args(&DIID_DispHTMLDocument, id, wFlags, pdp, pvarRes, pei, pspCaller);
+
+    event = (void*)0xdeadbeef;
+    hres = IHTMLWindow2_get_event(window, &event);
+    ok(hres == S_OK, "get_event failed: %08x\n", hres);
+    ok(!event, "event = %p\n", event);
+
+    return S_OK;
+}
+
+EVENT_HANDLER_FUNC_OBJ(iframedoc_onreadystatechange);
+
 static HRESULT WINAPI iframe_onreadystatechange(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
 {
+    IHTMLWindow2 *iframe_window;
+    IHTMLDocument2 *iframe_doc;
     IHTMLFrameBase2 *iframe;
     IHTMLElement2 *elem2;
     IHTMLElement *elem;
     VARIANT v;
-    BSTR str;
+    BSTR str, str2;
     HRESULT hres;
 
     test_event_args(&DIID_DispHTMLIFrame, id, wFlags, pdp, pvarRes, pei, pspCaller);
@@ -913,15 +950,33 @@ static HRESULT WINAPI iframe_onreadystatechange(IDispatchEx *iface, DISPID id, L
     ok(!lstrcmpW(str, V_BSTR(&v)), "ready states differ\n");
     VariantClear(&v);
 
-    if(!strcmp_wa(str, "loading"))
+    hres = IHTMLFrameBase2_get_contentWindow(iframe, &iframe_window);
+    ok(hres == S_OK, "get_contentDocument failed: %08x\n", hres);
+
+    hres = IHTMLWindow2_get_document(iframe_window, &iframe_doc);
+    IHTMLWindow2_Release(iframe_window);
+    ok(hres == S_OK, "get_document failed: %08x\n", hres);
+
+    hres = IHTMLDocument2_get_readyState(iframe_doc, &str2);
+    ok(!lstrcmpW(str, str2), "unexpected document readyState %s\n", wine_dbgstr_w(str2));
+    SysFreeString(str2);
+
+    if(!strcmp_wa(str, "loading")) {
         CHECK_EXPECT(iframe_onreadystatechange_loading);
-    else if(!strcmp_wa(str, "interactive"))
+
+        V_VT(&v) = VT_DISPATCH;
+        V_DISPATCH(&v) = (IDispatch*)&iframedoc_onreadystatechange_obj;
+        hres = IHTMLDocument2_put_onreadystatechange(iframe_doc, v);
+        ok(hres == S_OK, "put_onreadystatechange: %08x\n", hres);
+    }else if(!strcmp_wa(str, "interactive"))
         CHECK_EXPECT(iframe_onreadystatechange_interactive);
     else if(!strcmp_wa(str, "complete"))
         CHECK_EXPECT(iframe_onreadystatechange_complete);
     else
         ok(0, "unexpected state %s\n", wine_dbgstr_w(str));
 
+    IHTMLDocument2_Release(iframe_doc);
+    IHTMLFrameBase2_Release(iframe);
     return S_OK;
 }
 
@@ -1307,17 +1362,60 @@ static void test_onreadystatechange(IHTMLDocument2 *doc)
     ok(hres == S_OK, "put_src failed: %08x\n", hres);
 
     SET_EXPECT(iframe_onreadystatechange_loading);
+    SET_EXPECT(iframedoc_onreadystatechange);
     SET_EXPECT(iframe_onreadystatechange_interactive);
     SET_EXPECT(iframe_onreadystatechange_complete);
     pump_msgs(&called_iframe_onreadystatechange_complete);
-    todo_wine
     CHECK_CALLED(iframe_onreadystatechange_loading);
+    CHECK_CALLED(iframedoc_onreadystatechange);
     CHECK_CALLED(iframe_onreadystatechange_interactive);
     CHECK_CALLED(iframe_onreadystatechange_complete);
 
     IHTMLFrameBase_Release(iframe);
 }
 
+static void test_imgload(IHTMLDocument2 *doc)
+{
+    IHTMLImgElement *img;
+    IHTMLElement *elem;
+    VARIANT v;
+    BSTR str;
+    HRESULT hres;
+
+    elem = get_elem_id(doc, "imgid");
+    hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLImgElement, (void**)&img);
+    IHTMLElement_Release(elem);
+    ok(hres == S_OK, "Could not get IHTMLImgElement iface: %08x\n", hres);
+
+    V_VT(&v) = VT_EMPTY;
+    hres = IHTMLImgElement_get_onload(img, &v);
+    ok(hres == S_OK, "get_onload failed: %08x\n", hres);
+    ok(V_VT(&v) == VT_NULL, "V_VT(onload) = %d\n", V_VT(&v));
+
+    V_VT(&v) = VT_DISPATCH;
+    V_DISPATCH(&v) = (IDispatch*)&img_onload_obj;
+    hres = IHTMLImgElement_put_onload(img, v);
+    ok(hres == S_OK, "put_onload failed: %08x\n", hres);
+
+    V_VT(&v) = VT_EMPTY;
+    hres = IHTMLImgElement_get_onload(img, &v);
+    ok(hres == S_OK, "get_onload failed: %08x\n", hres);
+    ok(V_VT(&v) == VT_DISPATCH, "V_VT(onload) = %d\n", V_VT(&v));
+    ok(V_DISPATCH(&v) == (IDispatch*)&img_onload_obj, "V_DISPATCH(onload) != onloadkFunc\n");
+    VariantClear(&v);
+
+    str = a2bstr("http://www.winehq.org/images/winehq_logo_text.png");
+    hres = IHTMLImgElement_put_src(img, str);
+    ok(hres == S_OK, "put_src failed: %08x\n", hres);
+    SysFreeString(str);
+
+    SET_EXPECT(img_onload);
+    pump_msgs(&called_img_onload);
+    CHECK_CALLED(img_onload);
+
+    IHTMLImgElement_Release(img);
+}
+
 static void test_timeout(IHTMLDocument2 *doc)
 {
     IHTMLWindow3 *win3;
@@ -1957,6 +2055,7 @@ START_TEST(events)
     run_test(empty_doc_str, test_timeout);
     run_test(click_doc_str, test_onclick);
     run_test(readystate_doc_str, test_onreadystatechange);
+    run_test(img_doc_str, test_imgload);
 
     DestroyWindow(container_hwnd);
     CoUninitialize();
index 72ef427..6192f81 100644 (file)
@@ -5,12 +5,30 @@ function ok(b,m) {
     return external.ok(b, m);
 }
 
+function test_removeAttribute(e) {
+    ok(e.removeAttribute('nonexisting') === false, "removeAttribute('nonexisting') didn't return false");
+
+    e.title = "title";
+    ok(e.removeAttribute('title') === true, "removeAttribute('title') didn't return true");
+    ok(e.title === "", "e.title = " + e.title);
+    ok(("title" in e) === true, "title is not in e");
+
+    e["myattr"] = "test";
+    ok(e.removeAttribute('myattr') === true, "removeAttribute('myattr') didn't return true");
+    ok(e["myattr"] === undefined, "e['myattr'] = " + e['myattr']);
+    ok(("myattr" in e) === false, "myattr is in e");
+
+}
+
 function runTest() {
     obj = new Object();
     ok(obj === window.obj, "obj !== window.obj");
 
     ok(typeof(divid) === "object", "typeof(divid) = " + typeof(divid));
 
+    test_removeAttribute(document.getElementById("divid"));
+    test_removeAttribute(document.body);
+
     external.reportSuccess();
 }
 </script>
index 6a0cbe3..56d83ef 100644 (file)
@@ -1050,12 +1050,22 @@ static HRESULT QueryInterface(REFIID riid, void **ppv)
 static IHTMLDocument2 *create_document(void)
 {
     IHTMLDocument2 *doc;
+    IHTMLDocument5 *doc5;
     HRESULT hres;
 
     hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
             &IID_IHTMLDocument2, (void**)&doc);
     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
+    if (hres != S_OK) return NULL;
 
+    hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument5, (void**)&doc5);
+    if(FAILED(hres)) {
+        win_skip("Could not get IHTMLDocument5, probably too old IE\n");
+        IHTMLDocument2_Release(doc);
+        return NULL;
+    }
+
+    IHTMLDocument5_Release(doc5);
     return doc;
 }
 
index 5f06d93..a743e51 100644 (file)
@@ -535,6 +535,7 @@ static void test_domdoc( void )
     BSTR str;
     LONG code;
     LONG nLength = 0;
+    WCHAR buff[100];
 
     r = CoCreateInstance( &CLSID_DOMDocument, NULL, 
         CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc );
@@ -543,6 +544,12 @@ static void test_domdoc( void )
 
     test_disp((IUnknown*)doc);
 
+if (0)
+{
+    /* crashes on native */
+    r = IXMLDOMDocument_loadXML( doc, (BSTR)0x1, NULL );
+}
+
     /* try some stupid things */
     r = IXMLDOMDocument_loadXML( doc, NULL, NULL );
     ok( r == S_FALSE, "loadXML failed\n");
@@ -601,6 +608,15 @@ static void test_domdoc( void )
     ok( r == S_FALSE, "should be no document element\n");
     ok( element == NULL, "Element should be NULL\n");
 
+    /* test for BSTR handling, pass broken BSTR */
+    memcpy(&buff[2], szComplete1, sizeof(szComplete1));
+    /* just a big length */
+    *(DWORD*)buff = 0xf0f0;
+    b = VARIANT_FALSE;
+    r = IXMLDOMDocument_loadXML( doc, &buff[2], &b );
+    ok( r == S_OK, "loadXML failed\n");
+    ok( b == VARIANT_TRUE, "failed to load XML string\n");
+
     /* try to load something valid */
     b = VARIANT_FALSE;
     str = SysAllocString( szComplete1 );
@@ -2734,6 +2750,12 @@ static void test_XMLHTTP(void)
     SysFreeString(str2);
 
     hr = IXMLHttpRequest_send(pXMLHttpRequest, varbody);
+    if (hr == INET_E_RESOURCE_NOT_FOUND)
+    {
+        skip("No connection could be made with crossover.codeweavers.com\n");
+        IXMLHttpRequest_Release(pXMLHttpRequest);
+        return;
+    }
     todo_wine ok(hr == S_OK, "IXMLHttpRequest_send should have succeeded instead of failing with 0x%08x\n", hr);
     VariantClear(&varbody);
 
index 83ec872..cb560f2 100644 (file)
@@ -128,16 +128,28 @@ static int init_base_environment(DWORD dwKeyFlags)
     hProv = (HCRYPTPROV)INVALID_HANDLE_VALUE;
 
     result = CryptAcquireContext(&hProv, szContainer, szProvider, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
-    ok(!result && GetLastError()==NTE_BAD_FLAGS, "%d, %08x\n", result, GetLastError());
+    ok(!result && (GetLastError()==NTE_BAD_FLAGS ||
+       broken(GetLastError() == NTE_KEYSET_NOT_DEF /* Win9x/NT4 */)),
+       "%d, %08x\n", result, GetLastError());
     
     if (!CryptAcquireContext(&hProv, szContainer, szProvider, PROV_RSA_FULL, 0))
     {
-        ok(GetLastError()==NTE_BAD_KEYSET, "%08x\n", GetLastError());
-        if (GetLastError()!=NTE_BAD_KEYSET) return 0;
+        ok(GetLastError()==NTE_BAD_KEYSET ||
+           broken(GetLastError() == NTE_KEYSET_NOT_DEF /* Win9x/NT4 */),
+           "%08x\n", GetLastError());
+        if (GetLastError()!=NTE_BAD_KEYSET)
+        {
+            win_skip("RSA full provider not available\n");
+            return 0;
+        }
         result = CryptAcquireContext(&hProv, szContainer, szProvider, PROV_RSA_FULL, 
                                      CRYPT_NEWKEYSET);
         ok(result, "%08x\n", GetLastError());
-        if (!result) return 0;
+        if (!result)
+        {
+            win_skip("Couldn't create crypto provider\n");
+            return 0;
+        }
         result = CryptGenKey(hProv, AT_KEYEXCHANGE, dwKeyFlags, &hKey);
         ok(result, "%08x\n", GetLastError());
         if (result) CryptDestroyKey(hKey);
@@ -275,7 +287,6 @@ static BOOL derive_key(ALG_ID aiAlgid, HCRYPTKEY *phKey, DWORD len)
         return FALSE;
     } 
     ok(result, "%08x\n", GetLastError());
-    if (!result) return FALSE;
     result = CryptHashData(hHash, pbData, sizeof(pbData), 0);
     ok(result, "%08x\n", GetLastError());
     if (!result) return FALSE;
@@ -309,8 +320,9 @@ static void test_hashes(void)
     unsigned char pbData[2048];
     BOOL result;
     HCRYPTHASH hHash, hHashClone;
+    HCRYPTPROV prov;
     BYTE pbHashValue[36];
-    DWORD hashlen, len;
+    DWORD hashlen, len, error;
     int i;
 
     for (i=0; i<2048; i++) pbData[i] = (unsigned char)i;
@@ -441,6 +453,74 @@ static void test_hashes(void)
 
     result = CryptDestroyHash(hHash);
     ok(result, "%08x\n", GetLastError());
+
+    /* The SHA-2 variants aren't supported in the RSA full provider */
+    result = CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash);
+    ok(!result && GetLastError() == NTE_BAD_ALGID,
+       "expected NTE_BAD_ALGID, got %08x\n", GetLastError());
+    result = CryptCreateHash(hProv, CALG_SHA_384, 0, 0, &hHash);
+    ok(!result && GetLastError() == NTE_BAD_ALGID,
+       "expected NTE_BAD_ALGID, got %08x\n", GetLastError());
+    result = CryptCreateHash(hProv, CALG_SHA_512, 0, 0, &hHash);
+    ok(!result && GetLastError() == NTE_BAD_ALGID,
+       "expected NTE_BAD_ALGID, got %08x\n", GetLastError());
+
+    result = CryptAcquireContextA(&prov, NULL, szProvider, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+    ok(result, "CryptAcquireContext failed 0x%08x\n", GetLastError());
+
+    result = CryptCreateHash(prov, CALG_SHA1, 0, 0, &hHash);
+    ok(result, "CryptCreateHash failed 0x%08x\n", GetLastError());
+
+    /* release provider before using the hash */
+    result = CryptReleaseContext(prov, 0);
+    ok(result, "CryptReleaseContext failed 0x%08x\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    result = CryptHashData(hHash, (const BYTE *)"data", sizeof("data"), 0);
+    error = GetLastError();
+    ok(!result, "CryptHashData succeeded\n");
+    ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", error);
+
+    SetLastError(0xdeadbeef);
+    result = CryptDestroyHash(hHash);
+    error = GetLastError();
+    ok(!result, "CryptDestroyHash succeeded\n");
+    ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", error);
+
+    if (!pCryptDuplicateHash)
+    {
+        win_skip("CryptDuplicateHash is not available\n");
+        return;
+    }
+
+    result = CryptAcquireContextA(&prov, NULL, szProvider, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+    ok(result, "CryptAcquireContext failed 0x%08x\n", GetLastError());
+
+    result = CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash);
+    ok(result, "CryptCreateHash failed 0x%08x\n", GetLastError());
+
+    result = CryptHashData(hHash, (const BYTE *)"data", sizeof("data"), 0);
+    ok(result, "CryptHashData failed 0x%08x\n", GetLastError());
+
+    result = pCryptDuplicateHash(hHash, NULL, 0, &hHashClone);
+    ok(result, "CryptDuplicateHash failed 0x%08x\n", GetLastError());
+
+    len = 20;
+    result = CryptGetHashParam(hHashClone, HP_HASHVAL, pbHashValue, &len, 0);
+    ok(result, "CryptGetHashParam failed 0x%08x\n", GetLastError());
+
+    /* add data after duplicating the hash */
+    result = CryptHashData(hHash, (const BYTE *)"more data", sizeof("more data"), 0);
+    ok(result, "CryptHashData failed 0x%08x\n", GetLastError());
+
+    result = CryptDestroyHash(hHash);
+    ok(result, "CryptDestroyHash failed 0x%08x\n", GetLastError());
+
+    result = CryptDestroyHash(hHashClone);
+    ok(result, "CryptDestroyHash failed 0x%08x\n", GetLastError());
+
+    result = CryptReleaseContext(prov, 0);
+    ok(result, "CryptReleaseContext failed 0x%08x\n", GetLastError());
 }
 
 static void test_block_cipher_modes(void)
@@ -471,6 +551,10 @@ static void test_block_cipher_modes(void)
     result = CryptSetKeyParam(hKey, KP_MODE, (BYTE*)&dwMode, 0);
     ok(result, "%08x\n", GetLastError());
 
+    result = CryptGetKeyParam(hKey, KP_SALT, NULL, &dwLen, 0);
+    ok(result, "%08x\n", GetLastError());
+    ok(dwLen == 11 || broken(dwLen == 0 /* Win9x/NT4 */), "unexpected salt length %d\n", dwLen);
+
     dwLen = 23;
     result = CryptEncrypt(hKey, 0, TRUE, 0, NULL, &dwLen, 24);
     ok(result, "CryptEncrypt failed: %08x\n", GetLastError());
@@ -716,6 +800,11 @@ static void test_aes(int keylen)
 
     for (i=0; i<sizeof(pbData); i++) pbData[i] = (unsigned char)i;
 
+    /* AES provider doesn't support salt */
+    result = CryptGetKeyParam(hKey, KP_SALT, NULL, &dwLen, 0);
+    ok(!result && (GetLastError() == NTE_BAD_KEY || GetLastError() == ERROR_NO_TOKEN /* Win7 */),
+       "expected NTE_BAD_KEY or ERROR_NO_TOKEN, got %08x\n", GetLastError());
+
     dwLen = 13;
     result = CryptEncrypt(hKey, 0, TRUE, 0, pbData, &dwLen, 16);
     ok(result, "%08x\n", GetLastError());
@@ -747,6 +836,108 @@ static void test_aes(int keylen)
     ok(result, "%08x\n", GetLastError());
 }
 
+static void test_sha2(void)
+{
+    static const unsigned char sha256hash[32] = {
+        0x10, 0xfc, 0x3c, 0x51, 0xa1, 0x52, 0xe9, 0x0e, 0x5b, 0x90,
+        0x31, 0x9b, 0x60, 0x1d, 0x92, 0xcc, 0xf3, 0x72, 0x90, 0xef,
+        0x53, 0xc3, 0x5f, 0xf9, 0x25, 0x07, 0x68, 0x7d, 0x8a, 0x91,
+        0x1a, 0x08
+    };
+    static const unsigned char sha384hash[48] = {
+        0x98, 0xd3, 0x3f, 0x89, 0x0b, 0x23, 0x33, 0x44, 0x61, 0x32,
+        0x5a, 0x7c, 0xa3, 0x03, 0x89, 0xb5, 0x11, 0xd7, 0x41, 0xc8,
+        0x54, 0x6b, 0x12, 0x0c, 0x40, 0x15, 0xb6, 0x2a, 0x03, 0x43,
+        0xe5, 0x64, 0x7f, 0x10, 0x1e, 0xae, 0x47, 0xa9, 0x39, 0x05,
+        0x6f, 0x40, 0x60, 0x94, 0xd6, 0xad, 0x80, 0x55
+    };
+    static const unsigned char sha512hash[64] = {
+        0x37, 0x86, 0x0e, 0x7d, 0x25, 0xd9, 0xf9, 0x84, 0x3e, 0x3d,
+        0xc7, 0x13, 0x95, 0x73, 0x42, 0x04, 0xfd, 0x13, 0xad, 0x23,
+        0x39, 0x16, 0x32, 0x5f, 0x99, 0x3e, 0x3c, 0xee, 0x3f, 0x11,
+        0x36, 0xf9, 0xc9, 0x66, 0x08, 0x70, 0xcc, 0x49, 0xd8, 0xe0,
+        0x7d, 0xa1, 0x57, 0x62, 0x71, 0xa6, 0xc9, 0xa4, 0x24, 0x60,
+        0xfc, 0xde, 0x9d, 0xb2, 0xf1, 0xd2, 0xc2, 0xfb, 0x2d, 0xbf,
+        0xb7, 0xf4, 0x81, 0xd4
+    };
+    unsigned char pbData[2048];
+    BOOL result;
+    HCRYPTHASH hHash;
+    BYTE pbHashValue[64];
+    DWORD hashlen, len;
+    int i;
+
+    for (i=0; i<2048; i++) pbData[i] = (unsigned char)i;
+
+    /* SHA-256 hash */
+    SetLastError(0xdeadbeef);
+    result = CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash);
+    if (!result && GetLastError() == NTE_BAD_ALGID) {
+        win_skip("SHA-256/384/512 hashes are not supported before Windows XP SP3\n");
+        return;
+    }
+    ok(result, "%08x\n", GetLastError());
+    if (result) {
+        len = sizeof(DWORD);
+        result = CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashlen, &len, 0);
+        ok(result && (hashlen == 32), "%08x, hashlen: %d\n", GetLastError(), hashlen);
+
+        result = CryptHashData(hHash, pbData, sizeof(pbData), 0);
+        ok(result, "%08x\n", GetLastError());
+
+        len = 32;
+        result = CryptGetHashParam(hHash, HP_HASHVAL, pbHashValue, &len, 0);
+        ok(result, "%08x\n", GetLastError());
+
+        ok(!memcmp(pbHashValue, sha256hash, 32), "Wrong SHA-256 hash!\n");
+
+        result = CryptDestroyHash(hHash);
+        ok(result, "%08x\n", GetLastError());
+    }
+
+    /* SHA-384 hash */
+    result = CryptCreateHash(hProv, CALG_SHA_384, 0, 0, &hHash);
+    ok(result, "%08x\n", GetLastError());
+    if (result) {
+        len = sizeof(DWORD);
+        result = CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashlen, &len, 0);
+        ok(result && (hashlen == 48), "%08x, hashlen: %d\n", GetLastError(), hashlen);
+
+        result = CryptHashData(hHash, pbData, sizeof(pbData), 0);
+        ok(result, "%08x\n", GetLastError());
+
+        len = 48;
+        result = CryptGetHashParam(hHash, HP_HASHVAL, pbHashValue, &len, 0);
+        ok(result, "%08x\n", GetLastError());
+
+        ok(!memcmp(pbHashValue, sha384hash, 48), "Wrong SHA-384 hash!\n");
+
+        result = CryptDestroyHash(hHash);
+        ok(result, "%08x\n", GetLastError());
+    }
+
+    /* SHA-512 hash */
+    result = CryptCreateHash(hProv, CALG_SHA_512, 0, 0, &hHash);
+    ok(result, "%08x\n", GetLastError());
+    if (result) {
+        len = sizeof(DWORD);
+        result = CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashlen, &len, 0);
+        ok(result && (hashlen == 64), "%08x, hashlen: %d\n", GetLastError(), hashlen);
+
+        result = CryptHashData(hHash, pbData, sizeof(pbData), 0);
+        ok(result, "%08x\n", GetLastError());
+
+        len = 64;
+        result = CryptGetHashParam(hHash, HP_HASHVAL, pbHashValue, &len, 0);
+        ok(result, "%08x\n", GetLastError());
+
+        ok(!memcmp(pbHashValue, sha512hash, 64), "Wrong SHA-512 hash!\n");
+
+        result = CryptDestroyHash(hHash);
+        ok(result, "%08x\n", GetLastError());
+    }
+}
+
 static void test_rc2(void)
 {
     static const BYTE rc2_40_encrypted[16] = {
@@ -820,8 +1011,13 @@ static void test_rc2(void)
 
         result = CryptGetKeyParam(hKey, KP_SALT, NULL, &dwLen, 0);
         ok(result, "%08x\n", GetLastError());
+        /* The default salt length is always 11... */
+        ok(dwLen == 11, "unexpected salt length %d\n", dwLen);
+        /* and the default salt is always empty. */
         pbTemp = HeapAlloc(GetProcessHeap(), 0, dwLen);
         CryptGetKeyParam(hKey, KP_SALT, pbTemp, &dwLen, 0);
+        for (i=0; i<dwLen; i++)
+            ok(!pbTemp[i], "unexpected salt value %02x @ %d\n", pbTemp[i], i);
         HeapFree(GetProcessHeap(), 0, pbTemp);
 
         dwLen = sizeof(DWORD);
@@ -845,6 +1041,16 @@ static void test_rc2(void)
         result = CryptDecrypt(hKey, 0, TRUE, 0, pbData, &dwDataLen);
         ok(result, "%08x\n", GetLastError());
 
+        /* Setting the salt also succeeds... */
+        result = CryptSetKeyParam(hKey, KP_SALT, pbData, 0);
+        ok(result, "setting salt failed: %08x\n", GetLastError());
+        /* but the resulting salt length is now zero? */
+        dwLen = 0;
+        result = CryptGetKeyParam(hKey, KP_SALT, NULL, &dwLen, 0);
+        ok(result, "%08x\n", GetLastError());
+        ok(dwLen == 0 ||
+           broken(dwLen == 11), /* Win9x/WinMe/NT4 */
+           "unexpected salt length %d\n", dwLen);
         /* What sizes salt can I set? */
         salt.pbData = pbData;
         for (i=0; i<24; i++)
@@ -852,6 +1058,10 @@ static void test_rc2(void)
             salt.cbData = i;
             result = CryptSetKeyParam(hKey, KP_SALT_EX, (BYTE *)&salt, 0);
             ok(result, "setting salt failed for size %d: %08x\n", i, GetLastError());
+            /* The returned salt length is the same as the set salt length */
+            result = CryptGetKeyParam(hKey, KP_SALT, NULL, &dwLen, 0);
+            ok(result, "%08x\n", GetLastError());
+            ok(dwLen == i, "size %d: unexpected salt length %d\n", i, dwLen);
         }
         salt.cbData = 25;
         SetLastError(0xdeadbeef);
@@ -999,6 +1209,16 @@ static void test_rc4(void)
         result = CryptDecrypt(hKey, 0, TRUE, 0, pbData, &dwDataLen);
         ok(result, "%08x\n", GetLastError());
 
+        /* Setting the salt also succeeds... */
+        result = CryptSetKeyParam(hKey, KP_SALT, pbData, 0);
+        ok(result, "setting salt failed: %08x\n", GetLastError());
+        /* but the resulting salt length is now zero? */
+        dwLen = 0;
+        result = CryptGetKeyParam(hKey, KP_SALT, NULL, &dwLen, 0);
+        ok(result, "%08x\n", GetLastError());
+        ok(dwLen == 0 ||
+           broken(dwLen == 11), /* Win9x/WinMe/NT4 */
+           "unexpected salt length %d\n", dwLen);
         /* What sizes salt can I set? */
         salt.pbData = pbData;
         for (i=0; i<24; i++)
@@ -1006,6 +1226,10 @@ static void test_rc4(void)
             salt.cbData = i;
             result = CryptSetKeyParam(hKey, KP_SALT_EX, (BYTE *)&salt, 0);
             ok(result, "setting salt failed for size %d: %08x\n", i, GetLastError());
+            /* The returned salt length is the same as the set salt length */
+            result = CryptGetKeyParam(hKey, KP_SALT, NULL, &dwLen, 0);
+            ok(result, "%08x\n", GetLastError());
+            ok(dwLen == i, "size %d: unexpected salt length %d\n", i, dwLen);
         }
         salt.cbData = 25;
         SetLastError(0xdeadbeef);
@@ -1577,6 +1801,11 @@ static void test_rsa_encrypt(void)
         "expected CRYPT_MAC|CRYPT_WRITE|CRYPT_READ|CRYPT_DECRYPT|CRYPT_ENCRYPT,"
         " got %08x\n", dwVal);
 
+    /* An RSA key doesn't support salt */
+    result = CryptGetKeyParam(hRSAKey, KP_SALT, NULL, &dwLen, 0);
+    ok(!result && GetLastError() == NTE_BAD_KEY,
+       "expected NTE_BAD_KEY, got %08x\n", GetLastError());
+
     /* The key exchange key's public key may be exported.. */
     result = CryptExportKey(hRSAKey, 0, PUBLICKEYBLOB, 0, NULL, &dwLen);
     ok(result, "%08x\n", GetLastError());
@@ -2570,5 +2799,6 @@ START_TEST(rsaenh)
     test_aes(128);
     test_aes(192);
     test_aes(256);
+    test_sha2();
     clean_up_aes_environment();
 }
index d05275f..b576848 100644 (file)
     SetContextAttributes)
 #define SECPKG_FUNCTION_TABLE_SIZE_2 FIELD_OFFSET(SECPKG_FUNCTION_TABLE, \
     SetCredentialsAttributes)
-#define SECPKG_FUNCTION_TABLE_SIZE_3 sizeof(SECPKG_FUNCTION_TABLE)
+#define SECPKG_FUNCTION_TABLE_SIZE_3 FIELD_OFFSET(SECPKG_FUNCTION_TABLE, \
+    ChangeAccountPassword)
+#define SECPKG_FUNCTION_TABLE_SIZE_4 FIELD_OFFSET(SECPKG_FUNCTION_TABLE, \
+    QueryMetaData)
+#define SECPKG_FUNCTION_TABLE_SIZE_5 FIELD_OFFSET(SECPKG_FUNCTION_TABLE, \
+    ValidateTargetInfo)
+#define SECPKG_FUNCTION_TABLE_SIZE_6 sizeof(SECPKG_FUNCTION_TABLE)
 
 static NTSTATUS (NTAPI *pSpLsaModeInitialize)(ULONG, PULONG,
     PSECPKG_FUNCTION_TABLE*, PULONG);
@@ -121,6 +127,7 @@ static PSECPKG_FUNCTION_TABLE getNextSecPkgTable(PSECPKG_FUNCTION_TABLE pTable,
                                                  ULONG Version)
 {
     size_t size;
+    PSECPKG_FUNCTION_TABLE pNextTable;
 
     if (Version == SECPKG_INTERFACE_VERSION)
         size = SECPKG_FUNCTION_TABLE_SIZE_1;
@@ -128,12 +135,32 @@ static PSECPKG_FUNCTION_TABLE getNextSecPkgTable(PSECPKG_FUNCTION_TABLE pTable,
         size = SECPKG_FUNCTION_TABLE_SIZE_2;
     else if (Version == SECPKG_INTERFACE_VERSION_3)
         size = SECPKG_FUNCTION_TABLE_SIZE_3;
+    else if (Version == SECPKG_INTERFACE_VERSION_4)
+        size = SECPKG_FUNCTION_TABLE_SIZE_4;
+    else if (Version == SECPKG_INTERFACE_VERSION_5)
+        size = SECPKG_FUNCTION_TABLE_SIZE_5;
+    else if (Version == SECPKG_INTERFACE_VERSION_6)
+        size = SECPKG_FUNCTION_TABLE_SIZE_6;
     else {
         ok(FALSE, "Unknown package version 0x%x\n", Version);
         return NULL;
     }
 
-    return (PSECPKG_FUNCTION_TABLE)((PBYTE)pTable + size);
+    pNextTable = (PSECPKG_FUNCTION_TABLE)((PBYTE)pTable + size);
+    /* Win7 function tables appear to be SECPKG_INTERFACE_VERSION_6 format,
+       but unfortunately SpLsaModeInitialize returns SECPKG_INTERFACE_VERSION_3.
+       We detect that by comparing the "Initialize" pointer from the old table
+       to the "FreeCredentialsHandle" pointer of the new table. These functions
+       have different numbers of arguments, so they can't possibly point to the
+       same implementation */
+    if (broken((void *) pTable->Initialize == (void *) pNextTable->FreeCredentialsHandle &&
+               pNextTable->FreeCredentialsHandle != NULL))
+    {
+        win_skip("Invalid function pointers for next package\n");
+        return NULL;
+    }
+
+    return pNextTable;
 }
 
 static void testGetInfo(void)
@@ -181,7 +208,9 @@ static void testGetInfo(void)
            PackageInfo.fCapabilities);
         ok(PackageInfo.wVersion == 1, "wVersion: %d\n", PackageInfo.wVersion);
         ok(PackageInfo.wRPCID == 14, "wRPCID: %d\n", PackageInfo.wRPCID);
-        ok(PackageInfo.cbMaxToken == 0x4000, "cbMaxToken: 0x%x\n",
+        ok(PackageInfo.cbMaxToken == 0x4000 ||
+           PackageInfo.cbMaxToken == 0x6000, /* Win7 */
+           "cbMaxToken: 0x%x\n",
            PackageInfo.cbMaxToken);
     }
 }
index db44d27..e5e0896 100755 (executable)
  * Test helper macros
  */
 
-#ifdef _WIN64
+#define TEST_TYPE_SIZE(type, size)             C_ASSERT(sizeof(type) == size);
 
-# define TEST_TYPE_SIZE(type, size)
+#ifdef TYPE_ALIGNMENT
+# define TEST_TYPE_ALIGN(type, align)          C_ASSERT(TYPE_ALIGNMENT(type) == align);
+#else
 # define TEST_TYPE_ALIGN(type, align)
+#endif
+
+#ifdef _TYPE_ALIGNMENT
+# define TEST_TARGET_ALIGN(type, align)        C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align);
+# define TEST_FIELD_ALIGN(type, field, align)  C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align);
+#else
 # define TEST_TARGET_ALIGN(type, align)
 # define TEST_FIELD_ALIGN(type, field, align)
-# define TEST_FIELD_OFFSET(type, field, offset)
+#endif
 
-#else
+#define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset);
 
-# define TEST_TYPE_SIZE(type, size)             C_ASSERT(sizeof(type) == size);
+#define TEST_TARGET_SIZE(type, size)            TEST_TYPE_SIZE(*(type)0, size)
+#define TEST_FIELD_SIZE(type, field, size)      TEST_TYPE_SIZE((((type*)0)->field), size)
+#define TEST_TYPE_SIGNED(type)                  C_ASSERT((type) -1 < 0);
+#define TEST_TYPE_UNSIGNED(type)                C_ASSERT((type) -1 > 0);
 
-# ifdef TYPE_ALIGNMENT
-#  define TEST_TYPE_ALIGN(type, align)          C_ASSERT(TYPE_ALIGNMENT(type) == align);
-# else
-#  define TEST_TYPE_ALIGN(type, align)
-# endif
 
-# ifdef _TYPE_ALIGNMENT
-#  define TEST_TARGET_ALIGN(type, align)        C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align);
-#  define TEST_FIELD_ALIGN(type, field, align)  C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align);
-# else
-#  define TEST_TARGET_ALIGN(type, align)
-#  define TEST_FIELD_ALIGN(type, field, align)
-# endif
+#ifdef _WIN64
 
-# define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset);
+static void test_pack_ASSOCF(void)
+{
+    /* ASSOCF */
+    TEST_TYPE_SIZE   (ASSOCF, 4)
+    TEST_TYPE_ALIGN  (ASSOCF, 4)
+    TEST_TYPE_UNSIGNED(ASSOCF)
+}
 
-#endif
+static void test_pack_DLLGETVERSIONPROC(void)
+{
+    /* DLLGETVERSIONPROC */
+    TEST_TYPE_SIZE   (DLLGETVERSIONPROC, 8)
+    TEST_TYPE_ALIGN  (DLLGETVERSIONPROC, 8)
+}
 
-#define TEST_TARGET_SIZE(type, size)            TEST_TYPE_SIZE(*(type)0, size)
-#define TEST_FIELD_SIZE(type, field, size)      TEST_TYPE_SIZE((((type*)0)->field), size)
-#define TEST_TYPE_SIGNED(type)                  C_ASSERT((type) -1 < 0);
-#define TEST_TYPE_UNSIGNED(type)                C_ASSERT((type) -1 > 0);
+static void test_pack_DLLVERSIONINFO(void)
+{
+    /* DLLVERSIONINFO (pack 8) */
+    TEST_TYPE_SIZE   (DLLVERSIONINFO, 20)
+    TEST_TYPE_ALIGN  (DLLVERSIONINFO, 4)
+    TEST_FIELD_SIZE  (DLLVERSIONINFO, cbSize, 4)
+    TEST_FIELD_ALIGN (DLLVERSIONINFO, cbSize, 4)
+    TEST_FIELD_OFFSET(DLLVERSIONINFO, cbSize, 0)
+    TEST_FIELD_SIZE  (DLLVERSIONINFO, dwMajorVersion, 4)
+    TEST_FIELD_ALIGN (DLLVERSIONINFO, dwMajorVersion, 4)
+    TEST_FIELD_OFFSET(DLLVERSIONINFO, dwMajorVersion, 4)
+    TEST_FIELD_SIZE  (DLLVERSIONINFO, dwMinorVersion, 4)
+    TEST_FIELD_ALIGN (DLLVERSIONINFO, dwMinorVersion, 4)
+    TEST_FIELD_OFFSET(DLLVERSIONINFO, dwMinorVersion, 8)
+    TEST_FIELD_SIZE  (DLLVERSIONINFO, dwBuildNumber, 4)
+    TEST_FIELD_ALIGN (DLLVERSIONINFO, dwBuildNumber, 4)
+    TEST_FIELD_OFFSET(DLLVERSIONINFO, dwBuildNumber, 12)
+    TEST_FIELD_SIZE  (DLLVERSIONINFO, dwPlatformID, 4)
+    TEST_FIELD_ALIGN (DLLVERSIONINFO, dwPlatformID, 4)
+    TEST_FIELD_OFFSET(DLLVERSIONINFO, dwPlatformID, 16)
+}
 
+static void test_pack_DLLVERSIONINFO2(void)
+{
+    /* DLLVERSIONINFO2 (pack 8) */
+    TEST_TYPE_SIZE   (DLLVERSIONINFO2, 32)
+    TEST_TYPE_ALIGN  (DLLVERSIONINFO2, 8)
+    TEST_FIELD_SIZE  (DLLVERSIONINFO2, info1, 20)
+    TEST_FIELD_ALIGN (DLLVERSIONINFO2, info1, 4)
+    TEST_FIELD_OFFSET(DLLVERSIONINFO2, info1, 0)
+    TEST_FIELD_SIZE  (DLLVERSIONINFO2, dwFlags, 4)
+    TEST_FIELD_ALIGN (DLLVERSIONINFO2, dwFlags, 4)
+    TEST_FIELD_OFFSET(DLLVERSIONINFO2, dwFlags, 20)
+    TEST_FIELD_SIZE  (DLLVERSIONINFO2, ullVersion, 8)
+    TEST_FIELD_ALIGN (DLLVERSIONINFO2, ullVersion, 8)
+    TEST_FIELD_OFFSET(DLLVERSIONINFO2, ullVersion, 24)
+}
+
+static void test_pack_HUSKEY(void)
+{
+    /* HUSKEY */
+    TEST_TYPE_SIZE   (HUSKEY, 8)
+    TEST_TYPE_ALIGN  (HUSKEY, 8)
+}
+
+static void test_pack_PHUSKEY(void)
+{
+    /* PHUSKEY */
+    TEST_TYPE_SIZE   (PHUSKEY, 8)
+    TEST_TYPE_ALIGN  (PHUSKEY, 8)
+    TEST_TARGET_SIZE (PHUSKEY, 8)
+    TEST_TARGET_ALIGN(PHUSKEY, 8)
+}
+
+#else /* _WIN64 */
 
 static void test_pack_ASSOCF(void)
 {
@@ -161,6 +222,8 @@ static void test_pack_PHUSKEY(void)
     TEST_TARGET_ALIGN(PHUSKEY, 4)
 }
 
+#endif /* _WIN64 */
+
 static void test_pack(void)
 {
     test_pack_ASSOCF();
@@ -173,9 +236,5 @@ static void test_pack(void)
 
 START_TEST(generated)
 {
-#ifdef _WIN64
-    ok(0, "The type size / alignment tests don't support Win64 yet\n");
-#else
     test_pack();
-#endif
 }
index 67d1fe2..4a36b3a 100644 (file)
@@ -208,12 +208,16 @@ static void test_SHCreateStreamOnFileA(DWORD mode, DWORD stgm)
     /* invalid arguments */
 
     stream = NULL;
-    /* NT: ERROR_PATH_NOT_FOUND, 9x: ERROR_BAD_PATHNAME */
     ret = (*pSHCreateStreamOnFileA)(NULL, mode | stgm, &stream);
-    ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) ||
-        ret == HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME),
-        "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)"
-        "or HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME), got 0x%08x\n", ret);
+    if (ret == E_INVALIDARG) /* Win98 SE */ {
+        win_skip("Not supported\n");
+        return;
+    }
+
+    ok(ret == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) /* NT */ ||
+       ret == HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME) /* 9x */,
+       "SHCreateStreamOnFileA: expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) "
+       "or HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME), got 0x%08x\n", ret);
     ok(stream == NULL, "SHCreateStreamOnFileA: expected a NULL IStream object, got %p\n", stream);
 
 #if 0 /* This test crashes on WinXP SP2 */
@@ -342,6 +346,11 @@ static void test_SHCreateStreamOnFileW(DWORD mode, DWORD stgm)
 
     stream = NULL;
     ret = (*pSHCreateStreamOnFileW)(test_file, mode | STGM_FAILIFTHERE | stgm, &stream);
+    if (ret == E_INVALIDARG) /* Win98 SE */ {
+        win_skip("Not supported\n");
+        return;
+    }
+
     ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "SHCreateStreamOnFileW: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got 0x%08x\n", ret);
     ok(stream == NULL, "SHCreateStreamOnFileW: expected a NULL IStream object, got %p\n", stream);
 
@@ -423,6 +432,11 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm)
 
     stream = NULL;
     ret = (*pSHCreateStreamOnFileEx)(test_file, mode, 0, FALSE, template, &stream);
+    if (ret == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) {
+        win_skip("File probably locked by Anti-Virus/Spam software, trying again\n");
+        Sleep(1000);
+        ret = (*pSHCreateStreamOnFileEx)(test_file, mode, 0, FALSE, template, &stream);
+    }
     ok( ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
         ret == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
         "SHCreateStreamOnFileEx: expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) or "
@@ -482,6 +496,11 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm)
 
     stream = NULL;
     ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream);
+    if (ret == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) {
+        win_skip("File probably locked by Anti-Virus/Spam software, trying again\n");
+        Sleep(1000);
+        ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, FALSE, NULL, &stream);
+    }
     ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
     ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
 
@@ -498,6 +517,11 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm)
 
     stream = NULL;
     ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream);
+    if (ret == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) {
+        win_skip("File probably locked by Anti-Virus/Spam software, trying again\n");
+        Sleep(1000);
+        ret = (*pSHCreateStreamOnFileEx)(test_file, mode | STGM_CREATE | stgm, 0, TRUE, NULL, &stream);
+    }
     ok(ret == S_OK, "SHCreateStreamOnFileEx: expected S_OK, got 0x%08x\n", ret);
     ok(stream != NULL, "SHCreateStreamOnFileEx: expected a valid IStream object, got NULL\n");
 
index 22437e2..cfc25e1 100755 (executable)
 #include "oaidl.h"
 #include "ocidl.h"
 #include "mlang.h"
+#include "shlwapi.h"
+#include "docobj.h"
+#include "shobjidl.h"
 
 /* Function ptrs for ordinal calls */
 static HMODULE hShlwapi;
+static BOOL is_win2k_and_lower;
+
 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int);
 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD);
 
@@ -43,6 +48,14 @@ static HRESULT(WINAPI *pIConnectionPoint_SimpleInvoke)(IConnectionPoint*,DISPID,
 static HRESULT(WINAPI *pIConnectionPoint_InvokeWithCancel)(IConnectionPoint*,DISPID,DISPPARAMS*,DWORD,DWORD);
 static HRESULT(WINAPI *pConnectToConnectionPoint)(IUnknown*,REFIID,BOOL,IUnknown*, LPDWORD,IConnectionPoint **);
 static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG);
+static LONG   (WINAPI *pSHSetWindowBits)(HWND, INT, UINT, UINT);
+static INT    (WINAPI *pSHFormatDateTimeA)(const FILETIME UNALIGNED*, DWORD*, LPSTR, UINT);
+static INT    (WINAPI *pSHFormatDateTimeW)(const FILETIME UNALIGNED*, DWORD*, LPWSTR, UINT);
+static DWORD  (WINAPI *pSHGetObjectCompatFlags)(IUnknown*, const CLSID*);
+static BOOL   (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *);
+static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*);
+static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*);
+static HWND    (WINAPI *pSHCreateWorkerWindowA)(LONG, HWND, DWORD, DWORD, HMENU, LONG_PTR);
 
 static HMODULE hmlang;
 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
@@ -55,6 +68,79 @@ static const CHAR ie_international[] = {
 static const CHAR acceptlanguage[] = {
     'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
 
+typedef struct {
+    int id;
+    const void *args[5];
+} call_entry_t;
+
+typedef struct {
+    call_entry_t *calls;
+    int count;
+    int alloc;
+} call_trace_t;
+
+static void init_call_trace(call_trace_t *ctrace)
+{
+    ctrace->alloc = 10;
+    ctrace->count = 0;
+    ctrace->calls = HeapAlloc(GetProcessHeap(), 0, sizeof(call_entry_t) * ctrace->alloc);
+}
+
+static void free_call_trace(const call_trace_t *ctrace)
+{
+    HeapFree(GetProcessHeap(), 0, ctrace->calls);
+}
+
+static void add_call(call_trace_t *ctrace, int id, const void *arg0,
+    const void *arg1, const void *arg2, const void *arg3, const void *arg4)
+{
+    call_entry_t call;
+
+    call.id = id;
+    call.args[0] = arg0;
+    call.args[1] = arg1;
+    call.args[2] = arg2;
+    call.args[3] = arg3;
+    call.args[4] = arg4;
+
+    if (ctrace->count == ctrace->alloc)
+    {
+        ctrace->alloc *= 2;
+        ctrace->calls = HeapReAlloc(GetProcessHeap(),0, ctrace->calls, ctrace->alloc*sizeof(call_entry_t));
+    }
+
+    ctrace->calls[ctrace->count++] = call;
+}
+
+static void ok_trace_(call_trace_t *texpected, call_trace_t *tgot, int line)
+{
+    if (texpected->count == tgot->count)
+    {
+        INT i;
+        /* compare */
+        for (i = 0; i < texpected->count; i++)
+        {
+            call_entry_t *expected = &texpected->calls[i];
+            call_entry_t *got = &tgot->calls[i];
+            INT j;
+
+            ok_(__FILE__, line)(expected->id == got->id, "got different ids %d: %d, %d\n", i+1, expected->id, got->id);
+
+            for (j = 0; j < 5; j++)
+            {
+                ok_(__FILE__, line)(expected->args[j] == got->args[j], "got different args[%d] for %d: %p, %p\n", j, i+1,
+                   expected->args[j], got->args[j]);
+            }
+        }
+    }
+    else
+        ok_(__FILE__, line)(0, "traces length mismatch\n");
+}
+
+#define ok_trace(a, b) ok_trace_(a, b, __LINE__)
+
+/* trace of actually made calls */
+static call_trace_t trace_got;
 
 static void test_GetAcceptLanguagesA(void)
 {
@@ -180,7 +266,7 @@ static void test_GetAcceptLanguagesA(void)
         /* There is no space for the string in the registry.
            When the buffer is large enough, the default language is returned
 
-           When the buffer is to small for that fallback, win7_32 and w2k8_64
+           When the buffer is too small for that fallback, win7_32 and w2k8_64
            and above fail with HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), but
            recent os succeed and return a partial result while
            older os succeed and overflow the buffer */
@@ -248,7 +334,7 @@ static void test_GetAcceptLanguagesA(void)
     memset(buffer, '#', maxlen);
     buffer[maxlen] = 0;
     hr = pGetAcceptLanguagesA( buffer, &len);
-    /* When the buffer is to small, win7_32 and w2k8_64 and above fail with
+    /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
        HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), other versions suceed
        and return a partial 0 terminated result while other versions
        fail with E_INVALIDARG and return a partial unterminated result */
@@ -1397,31 +1483,940 @@ static void test_SHPropertyBag_ReadLONG(void)
     IUnknown_Release((IUnknown*)pb);
 }
 
+
+
+static void test_SHSetWindowBits(void)
+{
+    HWND hwnd;
+    DWORD style, styleold;
+    WNDCLASSA clsA;
+
+    if(!pSHSetWindowBits)
+    {
+        win_skip("SHSetWindowBits is not available\n");
+        return;
+    }
+
+    clsA.style = 0;
+    clsA.lpfnWndProc = DefWindowProcA;
+    clsA.cbClsExtra = 0;
+    clsA.cbWndExtra = 0;
+    clsA.hInstance = GetModuleHandleA(NULL);
+    clsA.hIcon = 0;
+    clsA.hCursor = LoadCursorA(0, IDC_ARROW);
+    clsA.hbrBackground = NULL;
+    clsA.lpszMenuName = NULL;
+    clsA.lpszClassName = "Shlwapi test class";
+    RegisterClassA(&clsA);
+
+    hwnd = CreateWindowA("Shlwapi test class", "Test", WS_VISIBLE, 0, 0, 100, 100,
+                          NULL, NULL, GetModuleHandle(NULL), 0);
+    ok(IsWindow(hwnd), "failed to create window\n");
+
+    /* null window */
+    SetLastError(0xdeadbeef);
+    style = pSHSetWindowBits(NULL, GWL_STYLE, 0, 0);
+    ok(style == 0, "expected 0 retval, got %d\n", style);
+    ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
+        broken(GetLastError() == 0xdeadbeef), /* Win9x/WinMe */
+        "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
+
+    /* zero mask, zero flags */
+    styleold = GetWindowLongA(hwnd, GWL_STYLE);
+    style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, 0);
+    ok(styleold == style, "expected old style\n");
+    ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
+
+    /* test mask */
+    styleold = GetWindowLongA(hwnd, GWL_STYLE);
+    ok(styleold & WS_VISIBLE, "expected WS_VISIBLE\n");
+    style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
+
+    ok(style == styleold, "expected previous style, got %x\n", style);
+    ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
+
+    /* test mask, unset style bit used */
+    styleold = GetWindowLongA(hwnd, GWL_STYLE);
+    style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
+    ok(style == styleold, "expected previous style, got %x\n", style);
+    ok(styleold == GetWindowLongA(hwnd, GWL_STYLE), "expected to keep old style\n");
+
+    /* set back with flags */
+    styleold = GetWindowLongA(hwnd, GWL_STYLE);
+    style = pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, WS_VISIBLE);
+    ok(style == styleold, "expected previous style, got %x\n", style);
+    ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "expected updated style\n");
+
+    /* reset and try to set without a mask */
+    pSHSetWindowBits(hwnd, GWL_STYLE, WS_VISIBLE, 0);
+    ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
+    styleold = GetWindowLongA(hwnd, GWL_STYLE);
+    style = pSHSetWindowBits(hwnd, GWL_STYLE, 0, WS_VISIBLE);
+    ok(style == styleold, "expected previous style, got %x\n", style);
+    ok((GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE) == 0, "expected updated style\n");
+
+    DestroyWindow(hwnd);
+
+    UnregisterClassA("Shlwapi test class", GetModuleHandleA(NULL));
+}
+
+static void test_SHFormatDateTimeA(void)
+{
+    FILETIME UNALIGNED filetime;
+    CHAR buff[100], buff2[100], buff3[100];
+    SYSTEMTIME st;
+    DWORD flags;
+    INT ret;
+
+    if(!pSHFormatDateTimeA)
+    {
+        win_skip("pSHFormatDateTimeA isn't available\n");
+        return;
+    }
+
+if (0)
+{
+    /* crashes on native */
+    ret = pSHFormatDateTimeA(NULL, NULL, NULL, 0);
+}
+
+    GetLocalTime(&st);
+    SystemTimeToFileTime(&st, &filetime);
+    /* SHFormatDateTime expects input as utc */
+    LocalFileTimeToFileTime(&filetime, &filetime);
+
+    /* no way to get required buffer length here */
+    SetLastError(0xdeadbeef);
+    ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
+    ok(ret == 0, "got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    buff[0] = 'a'; buff[1] = 0;
+    ret = pSHFormatDateTimeA(&filetime, NULL, buff, 0);
+    ok(ret == 0, "got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
+    ok(buff[0] == 'a', "expected same string, got %s\n", buff);
+
+    /* flags needs to have FDTF_NOAUTOREADINGORDER for these tests to succeed on Vista+ */
+
+    /* all combinations documented as invalid succeeded */
+    flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME | FDTF_LONGTIME;
+    SetLastError(0xdeadbeef);
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
+
+    flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGDATE;
+    SetLastError(0xdeadbeef);
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
+
+    flags =  FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
+    SetLastError(0xdeadbeef);
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef ||
+        broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe */
+        "expected 0xdeadbeef, got %d\n", GetLastError());
+
+    /* now check returned strings */
+    flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTTIME;
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
+    ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2));
+    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
+    ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
+
+    flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME;
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
+    ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
+    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
+    ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
+
+    /* both time flags */
+    flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGTIME | FDTF_SHORTTIME;
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
+    ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2));
+    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
+    ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
+
+    flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE;
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
+    ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
+    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
+    ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
+
+    flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE;
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
+    ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
+    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
+    ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
+
+    /* both date flags */
+    flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTDATE;
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
+    ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
+    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
+    ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
+
+    /* various combinations of date/time flags */
+    flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
+    ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
+    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
+    strcat(buff2, ", ");
+    ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
+    ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
+    strcat(buff2, buff3);
+    ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
+
+    flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
+    ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
+    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
+    strcat(buff2, ", ");
+    ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
+    ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
+    strcat(buff2, buff3);
+    ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
+
+    flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
+    ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
+    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
+    strcat(buff2, " ");
+    ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
+    ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
+    strcat(buff2, buff3);
+    ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
+
+    flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_LONGTIME;
+    ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
+    ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
+    ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2));
+    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
+    strcat(buff2, " ");
+    ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
+    ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
+    strcat(buff2, buff3);
+    ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
+}
+
+static void test_SHFormatDateTimeW(void)
+{
+    FILETIME UNALIGNED filetime;
+    WCHAR buff[100], buff2[100], buff3[100];
+    SYSTEMTIME st;
+    DWORD flags;
+    INT ret;
+    static const WCHAR spaceW[] = {' ',0};
+    static const WCHAR commaW[] = {',',' ',0};
+
+    if(!pSHFormatDateTimeW)
+    {
+        win_skip("pSHFormatDateTimeW isn't available\n");
+        return;
+    }
+
+if (0)
+{
+    /* crashes on native */
+    ret = pSHFormatDateTimeW(NULL, NULL, NULL, 0);
+}
+
+    GetLocalTime(&st);
+    SystemTimeToFileTime(&st, &filetime);
+    /* SHFormatDateTime expects input as utc */
+    LocalFileTimeToFileTime(&filetime, &filetime);
+
+    /* no way to get required buffer length here */
+    SetLastError(0xdeadbeef);
+    ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
+    ok(ret == 0, "got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    buff[0] = 'a'; buff[1] = 0;
+    ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
+    ok(ret == 0, "got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
+    ok(buff[0] == 'a', "expected same string\n");
+
+    /* all combinations documented as invalid succeeded */
+    flags = FDTF_SHORTTIME | FDTF_LONGTIME;
+    SetLastError(0xdeadbeef);
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
+
+    flags = FDTF_SHORTDATE | FDTF_LONGDATE;
+    SetLastError(0xdeadbeef);
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
+
+    flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
+    SetLastError(0xdeadbeef);
+    buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef ||
+        broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
+        "expected 0xdeadbeef, got %d\n", GetLastError());
+
+    /* now check returned strings */
+    flags = FDTF_SHORTTIME;
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    SetLastError(0xdeadbeef);
+    ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
+    if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("Needed W-functions are not implemented\n");
+        return;
+    }
+    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
+
+    flags = FDTF_LONGTIME;
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
+
+    /* both time flags */
+    flags = FDTF_LONGTIME | FDTF_SHORTTIME;
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
+
+    flags = FDTF_SHORTDATE;
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
+
+    flags = FDTF_LONGDATE;
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
+
+    /* both date flags */
+    flags = FDTF_LONGDATE | FDTF_SHORTDATE;
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
+
+    /* various combinations of date/time flags */
+    flags = FDTF_LONGDATE | FDTF_SHORTTIME;
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d, length %d\n", ret, lstrlenW(buff)+1);
+    ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    lstrcatW(buff2, commaW);
+    ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
+    lstrcatW(buff2, buff3);
+    ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
+
+    flags = FDTF_LONGDATE | FDTF_LONGTIME;
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    lstrcatW(buff2, commaW);
+    ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
+    lstrcatW(buff2, buff3);
+    ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
+
+    flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    lstrcatW(buff2, spaceW);
+    ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
+    lstrcatW(buff2, buff3);
+    ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
+
+    flags = FDTF_SHORTDATE | FDTF_LONGTIME;
+    ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    lstrcatW(buff2, spaceW);
+    ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
+    lstrcatW(buff2, buff3);
+    ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
+}
+
+static void test_SHGetObjectCompatFlags(void)
+{
+    struct compat_value {
+        CHAR nameA[30];
+        DWORD value;
+    };
+
+    struct compat_value values[] = {
+        { "OTNEEDSSFCACHE", 0x1 },
+        { "NO_WEBVIEW", 0x2 },
+        { "UNBINDABLE", 0x4 },
+        { "PINDLL", 0x8 },
+        { "NEEDSFILESYSANCESTOR", 0x10 },
+        { "NOTAFILESYSTEM", 0x20 },
+        { "CTXMENU_NOVERBS", 0x40 },
+        { "CTXMENU_LIMITEDQI", 0x80 },
+        { "COCREATESHELLFOLDERONLY", 0x100 },
+        { "NEEDSSTORAGEANCESTOR", 0x200 },
+        { "NOLEGACYWEBVIEW", 0x400 },
+        { "CTXMENU_XPQCMFLAGS", 0x1000 },
+        { "NOIPROPERTYSTORE", 0x2000 }
+    };
+
+    static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
+    CHAR keyA[39]; /* {CLSID} */
+    HKEY root;
+    DWORD ret;
+    int i;
+
+    if (!pSHGetObjectCompatFlags)
+    {
+        win_skip("SHGetObjectCompatFlags isn't available\n");
+        return;
+    }
+
+    /* null args */
+    ret = pSHGetObjectCompatFlags(NULL, NULL);
+    ok(ret == 0, "got %d\n", ret);
+
+    ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root);
+    if (ret != ERROR_SUCCESS)
+    {
+        skip("No compatibility class data found\n");
+        return;
+    }
+
+    for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++)
+    {
+        HKEY clsid_key;
+
+        if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS)
+        {
+            CHAR valueA[30];
+            DWORD expected = 0, got, length = sizeof(valueA);
+            CLSID clsid;
+            int v;
+
+            for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++)
+            {
+                int j;
+
+                for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++)
+                    if (lstrcmpA(values[j].nameA, valueA) == 0)
+                    {
+                        expected |= values[j].value;
+                        break;
+                    }
+
+                length = sizeof(valueA);
+            }
+
+            pGUIDFromStringA(keyA, &clsid);
+            got = pSHGetObjectCompatFlags(NULL, &clsid);
+            ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA);
+
+            RegCloseKey(clsid_key);
+        }
+    }
+
+    RegCloseKey(root);
+}
+
+typedef struct {
+    const IOleCommandTargetVtbl *lpVtbl;
+    LONG ref;
+} IOleCommandTargetImpl;
+
+static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
+
+IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
+{
+    IOleCommandTargetImpl *obj;
+
+    obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
+    obj->lpVtbl = &IOleCommandTargetImpl_Vtbl;
+    obj->ref = 1;
+
+    return (IOleCommandTarget*)obj;
+}
+
+static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
+{
+    IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
+
+    if (IsEqualIID(riid, &IID_IUnknown) ||
+        IsEqualIID(riid, &IID_IOleCommandTarget))
+    {
+        *ppvObj = This;
+    }
+
+    if(*ppvObj)
+    {
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
+{
+    IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
+{
+    IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    if (!ref)
+    {
+        HeapFree(GetProcessHeap(), 0, This);
+        return 0;
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IOleCommandTargetImpl_QueryStatus(
+    IOleCommandTarget *iface, const GUID *group, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IOleCommandTargetImpl_Exec(
+    IOleCommandTarget *iface,
+    const GUID *CmdGroup,
+    DWORD nCmdID,
+    DWORD nCmdexecopt,
+    VARIANT *pvaIn,
+    VARIANT *pvaOut)
+{
+    add_call(&trace_got, 3, CmdGroup, (void*)(DWORD_PTR)nCmdID, (void*)(DWORD_PTR)nCmdexecopt, pvaIn, pvaOut);
+    return S_OK;
+}
+
+static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
+{
+    IOleCommandTargetImpl_QueryInterface,
+    IOleCommandTargetImpl_AddRef,
+    IOleCommandTargetImpl_Release,
+    IOleCommandTargetImpl_QueryStatus,
+    IOleCommandTargetImpl_Exec
+};
+
+typedef struct {
+    const IServiceProviderVtbl *lpVtbl;
+    LONG ref;
+} IServiceProviderImpl;
+
+typedef struct {
+    const IProfferServiceVtbl *lpVtbl;
+    LONG ref;
+} IProfferServiceImpl;
+
+
+static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
+static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
+
+IServiceProvider* IServiceProviderImpl_Construct(void)
+{
+    IServiceProviderImpl *obj;
+
+    obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
+    obj->lpVtbl = &IServiceProviderImpl_Vtbl;
+    obj->ref = 1;
+
+    return (IServiceProvider*)obj;
+}
+
+IProfferService* IProfferServiceImpl_Construct(void)
+{
+    IProfferServiceImpl *obj;
+
+    obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
+    obj->lpVtbl = &IProfferServiceImpl_Vtbl;
+    obj->ref = 1;
+
+    return (IProfferService*)obj;
+}
+
+static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
+{
+    IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
+
+    if (IsEqualIID(riid, &IID_IUnknown) ||
+        IsEqualIID(riid, &IID_IServiceProvider))
+    {
+        *ppvObj = This;
+    }
+
+    if(*ppvObj)
+    {
+        IUnknown_AddRef(iface);
+        /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
+        if (IsEqualIID(riid, &IID_IServiceProvider))
+            add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
+{
+    IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
+{
+    IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    if (!ref)
+    {
+        HeapFree(GetProcessHeap(), 0, This);
+        return 0;
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IServiceProviderImpl_QueryService(
+    IServiceProvider *iface, REFGUID service, REFIID riid, void **ppv)
+{
+    /* native uses redefined pointer for IID_IOleCommandTarget, not one from uuid.lib */
+    if (IsEqualIID(riid, &IID_IOleCommandTarget))
+    {
+        add_call(&trace_got, 2, iface, service, &IID_IOleCommandTarget, 0, 0);
+        *ppv = IOleCommandTargetImpl_Construct();
+    }
+    if (IsEqualIID(riid, &IID_IProfferService))
+    {
+        if (IsEqualIID(service, &IID_IProfferService))
+            add_call(&trace_got, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
+        *ppv = IProfferServiceImpl_Construct();
+    }
+    return S_OK;
+}
+
+static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
+{
+    IServiceProviderImpl_QueryInterface,
+    IServiceProviderImpl_AddRef,
+    IServiceProviderImpl_Release,
+    IServiceProviderImpl_QueryService
+};
+
+static void test_IUnknown_QueryServiceExec(void)
+{
+    IServiceProvider *provider = IServiceProviderImpl_Construct();
+    static const GUID dummy_serviceid = { 0xdeadbeef };
+    static const GUID dummy_groupid = { 0xbeefbeef };
+    call_trace_t trace_expected;
+    HRESULT hr;
+
+    /* on <=W2K platforms same ordinal used for another export with different
+       prototype, so skipping using this indirect condition */
+    if (is_win2k_and_lower)
+    {
+        win_skip("IUnknown_QueryServiceExec is not available\n");
+        return;
+    }
+
+    /* null source pointer */
+    hr = pIUnknown_QueryServiceExec(NULL, &dummy_serviceid, &dummy_groupid, 0, 0, 0, 0);
+    ok(hr == E_FAIL, "got 0x%08x\n", hr);
+
+    /* expected trace:
+       IUnknown_QueryServiceExec( ptr1, serviceid, groupid, arg1, arg2, arg3, arg4);
+         -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &prov );
+         -> IServiceProvider_QueryService( prov, serviceid, &IID_IOleCommandTarget, &obj );
+         -> IOleCommandTarget_Exec( obj, groupid, arg1, arg2, arg3, arg4 );
+    */
+    init_call_trace(&trace_expected);
+
+    add_call(&trace_expected, 1, provider, &IID_IServiceProvider, 0, 0, 0);
+    add_call(&trace_expected, 2, provider, &dummy_serviceid, &IID_IOleCommandTarget, 0, 0);
+    add_call(&trace_expected, 3, &dummy_groupid, (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4);
+
+    init_call_trace(&trace_got);
+    hr = pIUnknown_QueryServiceExec((IUnknown*)provider, &dummy_serviceid, &dummy_groupid, 0x1, 0x2, (void*)0x3, (void*)0x4);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    ok_trace(&trace_expected, &trace_got);
+
+    free_call_trace(&trace_expected);
+    free_call_trace(&trace_got);
+
+    IServiceProvider_Release(provider);
+}
+
+
+static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
+{
+    IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
+
+    if (IsEqualIID(riid, &IID_IUnknown) ||
+        IsEqualIID(riid, &IID_IProfferService))
+    {
+        *ppvObj = This;
+    }
+    else if (IsEqualIID(riid, &IID_IServiceProvider))
+    {
+        *ppvObj = IServiceProviderImpl_Construct();
+        add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
+        return S_OK;
+    }
+
+    if(*ppvObj)
+    {
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
+{
+    IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
+{
+    IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    if (!ref)
+    {
+        HeapFree(GetProcessHeap(), 0, This);
+        return 0;
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
+    REFGUID service, IServiceProvider *pService, DWORD *pCookie)
+{
+    add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
+    return S_OK;
+}
+
+static HRESULT WINAPI IProfferServiceImpl_RevokeService(IProfferService *iface, DWORD cookie)
+{
+    add_call(&trace_got, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
+    return S_OK;
+}
+
+static const IProfferServiceVtbl IProfferServiceImpl_Vtbl =
+{
+    IProfferServiceImpl_QueryInterface,
+    IProfferServiceImpl_AddRef,
+    IProfferServiceImpl_Release,
+    IProfferServiceImpl_ProfferService,
+    IProfferServiceImpl_RevokeService
+};
+
+static void test_IUnknown_ProfferService(void)
+{
+    IServiceProvider *provider = IServiceProviderImpl_Construct();
+    IProfferService *proff = IProfferServiceImpl_Construct();
+    static const GUID dummy_serviceid = { 0xdeadbeef };
+    call_trace_t trace_expected;
+    HRESULT hr;
+    DWORD cookie;
+
+    /* on <=W2K platforms same ordinal used for another export with different
+       prototype, so skipping using this indirect condition */
+    if (is_win2k_and_lower)
+    {
+        win_skip("IUnknown_ProfferService is not available\n");
+        return;
+    }
+
+    /* null source pointer */
+    hr = pIUnknown_ProfferService(NULL, &dummy_serviceid, 0, 0);
+    ok(hr == E_FAIL, "got 0x%08x\n", hr);
+
+    /* expected trace:
+       IUnknown_ProfferService( ptr1, serviceid, arg1, arg2);
+         -> IUnknown_QueryInterface( ptr1, &IID_IServiceProvider, &provider );
+         -> IServiceProvider_QueryService( provider, &IID_IProfferService, &IID_IProfferService, &proffer );
+
+         if (service pointer not null):
+             -> IProfferService_ProfferService( proffer, serviceid, arg1, arg2 );
+         else
+             -> IProfferService_RevokeService( proffer, *arg2 );
+    */
+    init_call_trace(&trace_expected);
+
+    add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
+    add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
+    add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
+
+    init_call_trace(&trace_got);
+    hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    ok_trace(&trace_expected, &trace_got);
+    free_call_trace(&trace_got);
+    free_call_trace(&trace_expected);
+
+    /* same with ::Revoke path */
+    init_call_trace(&trace_expected);
+
+    add_call(&trace_expected, 1, proff, &IID_IServiceProvider, 0, 0, 0);
+    add_call(&trace_expected, 2, &IID_IProfferService, &IID_IProfferService, 0, 0, 0);
+    add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
+
+    init_call_trace(&trace_got);
+    hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok_trace(&trace_expected, &trace_got);
+    free_call_trace(&trace_got);
+    free_call_trace(&trace_expected);
+
+    IServiceProvider_Release(provider);
+    IProfferService_Release(proff);
+}
+
+static void test_SHCreateWorkerWindowA(void)
+{
+    WNDCLASSA cliA;
+    char classA[20];
+    HWND hwnd;
+    LONG_PTR ret;
+    BOOL res;
+
+    if (is_win2k_and_lower)
+    {
+        win_skip("SHCreateWorkerWindowA not available\n");
+        return;
+    }
+
+    hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0);
+    ok(hwnd != 0, "expected window\n");
+
+    GetClassName(hwnd, classA, 20);
+    ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
+
+    ret = GetWindowLongPtrA(hwnd, 0);
+    ok(ret == 0, "got %ld\n", ret);
+
+    /* class info */
+    memset(&cliA, 0, sizeof(cliA));
+    res = GetClassInfoA(GetModuleHandle("shlwapi.dll"), "WorkerA", &cliA);
+    ok(res, "failed to get class info\n");
+    ok(cliA.style == 0, "got 0x%08x\n", cliA.style);
+    ok(cliA.cbClsExtra == 0, "got %d\n", cliA.cbClsExtra);
+    ok(cliA.cbWndExtra == sizeof(LONG_PTR), "got %d\n", cliA.cbWndExtra);
+    ok(cliA.lpszMenuName == 0, "got %s\n", cliA.lpszMenuName);
+
+    DestroyWindow(hwnd);
+
+    /* set extra bytes */
+    hwnd = pSHCreateWorkerWindowA(0, NULL, 0, 0, 0, 0xdeadbeef);
+    ok(hwnd != 0, "expected window\n");
+
+    GetClassName(hwnd, classA, 20);
+    ok(lstrcmpA(classA, "WorkerA") == 0, "expected WorkerA class, got %s\n", classA);
+
+    ret = GetWindowLongPtrA(hwnd, 0);
+    ok(ret == 0xdeadbeef, "got %ld\n", ret);
+
+    /* test exstyle */
+    ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
+    ok(ret == WS_EX_WINDOWEDGE, "0x%08lx\n", ret);
+
+    DestroyWindow(hwnd);
+
+    hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
+    ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
+    ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW), "0x%08lx\n", ret);
+    DestroyWindow(hwnd);
+}
+
+static void init_pointers(void)
+{
+#define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
+    MAKEFUNC(SHAllocShared, 7);
+    MAKEFUNC(SHLockShared, 8);
+    MAKEFUNC(SHUnlockShared, 9);
+    MAKEFUNC(SHFreeShared, 10);
+    MAKEFUNC(GetAcceptLanguagesA, 14);
+    MAKEFUNC(SHSetWindowBits, 165);
+    MAKEFUNC(ConnectToConnectionPoint, 168);
+    MAKEFUNC(SHSearchMapInt, 198);
+    MAKEFUNC(SHCreateWorkerWindowA, 257);
+    MAKEFUNC(GUIDFromStringA, 269);
+    MAKEFUNC(SHPackDispParams, 282);
+    MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
+    MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
+    MAKEFUNC(SHFormatDateTimeA, 353);
+    MAKEFUNC(SHFormatDateTimeW, 354);
+    MAKEFUNC(SHGetObjectCompatFlags, 476);
+    MAKEFUNC(IUnknown_QueryServiceExec, 484);
+    MAKEFUNC(SHPropertyBag_ReadLONG, 496);
+    MAKEFUNC(IUnknown_ProfferService, 514);
+#undef MAKEFUNC
+}
+
 START_TEST(ordinal)
 {
-  hShlwapi = GetModuleHandleA("shlwapi.dll");
-
-  pGetAcceptLanguagesA = (void*)GetProcAddress(hShlwapi, (LPSTR)14);
-  pSHSearchMapInt = (void*)GetProcAddress(hShlwapi, (LPSTR)198);
-  pSHAllocShared=(void*)GetProcAddress(hShlwapi,(char*)7);
-  pSHLockShared=(void*)GetProcAddress(hShlwapi,(char*)8);
-  pSHUnlockShared=(void*)GetProcAddress(hShlwapi,(char*)9);
-  pSHFreeShared=(void*)GetProcAddress(hShlwapi,(char*)10);
-  pSHPackDispParams=(void*)GetProcAddress(hShlwapi,(char*)282);
-  pIConnectionPoint_SimpleInvoke=(void*)GetProcAddress(hShlwapi,(char*)284);
-  pIConnectionPoint_InvokeWithCancel=(void*)GetProcAddress(hShlwapi,(char*)283);
-  pConnectToConnectionPoint=(void*)GetProcAddress(hShlwapi,(char*)168);
-  pSHPropertyBag_ReadLONG=(void*)GetProcAddress(hShlwapi,(char*)496);
-
-  hmlang = LoadLibraryA("mlang.dll");
-  pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
-
-  test_GetAcceptLanguagesA();
-  test_SHSearchMapInt();
-  test_alloc_shared();
-  test_fdsa();
-  test_GetShellSecurityDescriptor();
-  test_SHPackDispParams();
-  test_IConnectionPoint();
-  test_SHPropertyBag_ReadLONG();
+    hShlwapi = GetModuleHandleA("shlwapi.dll");
+    is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0;
+
+    init_pointers();
+
+    hmlang = LoadLibraryA("mlang.dll");
+    pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
+
+    test_GetAcceptLanguagesA();
+    test_SHSearchMapInt();
+    test_alloc_shared();
+    test_fdsa();
+    test_GetShellSecurityDescriptor();
+    test_SHPackDispParams();
+    test_IConnectionPoint();
+    test_SHPropertyBag_ReadLONG();
+    test_SHSetWindowBits();
+    test_SHFormatDateTimeA();
+    test_SHFormatDateTimeW();
+    test_SHGetObjectCompatFlags();
+    test_IUnknown_QueryServiceExec();
+    test_IUnknown_ProfferService();
+    test_SHCreateWorkerWindowA();
 }
index e52502f..3e83a45 100755 (executable)
 #include "shlwapi.h"
 #include "wininet.h"
 
-static HMODULE hShlwapi;
 static HRESULT (WINAPI *pPathIsValidCharA)(char,DWORD);
 static HRESULT (WINAPI *pPathIsValidCharW)(WCHAR,DWORD);
 static LPWSTR  (WINAPI *pPathCombineW)(LPWSTR, LPCWSTR, LPCWSTR);
 static HRESULT (WINAPI *pPathCreateFromUrlA)(LPCSTR, LPSTR, LPDWORD, DWORD);
 static HRESULT (WINAPI *pPathCreateFromUrlW)(LPCWSTR, LPWSTR, LPDWORD, DWORD);
+static BOOL    (WINAPI *pPathAppendA)(LPSTR, LPCSTR);
 
 /* ################ */
 
@@ -300,6 +300,15 @@ static void test_PathIsValidCharA(void)
     BOOL ret;
     unsigned int c;
 
+    /* For whatever reason, PathIsValidCharA and PathAppendA share the same
+     * ordinal number in some native versions. Check this to prevent a crash.
+     */
+    if (!pPathIsValidCharA || pPathIsValidCharA == (void*)pPathAppendA)
+    {
+        win_skip("PathIsValidCharA isn't available\n");
+        return;
+    }
+
     for (c = 0; c < 0x7f; c++)
     {
         ret = pPathIsValidCharA( c, ~0U );
@@ -318,6 +327,12 @@ static void test_PathIsValidCharW(void)
     BOOL ret;
     unsigned int c;
 
+    if (!pPathIsValidCharW)
+    {
+        win_skip("PathIsValidCharW isn't available\n");
+        return;
+    }
+
     for (c = 0; c < 0x7f; c++)
     {
         ret = pPathIsValidCharW( c, ~0U );
@@ -392,7 +407,13 @@ static void test_PathCombineW(void)
     WCHAR wbuf[MAX_PATH+1], wstr1[MAX_PATH] = {'C',':','\\',0}, wstr2[MAX_PATH];
     static const WCHAR expout[] = {'C',':','\\','A','A',0};
     int i;
-   
+
+    if (!pPathCombineW)
+    {
+        win_skip("PathCombineW isn't available\n");
+        return;
+    }
+
     wszString2 = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
 
     /* NULL test */
@@ -1312,43 +1333,60 @@ static void test_PathUnquoteSpaces(void)
     }
 }
 
+static void test_PathGetDriveNumber(void)
+{
+    static const CHAR test1A[] = "a:\\test.file";
+    static const CHAR test2A[] = "file:////b:\\test.file";
+    static const CHAR test3A[] = "file:///c:\\test.file";
+    static const CHAR test4A[] = "file:\\\\c:\\test.file";
+    int ret;
+
+    SetLastError(0xdeadbeef);
+    ret = PathGetDriveNumberA(NULL);
+    ok(ret == -1, "got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "got %d\n", GetLastError());
+
+    ret = PathGetDriveNumberA(test1A);
+    ok(ret == 0, "got %d\n", ret);
+    ret = PathGetDriveNumberA(test2A);
+    ok(ret == -1, "got %d\n", ret);
+    ret = PathGetDriveNumberA(test3A);
+    ok(ret == -1, "got %d\n", ret);
+    ret = PathGetDriveNumberA(test4A);
+    ok(ret == -1, "got %d\n", ret);
+}
+
 /* ################ */
 
 START_TEST(path)
 {
-  hShlwapi = GetModuleHandleA("shlwapi.dll");
-  pPathCreateFromUrlA = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlA");
-  pPathCreateFromUrlW = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlW");
-
-  test_PathSearchAndQualify();
-  test_PathCreateFromUrl();
-  test_PathIsUrl();
-
-  test_PathAddBackslash();
-  test_PathMakePretty();
-  test_PathMatchSpec();
-
-  /* For whatever reason, PathIsValidCharA and PathAppendA share the same
-   * ordinal number in some native versions. Check this to prevent a crash.
-   */
-  pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
-  if (pPathIsValidCharA && pPathIsValidCharA != (void*)GetProcAddress(hShlwapi, "PathAppendA"))
-  {
-    test_PathIsValidCharA();
+    HMODULE hShlwapi = GetModuleHandleA("shlwapi.dll");
 
-     pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
-     if (pPathIsValidCharW) test_PathIsValidCharW();
-  }
+    pPathCreateFromUrlA = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlA");
+    pPathCreateFromUrlW = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlW");
+    pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW");
+    pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
+    pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
+    pPathAppendA = (void*)GetProcAddress(hShlwapi, "PathAppendA");
 
-  pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW");
-  if (pPathCombineW)
-    test_PathCombineW();
+    test_PathSearchAndQualify();
+    test_PathCreateFromUrl();
+    test_PathIsUrl();
+
+    test_PathAddBackslash();
+    test_PathMakePretty();
+    test_PathMatchSpec();
 
-  test_PathCombineA();
-  test_PathAppendA();
-  test_PathCanonicalizeA();
-  test_PathFindExtensionA();
-  test_PathBuildRootA();
-  test_PathCommonPrefixA();
-  test_PathUnquoteSpaces();
+    test_PathIsValidCharA();
+    test_PathIsValidCharW();
+
+    test_PathCombineW();
+    test_PathCombineA();
+    test_PathAppendA();
+    test_PathCanonicalizeA();
+    test_PathFindExtensionA();
+    test_PathBuildRootA();
+    test_PathCommonPrefixA();
+    test_PathUnquoteSpaces();
+    test_PathGetDriveNumber();
 }
index cd5cffd..0fe7009 100644 (file)
@@ -3,7 +3,7 @@
 <group>
 <module name="shlwapi_winetest" type="win32cui" installbase="bin" installname="shlwapi_winetest.exe" allowwarnings="true">
        <include base="shlwapi_winetest">.</include>
-    <define name="__ROS_LONG64__" />
+       <define name="__ROS_LONG64__" />
        <file>assoc.c</file>
        <file>clist.c</file>
        <file>clsid.c</file>
@@ -21,6 +21,7 @@
        <library>advapi32</library>
        <library>ole32</library>
        <library>oleaut32</library>
+       <library>user32</library>
        <library>ntdll</library>
 </module>
 </group>
index 00f0b02..17c652d 100755 (executable)
@@ -863,6 +863,33 @@ static void test_StrXXX_overflows(void)
     else
         win_skip("StrCatBuffA() is not available\n");
 
+if (0)
+{
+    /* crashes on XP */
+    StrCpyNW(wbuf, (LPCWSTR)0x1, 10);
+    StrCpyNW((LPWSTR)0x1, wstr1, 10);
+}
+
+    memset(wbuf, 0xbf, sizeof(wbuf));
+    expect_eq(StrCpyNW(wbuf, (LPCWSTR)0x1, 1), wbuf, PWCHAR, "%p");
+    expect_eq(wbuf[0], 0, WCHAR, "%x");
+    expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x");
+
+    memset(wbuf, 0xbf, sizeof(wbuf));
+    expect_eq(StrCpyNW(wbuf, 0, 10), wbuf, PWCHAR, "%p");
+    expect_eq(wbuf[0], 0, WCHAR, "%x");
+    expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x");
+
+    memset(wbuf, 0xbf, sizeof(wbuf));
+    expect_eq(StrCpyNW(wbuf, 0, 0), wbuf, PWCHAR, "%p");
+    expect_eq(wbuf[0], (WCHAR)0xbfbf, WCHAR, "%x");
+    expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x");
+
+    memset(wbuf, 0xbf, sizeof(wbuf));
+    expect_eq(StrCpyNW(wbuf, wstr1, 0), wbuf, PWCHAR, "%p");
+    expect_eq(wbuf[0], (WCHAR)0xbfbf, WCHAR, "%x");
+    expect_eq(wbuf[1], (WCHAR)0xbfbf, WCHAR, "%x");
+
     memset(wbuf, 0xbf, sizeof(wbuf));
     expect_eq(StrCpyNW(wbuf, wstr1, 10), wbuf, PWCHAR, "%p");
     expect_eq(wbuf[9], 0, WCHAR, "%x");
index 3d86ae7..0dd9643 100644 (file)
@@ -160,6 +160,7 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = {
     {"A", 0, S_OK, "A", FALSE},
     {"/uri-res/N2R?urn:sha1:B3K", URL_DONT_ESCAPE_EXTRA_INFO | URL_WININET_COMPATIBILITY /*0x82000000*/, S_OK, "/uri-res/N2R?urn:sha1:B3K", FALSE} /*LimeWire online installer calls this*/,
     {"http:www.winehq.org/dir/../index.html", 0, S_OK, "http:www.winehq.org/index.html"},
+    {"http://localhost/test.html", URL_FILE_USE_PATHURL, S_OK, "http://localhost/test.html"}
 };
 
 /* ################ */
@@ -278,6 +279,11 @@ static const TEST_URL_COMBINE TEST_COMBINE[] = {
     {"http://www.winehq.org/tests/../tests/", "/tests10/..", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests10/.."},
     {"http://www.winehq.org/tests/../", "tests11", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../tests11"},
     {"file:///C:\\dir\\file.txt", "test.txt", 0, S_OK, "file:///C:/dir/test.txt"},
+    {"file:///C:\\dir\\file.txt#hash\\hash", "test.txt", 0, S_OK, "file:///C:/dir/file.txt#hash/test.txt"},
+    {"file:///C:\\dir\\file.html#hash\\hash", "test.html", 0, S_OK, "file:///C:/dir/test.html"},
+    {"file:///C:\\dir\\file.htm#hash\\hash", "test.htm", 0, S_OK, "file:///C:/dir/test.htm"},
+    {"file:///C:\\dir\\file.hTmL#hash\\hash", "test.hTmL", 0, S_OK, "file:///C:/dir/test.hTmL"},
+    {"file:///C:\\dir.html\\file.txt#hash\\hash", "test.txt", 0, S_OK, "file:///C:/dir.html/file.txt#hash/test.txt"},
     {"C:\\winehq\\winehq.txt", "C:\\Test\\test.txt", 0, S_OK, "file:///C:/Test/test.txt"},
     {"http://www.winehq.org/test/", "test%20file.txt", 0, S_OK, "http://www.winehq.org/test/test%20file.txt"},
     {"http://www.winehq.org/test/", "test%20file.txt", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org/test/test%20file.txt"},
@@ -537,6 +543,13 @@ static void test_url_part(const char* szUrl, DWORD dwPart, DWORD dwFlags, const
   HRESULT res;
   DWORD dwSize;
 
+  dwSize = 1;
+  res = pUrlGetPartA(szUrl, szPart, &dwSize, dwPart, dwFlags);
+  ok(res == E_POINTER, "UrlGetPart for \"%s\" gave: 0x%08x\n", szUrl, res);
+  ok(dwSize == strlen(szExpected)+1 ||
+          (*szExpected == '?' && dwSize == strlen(szExpected)),
+          "UrlGetPart for \"%s\" gave size: %u\n", szUrl, dwSize);
+
   dwSize = INTERNET_MAX_URL_LENGTH;
   res = pUrlGetPartA(szUrl, szPart, &dwSize, dwPart, dwFlags);
   ok(res == S_OK,
@@ -570,6 +583,7 @@ static void test_UrlGetPart(void)
 {
   const char* file_url = "file://h o s t/c:/windows/file";
   const char* http_url = "http://user:pass 123@www.wine hq.org";
+  const char* res_url = "res://some.dll/find.dlg";
   const char* about_url = "about:blank";
 
   CHAR szPart[INTERNET_MAX_URL_LENGTH];
@@ -581,20 +595,38 @@ static void test_UrlGetPart(void)
     return;
   }
 
+  res = pUrlGetPartA(NULL, NULL, NULL, URL_PART_SCHEME, 0);
+  ok(res == E_INVALIDARG, "null params gave: 0x%08x\n", res);
+
+  res = pUrlGetPartA(NULL, szPart, &dwSize, URL_PART_SCHEME, 0);
+  ok(res == E_INVALIDARG, "null URL gave: 0x%08x\n", res);
+
+  res = pUrlGetPartA(res_url, NULL, &dwSize, URL_PART_SCHEME, 0);
+  ok(res == E_INVALIDARG, "null szPart gave: 0x%08x\n", res);
+
+  res = pUrlGetPartA(res_url, szPart, NULL, URL_PART_SCHEME, 0);
+  ok(res == E_INVALIDARG, "null URL gave: 0x%08x\n", res);
+
+  dwSize = 0;
+  szPart[0]='x'; szPart[1]=0;
+  res = pUrlGetPartA("hi", szPart, &dwSize, URL_PART_SCHEME, 0);
+  ok(res == E_INVALIDARG, "UrlGetPartA(*pcchOut = 0) returned %08X\n", res);
+  ok(szPart[0] == 'x' && szPart[1] == 0, "UrlGetPartA(*pcchOut = 0) modified szPart: \"%s\"\n", szPart);
+  ok(dwSize == 0, "dwSize = %d\n", dwSize);
+
   dwSize = sizeof szPart;
   szPart[0]='x'; szPart[1]=0;
   res = pUrlGetPartA("hi", szPart, &dwSize, URL_PART_SCHEME, 0);
-  todo_wine {
   ok (res==S_FALSE, "UrlGetPartA(\"hi\") returned %08X\n", res);
   ok(szPart[0]==0, "UrlGetPartA(\"hi\") return \"%s\" instead of \"\"\n", szPart);
-  }
+  ok(dwSize == 0, "dwSize = %d\n", dwSize);
+
   dwSize = sizeof szPart;
   szPart[0]='x'; szPart[1]=0;
   res = pUrlGetPartA("hi", szPart, &dwSize, URL_PART_QUERY, 0);
-  todo_wine {
   ok (res==S_FALSE, "UrlGetPartA(\"hi\") returned %08X\n", res);
   ok(szPart[0]==0, "UrlGetPartA(\"hi\") return \"%s\" instead of \"\"\n", szPart);
-  }
+  ok(dwSize == 0, "dwSize = %d\n", dwSize);
 
   test_url_part(TEST_URL_3, URL_PART_HOSTNAME, 0, "localhost");
   test_url_part(TEST_URL_3, URL_PART_PORT, 0, "21");
@@ -614,9 +646,20 @@ static void test_UrlGetPart(void)
   res = pUrlGetPartA(about_url, szPart, &dwSize, URL_PART_HOSTNAME, 0);
   ok(res==E_FAIL, "returned %08x\n", res);
 
+  test_url_part(res_url, URL_PART_SCHEME, 0, "res");
+  test_url_part("http://www.winehq.org", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, "http:www.winehq.org");
+
+  dwSize = sizeof szPart;
+  szPart[0]='x'; szPart[1]=0;
+  res = pUrlGetPartA(res_url, szPart, &dwSize, URL_PART_QUERY, 0);
+  ok(res==S_FALSE, "UrlGetPartA returned %08X\n", res);
+  ok(szPart[0]==0, "UrlGetPartA gave \"%s\" instead of \"\"\n", szPart);
+  ok(dwSize == 0, "dwSize = %d\n", dwSize);
+
   dwSize = sizeof(szPart);
   res = pUrlGetPartA("file://c:\\index.htm", szPart, &dwSize, URL_PART_HOSTNAME, 0);
   ok(res==S_FALSE, "returned %08x\n", res);
+  ok(dwSize == 0, "dwSize = %d\n", dwSize);
 
   dwSize = sizeof(szPart);
   szPart[0] = 'x'; szPart[1] = '\0';
@@ -624,6 +667,11 @@ static void test_UrlGetPart(void)
   ok(res==S_FALSE, "returned %08x\n", res);
   ok(szPart[0] == '\0', "szPart[0] = %c\n", szPart[0]);
   ok(dwSize == 0, "dwSize = %d\n", dwSize);
+
+  dwSize = sizeof(szPart);
+  szPart[0] = 'x'; szPart[1] = '\0';
+  res = pUrlGetPartA("index.htm", szPart, &dwSize, URL_PART_HOSTNAME, 0);
+  ok(res==E_FAIL, "returned %08x\n", res);
 }
 
 /* ########################### */
@@ -1000,6 +1048,15 @@ static void test_UrlCreateFromPath(void)
 
 /* ########################### */
 
+static void test_UrlIs_null(DWORD flag)
+{
+    BOOL ret;
+    ret = pUrlIsA(NULL, flag);
+    ok(ret == FALSE, "pUrlIsA(NULL, %d) failed\n", flag);
+    ret = pUrlIsW(NULL, flag);
+    ok(ret == FALSE, "pUrlIsW(NULL, %d) failed\n", flag);
+}
+
 static void test_UrlIs(void)
 {
     BOOL ret;
@@ -1011,6 +1068,14 @@ static void test_UrlIs(void)
         return;
     }
 
+    test_UrlIs_null(URLIS_APPLIABLE);
+    test_UrlIs_null(URLIS_DIRECTORY);
+    test_UrlIs_null(URLIS_FILEURL);
+    test_UrlIs_null(URLIS_HASQUERY);
+    test_UrlIs_null(URLIS_NOHISTORY);
+    test_UrlIs_null(URLIS_OPAQUE);
+    test_UrlIs_null(URLIS_URL);
+
     for(i = 0; i < sizeof(TEST_PATH_IS_URL) / sizeof(TEST_PATH_IS_URL[0]); i++) {
        MultiByteToWideChar(CP_ACP, 0, TEST_PATH_IS_URL[i].path, -1, wurl, 80);
 
index 8a2f353..63e892b 100644 (file)
  * Test helper macros
  */
 
-#ifdef _WIN64
+#define TEST_TYPE_SIZE(type, size)             C_ASSERT(sizeof(type) == size);
 
-# define TEST_TYPE_SIZE(type, size)
+#ifdef TYPE_ALIGNMENT
+# define TEST_TYPE_ALIGN(type, align)          C_ASSERT(TYPE_ALIGNMENT(type) == align);
+#else
 # define TEST_TYPE_ALIGN(type, align)
+#endif
+
+#ifdef _TYPE_ALIGNMENT
+# define TEST_TARGET_ALIGN(type, align)        C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align);
+# define TEST_FIELD_ALIGN(type, field, align)  C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align);
+#else
 # define TEST_TARGET_ALIGN(type, align)
 # define TEST_FIELD_ALIGN(type, field, align)
-# define TEST_FIELD_OFFSET(type, field, offset)
+#endif
 
-#else
+#define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset);
 
-# define TEST_TYPE_SIZE(type, size)             C_ASSERT(sizeof(type) == size);
+#define TEST_TARGET_SIZE(type, size)            TEST_TYPE_SIZE(*(type)0, size)
+#define TEST_FIELD_SIZE(type, field, size)      TEST_TYPE_SIZE((((type*)0)->field), size)
+#define TEST_TYPE_SIGNED(type)                  C_ASSERT((type) -1 < 0);
+#define TEST_TYPE_UNSIGNED(type)                C_ASSERT((type) -1 > 0);
 
-# ifdef TYPE_ALIGNMENT
-#  define TEST_TYPE_ALIGN(type, align)          C_ASSERT(TYPE_ALIGNMENT(type) == align);
-# else
-#  define TEST_TYPE_ALIGN(type, align)
-# endif
 
-# ifdef _TYPE_ALIGNMENT
-#  define TEST_TARGET_ALIGN(type, align)        C_ASSERT(_TYPE_ALIGNMENT(*(type)0) == align);
-#  define TEST_FIELD_ALIGN(type, field, align)  C_ASSERT(_TYPE_ALIGNMENT(((type*)0)->field) == align);
-# else
-#  define TEST_TARGET_ALIGN(type, align)
-#  define TEST_FIELD_ALIGN(type, field, align)
-# endif
+#ifdef _WIN64
 
-# define TEST_FIELD_OFFSET(type, field, offset) C_ASSERT(FIELD_OFFSET(type, field) == offset);
+static void test_pack_BINDINFO(void)
+{
+    /* BINDINFO */
+    TEST_FIELD_SIZE  (BINDINFO, cbSize, 4)
+    TEST_FIELD_ALIGN (BINDINFO, cbSize, 4)
+    TEST_FIELD_OFFSET(BINDINFO, cbSize, 0)
+    TEST_FIELD_SIZE  (BINDINFO, szExtraInfo, 8)
+    TEST_FIELD_ALIGN (BINDINFO, szExtraInfo, 8)
+    TEST_FIELD_OFFSET(BINDINFO, szExtraInfo, 8)
+}
 
-#endif
+static void test_pack_IBindHost(void)
+{
+    /* IBindHost */
+}
 
-#define TEST_TARGET_SIZE(type, size)            TEST_TYPE_SIZE(*(type)0, size)
-#define TEST_FIELD_SIZE(type, field, size)      TEST_TYPE_SIZE((((type*)0)->field), size)
-#define TEST_TYPE_SIGNED(type)                  C_ASSERT((type) -1 < 0);
-#define TEST_TYPE_UNSIGNED(type)                C_ASSERT((type) -1 > 0);
+static void test_pack_IBindHostVtbl(void)
+{
+    /* IBindHostVtbl */
+}
+
+static void test_pack_IBindStatusCallback(void)
+{
+    /* IBindStatusCallback */
+}
 
+static void test_pack_IBindStatusCallbackVtbl(void)
+{
+    /* IBindStatusCallbackVtbl */
+}
+
+static void test_pack_IBinding(void)
+{
+    /* IBinding */
+}
+
+static void test_pack_IBindingVtbl(void)
+{
+    /* IBindingVtbl */
+}
+
+static void test_pack_IInternetProtocolInfo(void)
+{
+    /* IInternetProtocolInfo */
+}
+
+static void test_pack_IInternetProtocolInfoVtbl(void)
+{
+    /* IInternetProtocolInfoVtbl */
+}
+
+static void test_pack_IInternetSession(void)
+{
+    /* IInternetSession */
+}
+
+static void test_pack_IInternetSessionVtbl(void)
+{
+    /* IInternetSessionVtbl */
+}
+
+static void test_pack_IPersistMoniker(void)
+{
+    /* IPersistMoniker */
+}
+
+static void test_pack_IPersistMonikerVtbl(void)
+{
+    /* IPersistMonikerVtbl */
+}
+
+static void test_pack_IWinInetHttpInfo(void)
+{
+    /* IWinInetHttpInfo */
+}
+
+static void test_pack_IWinInetHttpInfoVtbl(void)
+{
+    /* IWinInetHttpInfoVtbl */
+}
+
+static void test_pack_IWinInetInfo(void)
+{
+    /* IWinInetInfo */
+}
+
+static void test_pack_IWinInetInfoVtbl(void)
+{
+    /* IWinInetInfoVtbl */
+}
+
+static void test_pack_LPBINDHOST(void)
+{
+    /* LPBINDHOST */
+    TEST_TYPE_SIZE   (LPBINDHOST, 8)
+    TEST_TYPE_ALIGN  (LPBINDHOST, 8)
+}
+
+static void test_pack_LPBINDING(void)
+{
+    /* LPBINDING */
+    TEST_TYPE_SIZE   (LPBINDING, 8)
+    TEST_TYPE_ALIGN  (LPBINDING, 8)
+}
+
+static void test_pack_LPBINDSTATUSCALLBACK(void)
+{
+    /* LPBINDSTATUSCALLBACK */
+    TEST_TYPE_SIZE   (LPBINDSTATUSCALLBACK, 8)
+    TEST_TYPE_ALIGN  (LPBINDSTATUSCALLBACK, 8)
+}
+
+static void test_pack_LPIINTERNETPROTOCOLINFO(void)
+{
+    /* LPIINTERNETPROTOCOLINFO */
+    TEST_TYPE_SIZE   (LPIINTERNETPROTOCOLINFO, 8)
+    TEST_TYPE_ALIGN  (LPIINTERNETPROTOCOLINFO, 8)
+}
+
+static void test_pack_LPIINTERNETSESSION(void)
+{
+    /* LPIINTERNETSESSION */
+    TEST_TYPE_SIZE   (LPIINTERNETSESSION, 8)
+    TEST_TYPE_ALIGN  (LPIINTERNETSESSION, 8)
+}
+
+static void test_pack_LPPERSISTMONIKER(void)
+{
+    /* LPPERSISTMONIKER */
+    TEST_TYPE_SIZE   (LPPERSISTMONIKER, 8)
+    TEST_TYPE_ALIGN  (LPPERSISTMONIKER, 8)
+}
+
+static void test_pack_LPREMFORMATETC(void)
+{
+    /* LPREMFORMATETC */
+    TEST_TYPE_SIZE   (LPREMFORMATETC, 8)
+    TEST_TYPE_ALIGN  (LPREMFORMATETC, 8)
+}
+
+static void test_pack_LPREMSECURITY_ATTRIBUTES(void)
+{
+    /* LPREMSECURITY_ATTRIBUTES */
+    TEST_TYPE_SIZE   (LPREMSECURITY_ATTRIBUTES, 8)
+    TEST_TYPE_ALIGN  (LPREMSECURITY_ATTRIBUTES, 8)
+}
+
+static void test_pack_LPWININETHTTPINFO(void)
+{
+    /* LPWININETHTTPINFO */
+    TEST_TYPE_SIZE   (LPWININETHTTPINFO, 8)
+    TEST_TYPE_ALIGN  (LPWININETHTTPINFO, 8)
+}
+
+static void test_pack_LPWININETINFO(void)
+{
+    /* LPWININETINFO */
+    TEST_TYPE_SIZE   (LPWININETINFO, 8)
+    TEST_TYPE_ALIGN  (LPWININETINFO, 8)
+}
+
+static void test_pack_PREMSECURITY_ATTRIBUTES(void)
+{
+    /* PREMSECURITY_ATTRIBUTES */
+    TEST_TYPE_SIZE   (PREMSECURITY_ATTRIBUTES, 8)
+    TEST_TYPE_ALIGN  (PREMSECURITY_ATTRIBUTES, 8)
+}
+
+static void test_pack_REMSECURITY_ATTRIBUTES(void)
+{
+    /* REMSECURITY_ATTRIBUTES */
+    TEST_TYPE_SIZE   (REMSECURITY_ATTRIBUTES, 12)
+    TEST_TYPE_ALIGN  (REMSECURITY_ATTRIBUTES, 4)
+    TEST_FIELD_SIZE  (REMSECURITY_ATTRIBUTES, nLength, 4)
+    TEST_FIELD_ALIGN (REMSECURITY_ATTRIBUTES, nLength, 4)
+    TEST_FIELD_OFFSET(REMSECURITY_ATTRIBUTES, nLength, 0)
+    TEST_FIELD_SIZE  (REMSECURITY_ATTRIBUTES, lpSecurityDescriptor, 4)
+    TEST_FIELD_ALIGN (REMSECURITY_ATTRIBUTES, lpSecurityDescriptor, 4)
+    TEST_FIELD_OFFSET(REMSECURITY_ATTRIBUTES, lpSecurityDescriptor, 4)
+    TEST_FIELD_SIZE  (REMSECURITY_ATTRIBUTES, bInheritHandle, 4)
+    TEST_FIELD_ALIGN (REMSECURITY_ATTRIBUTES, bInheritHandle, 4)
+    TEST_FIELD_OFFSET(REMSECURITY_ATTRIBUTES, bInheritHandle, 8)
+}
+
+static void test_pack_RemBINDINFO(void)
+{
+    /* RemBINDINFO */
+    TEST_TYPE_SIZE   (RemBINDINFO, 96)
+    TEST_TYPE_ALIGN  (RemBINDINFO, 8)
+    TEST_FIELD_SIZE  (RemBINDINFO, cbSize, 4)
+    TEST_FIELD_ALIGN (RemBINDINFO, cbSize, 4)
+    TEST_FIELD_OFFSET(RemBINDINFO, cbSize, 0)
+    TEST_FIELD_SIZE  (RemBINDINFO, szExtraInfo, 8)
+    TEST_FIELD_ALIGN (RemBINDINFO, szExtraInfo, 8)
+    TEST_FIELD_OFFSET(RemBINDINFO, szExtraInfo, 8)
+    TEST_FIELD_SIZE  (RemBINDINFO, grfBindInfoF, 4)
+    TEST_FIELD_ALIGN (RemBINDINFO, grfBindInfoF, 4)
+    TEST_FIELD_OFFSET(RemBINDINFO, grfBindInfoF, 16)
+    TEST_FIELD_SIZE  (RemBINDINFO, dwBindVerb, 4)
+    TEST_FIELD_ALIGN (RemBINDINFO, dwBindVerb, 4)
+    TEST_FIELD_OFFSET(RemBINDINFO, dwBindVerb, 20)
+    TEST_FIELD_SIZE  (RemBINDINFO, szCustomVerb, 8)
+    TEST_FIELD_ALIGN (RemBINDINFO, szCustomVerb, 8)
+    TEST_FIELD_OFFSET(RemBINDINFO, szCustomVerb, 24)
+    TEST_FIELD_SIZE  (RemBINDINFO, cbstgmedData, 4)
+    TEST_FIELD_ALIGN (RemBINDINFO, cbstgmedData, 4)
+    TEST_FIELD_OFFSET(RemBINDINFO, cbstgmedData, 32)
+    TEST_FIELD_SIZE  (RemBINDINFO, dwOptions, 4)
+    TEST_FIELD_ALIGN (RemBINDINFO, dwOptions, 4)
+    TEST_FIELD_OFFSET(RemBINDINFO, dwOptions, 36)
+    TEST_FIELD_SIZE  (RemBINDINFO, dwOptionsFlags, 4)
+    TEST_FIELD_ALIGN (RemBINDINFO, dwOptionsFlags, 4)
+    TEST_FIELD_OFFSET(RemBINDINFO, dwOptionsFlags, 40)
+    TEST_FIELD_SIZE  (RemBINDINFO, dwCodePage, 4)
+    TEST_FIELD_ALIGN (RemBINDINFO, dwCodePage, 4)
+    TEST_FIELD_OFFSET(RemBINDINFO, dwCodePage, 44)
+    TEST_FIELD_SIZE  (RemBINDINFO, securityAttributes, 12)
+    TEST_FIELD_ALIGN (RemBINDINFO, securityAttributes, 4)
+    TEST_FIELD_OFFSET(RemBINDINFO, securityAttributes, 48)
+    TEST_FIELD_SIZE  (RemBINDINFO, iid, 16)
+    TEST_FIELD_ALIGN (RemBINDINFO, iid, 4)
+    TEST_FIELD_OFFSET(RemBINDINFO, iid, 60)
+    TEST_FIELD_SIZE  (RemBINDINFO, pUnk, 8)
+    TEST_FIELD_ALIGN (RemBINDINFO, pUnk, 8)
+    TEST_FIELD_OFFSET(RemBINDINFO, pUnk, 80)
+    TEST_FIELD_SIZE  (RemBINDINFO, dwReserved, 4)
+    TEST_FIELD_ALIGN (RemBINDINFO, dwReserved, 4)
+    TEST_FIELD_OFFSET(RemBINDINFO, dwReserved, 88)
+}
+
+static void test_pack_RemFORMATETC(void)
+{
+    /* RemFORMATETC */
+    TEST_TYPE_SIZE   (RemFORMATETC, 20)
+    TEST_TYPE_ALIGN  (RemFORMATETC, 4)
+    TEST_FIELD_SIZE  (RemFORMATETC, cfFormat, 4)
+    TEST_FIELD_ALIGN (RemFORMATETC, cfFormat, 4)
+    TEST_FIELD_OFFSET(RemFORMATETC, cfFormat, 0)
+    TEST_FIELD_SIZE  (RemFORMATETC, ptd, 4)
+    TEST_FIELD_ALIGN (RemFORMATETC, ptd, 4)
+    TEST_FIELD_OFFSET(RemFORMATETC, ptd, 4)
+    TEST_FIELD_SIZE  (RemFORMATETC, dwAspect, 4)
+    TEST_FIELD_ALIGN (RemFORMATETC, dwAspect, 4)
+    TEST_FIELD_OFFSET(RemFORMATETC, dwAspect, 8)
+    TEST_FIELD_SIZE  (RemFORMATETC, lindex, 4)
+    TEST_FIELD_ALIGN (RemFORMATETC, lindex, 4)
+    TEST_FIELD_OFFSET(RemFORMATETC, lindex, 12)
+    TEST_FIELD_SIZE  (RemFORMATETC, tymed, 4)
+    TEST_FIELD_ALIGN (RemFORMATETC, tymed, 4)
+    TEST_FIELD_OFFSET(RemFORMATETC, tymed, 16)
+}
+
+#else /* _WIN64 */
 
 static void test_pack_BINDINFO(void)
 {
-    /* BINDINFO (pack 4) */
+    /* BINDINFO */
     TEST_FIELD_SIZE  (BINDINFO, cbSize, 4)
     TEST_FIELD_ALIGN (BINDINFO, cbSize, 4)
     TEST_FIELD_OFFSET(BINDINFO, cbSize, 0)
@@ -108,7 +352,7 @@ static void test_pack_IBindHost(void)
 
 static void test_pack_IBindHostVtbl(void)
 {
-    /* IBindHostVtbl (pack 4) */
+    /* IBindHostVtbl */
 }
 
 static void test_pack_IBindStatusCallback(void)
@@ -118,7 +362,7 @@ static void test_pack_IBindStatusCallback(void)
 
 static void test_pack_IBindStatusCallbackVtbl(void)
 {
-    /* IBindStatusCallbackVtbl (pack 4) */
+    /* IBindStatusCallbackVtbl */
 }
 
 static void test_pack_IBinding(void)
@@ -128,7 +372,7 @@ static void test_pack_IBinding(void)
 
 static void test_pack_IBindingVtbl(void)
 {
-    /* IBindingVtbl (pack 4) */
+    /* IBindingVtbl */
 }
 
 static void test_pack_IInternetProtocolInfo(void)
@@ -138,7 +382,7 @@ static void test_pack_IInternetProtocolInfo(void)
 
 static void test_pack_IInternetProtocolInfoVtbl(void)
 {
-    /* IInternetProtocolInfoVtbl (pack 4) */
+    /* IInternetProtocolInfoVtbl */
 }
 
 static void test_pack_IInternetSession(void)
@@ -148,7 +392,7 @@ static void test_pack_IInternetSession(void)
 
 static void test_pack_IInternetSessionVtbl(void)
 {
-    /* IInternetSessionVtbl (pack 4) */
+    /* IInternetSessionVtbl */
 }
 
 static void test_pack_IPersistMoniker(void)
@@ -158,7 +402,7 @@ static void test_pack_IPersistMoniker(void)
 
 static void test_pack_IPersistMonikerVtbl(void)
 {
-    /* IPersistMonikerVtbl (pack 4) */
+    /* IPersistMonikerVtbl */
 }
 
 static void test_pack_IWinInetHttpInfo(void)
@@ -168,7 +412,7 @@ static void test_pack_IWinInetHttpInfo(void)
 
 static void test_pack_IWinInetHttpInfoVtbl(void)
 {
-    /* IWinInetHttpInfoVtbl (pack 4) */
+    /* IWinInetHttpInfoVtbl */
 }
 
 static void test_pack_IWinInetInfo(void)
@@ -178,7 +422,7 @@ static void test_pack_IWinInetInfo(void)
 
 static void test_pack_IWinInetInfoVtbl(void)
 {
-    /* IWinInetInfoVtbl (pack 4) */
+    /* IWinInetInfoVtbl */
 }
 
 static void test_pack_LPBINDHOST(void)
@@ -260,7 +504,7 @@ static void test_pack_PREMSECURITY_ATTRIBUTES(void)
 
 static void test_pack_REMSECURITY_ATTRIBUTES(void)
 {
-    /* REMSECURITY_ATTRIBUTES (pack 4) */
+    /* REMSECURITY_ATTRIBUTES */
     TEST_TYPE_SIZE   (REMSECURITY_ATTRIBUTES, 12)
     TEST_TYPE_ALIGN  (REMSECURITY_ATTRIBUTES, 4)
     TEST_FIELD_SIZE  (REMSECURITY_ATTRIBUTES, nLength, 4)
@@ -276,7 +520,7 @@ static void test_pack_REMSECURITY_ATTRIBUTES(void)
 
 static void test_pack_RemBINDINFO(void)
 {
-    /* RemBINDINFO (pack 4) */
+    /* RemBINDINFO */
     TEST_TYPE_SIZE   (RemBINDINFO, 72)
     TEST_TYPE_ALIGN  (RemBINDINFO, 4)
     TEST_FIELD_SIZE  (RemBINDINFO, cbSize, 4)
@@ -322,7 +566,7 @@ static void test_pack_RemBINDINFO(void)
 
 static void test_pack_RemFORMATETC(void)
 {
-    /* RemFORMATETC (pack 4) */
+    /* RemFORMATETC */
     TEST_TYPE_SIZE   (RemFORMATETC, 20)
     TEST_TYPE_ALIGN  (RemFORMATETC, 4)
     TEST_FIELD_SIZE  (RemFORMATETC, cfFormat, 4)
@@ -342,6 +586,8 @@ static void test_pack_RemFORMATETC(void)
     TEST_FIELD_OFFSET(RemFORMATETC, tymed, 16)
 }
 
+#endif /* _WIN64 */
+
 static void test_pack(void)
 {
     test_pack_BINDINFO();
@@ -379,9 +625,5 @@ static void test_pack(void)
 
 START_TEST(generated)
 {
-#ifdef _WIN64
-    ok(0, "The type size / alignment tests don't support Win64 yet\n");
-#else
     test_pack();
-#endif
 }
index 2e77c1b..259c5a0 100644 (file)
@@ -63,6 +63,8 @@ DEFINE_EXPECT(QI_IInternetProtocolInfo);
 DEFINE_EXPECT(CreateInstance);
 DEFINE_EXPECT(unk_Release);
 
+static HRESULT (WINAPI *pCoInternetCompareUrl)(LPCWSTR, LPCWSTR, DWORD);
+
 static void test_CreateFormatEnum(void)
 {
     IEnumFORMATETC *fenum = NULL, *fenum2 = NULL;
@@ -363,13 +365,18 @@ static void test_CoInternetCompareUrl(void)
 {
     HRESULT hres;
 
-    hres = CoInternetCompareUrl(url1, url1, 0);
+    if (!pCoInternetCompareUrl) {
+        win_skip("CoInternetCompareUrl not found\n");
+        return;
+    }
+
+    hres = pCoInternetCompareUrl(url1, url1, 0);
     ok(hres == S_OK, "CoInternetParseUrl failed: %08x\n", hres);
 
-    hres = CoInternetCompareUrl(url1, url3, 0);
+    hres = pCoInternetCompareUrl(url1, url3, 0);
     ok(hres == S_FALSE, "CoInternetParseUrl failed: %08x\n", hres);
 
-    hres = CoInternetCompareUrl(url3, url1, 0);
+    hres = pCoInternetCompareUrl(url3, url1, 0);
     ok(hres == S_FALSE, "CoInternetParseUrl failed: %08x\n", hres);
 }
 
@@ -1402,10 +1409,15 @@ static void test_IsValidURL(void)
 
 START_TEST(misc)
 {
+    HMODULE hurlmon;
+
     OleInitialize(NULL);
 
     register_protocols();
 
+    hurlmon = GetModuleHandle("urlmon.dll");
+    pCoInternetCompareUrl = (void *) GetProcAddress(hurlmon, "CoInternetCompareUrl");
+
     test_CreateFormatEnum();
     test_RegisterFormatEnumerator();
     test_CoInternetParseUrl();
index e441698..239da6c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005-2006 Jacek Caban for CodeWeavers
- * Copyright 2009 Detlef Riekenberg
+ * Copyright 2009-2010 Detlef Riekenberg
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 #include "initguid.h"
 
+static HRESULT (WINAPI *pCoInternetGetSecurityUrl)(LPCWSTR, LPWSTR*, PSUACTION, DWORD);
+
 static const WCHAR url1[] = {'r','e','s',':','/','/','m','s','h','t','m','l','.','d','l','l',
         '/','b','l','a','n','k','.','h','t','m',0};
 static const WCHAR url2[] = {'i','n','d','e','x','.','h','t','m',0};
 static const WCHAR url3[] = {'f','i','l','e',':','/','/','c',':','\\','I','n','d','e','x','.','h','t','m',0};
 static const WCHAR url4[] = {'f','i','l','e',':','s','o','m','e','%','2','0','f','i','l','e',
         '%','2','e','j','p','g',0};
-static const WCHAR url5[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q',
-        '.','o','r','g',0};
+static const WCHAR url5[] = {'h','t','t','p',':','/','/','w','w','w','.','z','o','n','e','3',
+        '.','w','i','n','e','t','e','s','t',0};
 static const WCHAR url6[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
-static const WCHAR url7[] = {'f','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g','/',
-        'f','i','l','e','.','t','e','s','t',0};
+static const WCHAR url7[] = {'f','t','p',':','/','/','z','o','n','e','3',
+        '.','w','i','n','e','t','e','s','t','/','f','i','l','e','.','t','e','s','t',0};
 static const WCHAR url8[] = {'t','e','s','t',':','1','2','3','a','b','c',0};
-static const WCHAR url9[] =
-    {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
-     '/','s','i','t','e','/','a','b','o','u','t',0};
+static const WCHAR url9[] = {'h','t','t','p',':','/','/','w','w','w','.','z','o','n','e','3',
+        '.','w','i','n','e','t','e','s','t', '/','s','i','t','e','/','a','b','o','u','t',0};
 static const WCHAR url10[] = {'f','i','l','e',':','/','/','s','o','m','e','%','2','0','f','i','l','e',
         '.','j','p','g',0};
 
@@ -58,11 +59,11 @@ static const WCHAR url4e[] = {'f','i','l','e',':','s','o','m','e',' ','f','i','l
 
 
 static const BYTE secid1[] = {'f','i','l','e',':',0,0,0,0};
-static const BYTE secid5[] = {'h','t','t','p',':','w','w','w','.','w','i','n','e','h','q',
-    '.','o','r','g',3,0,0,0};
+static const BYTE secid5[] = {'h','t','t','p',':','w','w','w','.','z','o','n','e','3',
+        '.','w','i','n','e','t','e','s','t',3,0,0,0};
 static const BYTE secid6[] = {'a','b','o','u','t',':','b','l','a','n','k',3,0,0,0};
-static const BYTE secid7[] = {'f','t','p',':','w','i','n','e','h','q','.','o','r','g',
-                              3,0,0,0};
+static const BYTE secid7[] = {'f','t','p',':','z','o','n','e','3',
+        '.','w','i','n','e','t','e','s','t',3,0,0,0};
 static const BYTE secid10[] =
     {'f','i','l','e',':','s','o','m','e','%','2','0','f','i','l','e','.','j','p','g',3,0,0,0};
 static const BYTE secid10_2[] =
@@ -632,7 +633,9 @@ static void test_InternetSecurityMarshalling(void)
     ok(hres == S_OK, "CreateStreamOnHGlobal returned: %08x\n", hres);
 
     hres = CoMarshalInterface(stream, &IID_IInternetSecurityManager, unk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
-    ok(hres == S_OK, "CoMarshalInterface returned: %08x\n", hres);
+    /* Not supported in W98 */
+    ok(hres == S_OK || broken(hres == REGDB_E_IIDNOTREG),
+        "CoMarshalInterface returned: %08x\n", hres);
 
     IStream_Release(stream);
     IUnknown_Release(unk);
@@ -641,8 +644,9 @@ static void test_InternetSecurityMarshalling(void)
 
 static void test_InternetGetSecurityUrl(void)
 {
-    const WCHAR url5_out[] = {'h','t','t','p',':','w','w','w','.','w','i','n','e','h','q','.','o','r','g',0};
-    const WCHAR url7_out[] = {'f','t','p',':','w','i','n','e','h','q','.','o','r','g',0};
+    const WCHAR url5_out[] = {'h','t','t','p',':','w','w','w','.','z','o','n','e','3',
+                              '.','w','i','n','e','t','e','s','t',0};
+    const WCHAR url7_out[] = {'f','t','p',':','z','o','n','e','3','.','w','i','n','e','t','e','s','t',0};
 
     const WCHAR *in[] = {url2, url3, url4, url5, url7, url8, url9, url10};
     const WCHAR *out_default[] = {url2, url3, url4, url5_out, url7_out, url8, url5_out, url10};
@@ -652,8 +656,13 @@ static void test_InternetGetSecurityUrl(void)
     DWORD i;
     HRESULT hres;
 
+    if (!pCoInternetGetSecurityUrl) {
+        win_skip("CoInternetGetSecurityUrl not found\n");
+        return;
+    }
+
     for(i=0; i<sizeof(in)/sizeof(WCHAR*); i++) {
-        hres = CoInternetGetSecurityUrl(in[i], &sec, PSU_DEFAULT, 0);
+        hres = pCoInternetGetSecurityUrl(in[i], &sec, PSU_DEFAULT, 0);
         ok(hres == S_OK, "(%d) CoInternetGetSecurityUrl returned: %08x\n", i, hres);
         if(hres == S_OK) {
             ok(!strcmp_w(sec, out_default[i]), "(%d) Got %s, expected %s\n",
@@ -661,7 +670,7 @@ static void test_InternetGetSecurityUrl(void)
             CoTaskMemFree(sec);
         }
 
-        hres = CoInternetGetSecurityUrl(in[i], &sec, PSU_SECURITY_URL_ONLY, 0);
+        hres = pCoInternetGetSecurityUrl(in[i], &sec, PSU_SECURITY_URL_ONLY, 0);
         ok(hres == S_OK, "(%d) CoInternetGetSecurityUrl returned: %08x\n", i, hres);
         if(hres == S_OK) {
             ok(!strcmp_w(sec, out_securl[i]), "(%d) Got %s, expected %s\n",
@@ -674,8 +683,13 @@ static void test_InternetGetSecurityUrl(void)
 
 START_TEST(sec_mgr)
 {
+    HMODULE hurlmon;
+
     OleInitialize(NULL);
 
+    hurlmon = GetModuleHandle("urlmon.dll");
+    pCoInternetGetSecurityUrl = (void*) GetProcAddress(hurlmon, "CoInternetGetSecurityUrl");
+
     test_InternetGetSecurityUrl();
     test_SecurityManager();
     test_polices();
index d5b9d12..09cbb42 100644 (file)
@@ -1388,7 +1388,7 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallbackEx *iface, ULONG u
             CHECK_EXPECT(Obj_OnProgress_CLASSIDAVAILABLE);
         else
             todo_wine CHECK_EXPECT(Obj_OnProgress_CLASSIDAVAILABLE);
-        hr = CLSIDFromString((LPOLESTR)szStatusText, &clsid);
+        hr = CLSIDFromString((LPCOLESTR)szStatusText, &clsid);
         ok(hr == S_OK, "CLSIDFromString failed with error 0x%08x\n", hr);
         ok(IsEqualCLSID(&clsid, &CLSID_HTMLDocument),
             "Expected clsid to be CLSID_HTMLDocument instead of %s\n", debugstr_guid(&clsid));
index 5795e90..b7f3d2f 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright 2006 Jeff Latimer
  * Copyright 2006 Hans Leidekker
+ * Copyright 2010 CodeWeavers, Aric Stewart
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <windows.h>
 #include <usp10.h>
 
-static void test_ScriptShape(HDC hdc)
+static void test_ScriptItemize( void )
 {
     static const WCHAR test1[] = {'t', 'e', 's', 't',0};
-    BOOL ret;
+    static const WCHAR test2[] = {'1','2','3','-','5','2',0x064a,0x064f,0x0633,0x0627,0x0648,0x0650,0x064a,'7','1','.',0};
+    static const WCHAR test3[] =
+{0x0e04,0x0e27,0x0e32,0x0e21,0x0e1e,0x0e22,0x0e32,0x0e22,0x0e32, 0x0e21
+,0x0e2d,0x0e22,0x0e39,0x0e48,0x0e17,0x0e35,0x0e48,0x0e44,0x0e2b,0x0e19
+,0x0e04,0x0e27,0x0e32,0x0e21,0x0e2a, 0x0e33,0x0e40,0x0e23,0x0e47,0x0e08,
+ 0x0e2d,0x0e22,0x0e39,0x0e48,0x0e17,0x0e35,0x0e48,0x0e19,0x0e31,0x0e48,0x0e19,0};
+    static const WCHAR test4[]  = {'1','2','3','-','5','2',' ','i','s',' ','7','1','.',0};
+    static const WCHAR test5[]  =
+{0x0627,0x0644,0x0635,0x0651,0x0650,0x062d,0x0629,0x064f,' ',0x062a,0x064e,
+0x0627,0x062c,0x064c,' ',0x0639,0x064e,0x0644,0x0649,' ',
+0x0631,0x064f,0x0624,0x0648,0x0633,0x0650,' ',0x0627,0x0644
+,0x0623,0x0635,0x0650,0x062d,0x0651,0x064e,0x0627,0x0621,0x0650,0};
+    SCRIPT_ITEM items[10];
+    SCRIPT_CONTROL  Control;
+    SCRIPT_STATE    State;
+    HRESULT hr;
+    int nItems;
+
+    memset(&Control, 0, sizeof(Control));
+    memset(&State, 0, sizeof(State));
+
+    hr = ScriptItemize(NULL, 4, 10, &Control, &State, items, NULL);
+    ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pwcInChars is NULL\n");
+
+    hr = ScriptItemize(test1, 4, 10, &Control, &State, NULL, NULL);
+    ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pItems is NULL\n");
+
+    hr = ScriptItemize(test1, 4, 1, &Control, &State, items, NULL);
+    ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cMaxItems < 2.");
+
+    hr = ScriptItemize(test1, 0, 10, NULL, NULL, items, &nItems);
+    ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cInChars is 0\n");
+
+    hr = ScriptItemize(test1, 4, 10, NULL, NULL, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 1, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+
+    State.uBidiLevel = 0;
+    hr = ScriptItemize(test1, 4, 10, &Control, &State, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 1, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+
+    State.uBidiLevel = 1;
+    hr = ScriptItemize(test1, 4, 10, &Control, &State, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 1, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    todo_wine ok(items[0].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
+
+    hr = ScriptItemize(test2, 16, 10, NULL, NULL, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 6, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+    ok(items[1].iCharPos == 3, "Wrong CharPos \n");
+    ok(items[1].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[1].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[1].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+    ok(items[2].iCharPos == 4, "Wrong CharPos \n");
+    ok(items[2].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[2].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[2].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+    ok(items[3].iCharPos == 6, "Wrong CharPos \n");
+    ok(items[3].a.fRTL == 1, "Wrong fRTL\n");
+    ok(items[3].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
+    ok(items[3].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
+    ok(items[4].iCharPos == 13, "Wrong CharPos \n");
+    ok(items[4].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[4].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[4].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+    ok(items[5].iCharPos == 15, "Wrong CharPos \n");
+    ok(items[5].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[5].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[5].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+
+    State.uBidiLevel = 0;
+    hr = ScriptItemize(test2, 16, 10, &Control, &State, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 4, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    todo_wine ok(items[0].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
+    ok(items[1].iCharPos == 6, "Wrong CharPos \n");
+    ok(items[1].a.fRTL == 1, "Wrong fRTL\n");
+    ok(items[1].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
+    ok(items[1].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
+    ok(items[2].iCharPos == 13, "Wrong CharPos \n");
+    ok(items[2].a.fRTL == 0, "Wrong fRTL\n");
+    todo_wine ok(items[2].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
+    ok(items[2].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
+    ok(items[3].iCharPos == 15, "Wrong CharPos \n");
+    ok(items[3].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[3].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[3].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+
+    State.uBidiLevel = 1;
+    hr = ScriptItemize(test2, 16, 10, &Control, &State, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 4, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
+    todo_wine ok(items[0].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
+    ok(items[0].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
+    ok(items[1].iCharPos == 6, "Wrong CharPos \n");
+    ok(items[1].a.fRTL == 1, "Wrong fRTL\n");
+    ok(items[1].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
+    ok(items[1].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
+    ok(items[2].iCharPos == 13, "Wrong CharPos \n");
+    ok(items[2].a.fRTL == 0, "Wrong fRTL\n");
+    todo_wine ok(items[2].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
+    ok(items[2].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
+    ok(items[3].iCharPos == 15, "Wrong CharPos \n");
+    ok(items[3].a.fRTL == 1, "Wrong fRTL\n");
+    ok(items[3].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
+    ok(items[3].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
+
+    hr = ScriptItemize(test3, 41, 10, NULL, NULL, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 1, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+
+    State.uBidiLevel = 0;
+    hr = ScriptItemize(test3, 41, 10, &Control, &State, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 1, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+
+    State.uBidiLevel = 1;
+    hr = ScriptItemize(test3, 41, 10, &Control, &State, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 1, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    todo_wine ok(items[0].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
+
+    hr = ScriptItemize(test4, 12, 10, NULL, NULL, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 5, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+    ok(items[1].iCharPos == 3, "Wrong CharPos \n");
+    ok(items[1].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[1].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[1].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+    ok(items[2].iCharPos == 4, "Wrong CharPos \n");
+    ok(items[2].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[2].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[2].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+    ok(items[3].iCharPos == 7, "Wrong CharPos \n");
+    ok(items[3].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[3].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[3].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+    ok(items[4].iCharPos == 10, "Wrong CharPos \n");
+    ok(items[4].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[4].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[4].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+
+    State.uBidiLevel = 0;
+    hr = ScriptItemize(test4, 12, 10, &Control, &State, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 5, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[0].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+    ok(items[1].iCharPos == 3, "Wrong CharPos \n");
+    ok(items[1].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[1].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[1].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+    ok(items[2].iCharPos == 4, "Wrong CharPos \n");
+    ok(items[2].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[2].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[2].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+    ok(items[3].iCharPos == 7, "Wrong CharPos \n");
+    ok(items[3].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[3].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[3].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+    ok(items[4].iCharPos == 10, "Wrong CharPos \n");
+    ok(items[4].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[4].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[4].a.s.uBidiLevel == 0, "Wrong BidiLevel\n");
+
+    State.uBidiLevel = 1;
+    hr = ScriptItemize(test4, 12, 10, &Control, &State, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    todo_wine ok(nItems == 4, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 0, "Wrong fRTL\n");
+    todo_wine ok(items[0].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
+    ok(items[0].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
+    ok(items[1].iCharPos == 6, "Wrong CharPos \n");
+    ok(items[1].a.fRTL == 1, "Wrong fRTL\n");
+    ok(items[1].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
+    ok(items[1].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
+    ok(items[2].iCharPos == 7, "Wrong CharPos \n");
+    ok(items[2].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[2].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    ok(items[2].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
+    todo_wine ok(items[3].iCharPos == 10, "Wrong CharPos \n");
+    ok(items[3].a.fRTL == 0, "Wrong fRTL\n");
+    ok(items[3].a.fLayoutRTL == 0, "Wrong fLayoutRTL\n");
+    todo_wine ok(items[3].a.s.uBidiLevel == 2, "Wrong BidiLevel\n");
+
+    hr = ScriptItemize(test5, 38, 10, NULL, NULL, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 1, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 1, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
+    ok(items[0].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
+
+    State.uBidiLevel = 0;
+    hr = ScriptItemize(test5, 38, 10, &Control, &State, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 1, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 1, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
+    ok(items[0].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
+
+    State.uBidiLevel = 1;
+    hr = ScriptItemize(test5, 38, 10, &Control, &State, items, &nItems);
+    ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
+    ok(nItems == 1, "Wrong number of items\n");
+    ok(items[0].iCharPos == 0, "Wrong CharPos \n");
+    ok(items[0].a.fRTL == 1, "Wrong fRTL\n");
+    ok(items[0].a.fLayoutRTL == 1, "Wrong fLayoutRTL\n");
+    ok(items[0].a.s.uBidiLevel == 1, "Wrong BidiLevel\n");
+}
+
+
+static void test_ScriptShape(HDC hdc)
+{
+    static const WCHAR test1[] = {'w', 'i', 'n', 'e',0};
+    static const WCHAR test2[] = {0x202B, 'i', 'n', 0x202C,0};
     HRESULT hr;
     SCRIPT_CACHE sc = NULL;
-    WORD glyphs[4], logclust[4];
+    WORD glyphs[4], glyphs2[4], logclust[4];
     SCRIPT_VISATTR attrs[4];
     SCRIPT_ITEM items[2];
-    int nb, widths[4];
-    GOFFSET offset[4];
-    ABC abc[4];
-
-    hr = ScriptItemize(NULL, 4, 2, NULL, NULL, items, NULL);
-    ok(hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG not %08x\n", hr);
-
-    hr = ScriptItemize(test1, 4, 2, NULL, NULL, NULL, NULL);
-    ok(hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG not %08x\n", hr);
+    int nb;
 
     hr = ScriptItemize(test1, 4, 2, NULL, NULL, items, NULL);
     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
@@ -73,8 +322,122 @@ static void test_ScriptShape(HDC hdc)
     ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
 
+
+    memset(glyphs,-1,sizeof(glyphs));
+    memset(logclust,-1,sizeof(logclust));
+    memset(attrs,-1,sizeof(attrs));
     hr = ScriptShape(NULL, &sc, test1, 4, 4, &items[0].a, glyphs, logclust, attrs, &nb);
     ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
+    ok(nb == 4, "Wrong number of items\n");
+    ok(logclust[0] == 0, "clusters out of order\n");
+    ok(logclust[1] == 1, "clusters out of order\n");
+    ok(logclust[2] == 2, "clusters out of order\n");
+    ok(logclust[3] == 3, "clusters out of order\n");
+    ok(attrs[0].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
+    ok(attrs[1].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
+    ok(attrs[2].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
+    ok(attrs[3].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
+    ok(attrs[0].fClusterStart == 1, "fClusterStart incorrect\n");
+    ok(attrs[1].fClusterStart == 1, "fClusterStart incorrect\n");
+    ok(attrs[2].fClusterStart == 1, "fClusterStart incorrect\n");
+    ok(attrs[3].fClusterStart == 1, "fClusterStart incorrect\n");
+    ok(attrs[0].fDiacritic == 0, "fDiacritic incorrect\n");
+    ok(attrs[1].fDiacritic == 0, "fDiacritic incorrect\n");
+    ok(attrs[2].fDiacritic == 0, "fDiacritic incorrect\n");
+    ok(attrs[3].fDiacritic == 0, "fDiacritic incorrect\n");
+    ok(attrs[0].fZeroWidth == 0, "fZeroWidth incorrect\n");
+    ok(attrs[1].fZeroWidth == 0, "fZeroWidth incorrect\n");
+    ok(attrs[2].fZeroWidth == 0, "fZeroWidth incorrect\n");
+    ok(attrs[3].fZeroWidth == 0, "fZeroWidth incorrect\n");
+
+    ScriptFreeCache(&sc);
+    sc = NULL;
+
+    memset(glyphs2,-1,sizeof(glyphs2));
+    memset(logclust,-1,sizeof(logclust));
+    memset(attrs,-1,sizeof(attrs));
+    hr = ScriptShape(hdc, &sc, test2, 4, 4, &items[0].a, glyphs2, logclust, attrs, &nb);
+    ok(hr == S_OK, "ScriptShape should return S_OK not %08x\n", hr);
+    ok(nb == 4, "Wrong number of items\n");
+    ok(glyphs2[0] == 0, "Incorrect glyph for 0x202B\n");
+    ok(glyphs2[3] == 0, "Incorrect glyph for 0x202C\n");
+    ok(logclust[0] == 0, "clusters out of order\n");
+    ok(logclust[1] == 1, "clusters out of order\n");
+    ok(logclust[2] == 2, "clusters out of order\n");
+    ok(logclust[3] == 3, "clusters out of order\n");</