- Sync msctf, mscoree, mciqtz32, localspl, inetmib1 with Wine 1.1.21
authorDmitry Chapyshev <dmitry@reactos.org>
Sat, 9 May 2009 09:24:59 +0000 (09:24 +0000)
committerDmitry Chapyshev <dmitry@reactos.org>
Sat, 9 May 2009 09:24:59 +0000 (09:24 +0000)
svn path=/trunk/; revision=40850

12 files changed:
reactos/dll/win32/inetmib1/main.c
reactos/dll/win32/localspl/localspl_private.h
reactos/dll/win32/localspl/provider.c
reactos/dll/win32/mciqtz32/mciqtz.c
reactos/dll/win32/mciqtz32/mciqtz_private.h
reactos/dll/win32/mscoree/mscoree.spec
reactos/dll/win32/mscoree/mscoree_main.c
reactos/dll/win32/msctf/categorymgr.c
reactos/dll/win32/msctf/inputprocessor.c
reactos/dll/win32/msctf/msctf.c
reactos/dll/win32/msctf/msctf_internal.h
reactos/dll/win32/msctf/threadmgr.c

index 3b39174..1093117 100644 (file)
@@ -125,6 +125,7 @@ static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind,
     AsnInteger32 *pErrorStatus)
 {
     AsnObjectIdentifier numberOid = DEFINE_OID(mib2IfNumber);
+    BOOL ret = TRUE;
 
     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
         pErrorStatus);
@@ -155,12 +156,13 @@ static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind,
         break;
     case SNMP_PDU_SET:
         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
+        ret = FALSE;
         break;
     default:
         FIXME("0x%02x: unsupported PDU type\n", bPduType);
         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
     }
-    return TRUE;
+    return ret;
 }
 
 static void copyOperStatus(AsnAny *value, void *src)
@@ -431,45 +433,61 @@ static AsnInteger32 getItemAndInstanceFromTable(AsnObjectIdentifier *oid,
     return ret;
 }
 
-static void setOidWithItem(AsnObjectIdentifier *dst, AsnObjectIdentifier *base,
+static INT setOidWithItem(AsnObjectIdentifier *dst, AsnObjectIdentifier *base,
     UINT item)
 {
     UINT id;
     AsnObjectIdentifier oid;
+    INT ret;
 
-    SnmpUtilOidCpy(dst, base);
-    oid.idLength = 1;
-    oid.ids = &id;
-    id = item;
-    SnmpUtilOidAppend(dst, &oid);
+    ret = SnmpUtilOidCpy(dst, base);
+    if (ret)
+    {
+        oid.idLength = 1;
+        oid.ids = &id;
+        id = item;
+        ret = SnmpUtilOidAppend(dst, &oid);
+    }
+    return ret;
 }
 
-static void setOidWithItemAndIpAddr(AsnObjectIdentifier *dst,
+static INT setOidWithItemAndIpAddr(AsnObjectIdentifier *dst,
     AsnObjectIdentifier *base, UINT item, DWORD addr)
 {
     UINT id;
     BYTE *ptr;
     AsnObjectIdentifier oid;
+    INT ret;
 
-    setOidWithItem(dst, base, item);
-    oid.idLength = 1;
-    oid.ids = &id;
-    for (ptr = (BYTE *)&addr; ptr < (BYTE *)&addr + sizeof(DWORD); ptr++)
+    ret = setOidWithItem(dst, base, item);
+    if (ret)
     {
-        id = *ptr;
-        SnmpUtilOidAppend(dst, &oid);
+        oid.idLength = 1;
+        oid.ids = &id;
+        for (ptr = (BYTE *)&addr; ret && ptr < (BYTE *)&addr + sizeof(DWORD);
+         ptr++)
+        {
+            id = *ptr;
+            ret = SnmpUtilOidAppend(dst, &oid);
+        }
     }
+    return ret;
 }
 
-static void setOidWithItemAndInteger(AsnObjectIdentifier *dst,
+static INT setOidWithItemAndInteger(AsnObjectIdentifier *dst,
     AsnObjectIdentifier *base, UINT item, UINT instance)
 {
     AsnObjectIdentifier oid;
+    INT ret;
 
-    setOidWithItem(dst, base, item);
-    oid.idLength = 1;
-    oid.ids = &instance;
-    SnmpUtilOidAppend(dst, &oid);
+    ret = setOidWithItem(dst, base, item);
+    if (ret)
+    {
+        oid.idLength = 1;
+        oid.ids = &instance;
+        ret = SnmpUtilOidAppend(dst, &oid);
+    }
+    return ret;
 }
 
 static struct structToAsnValue mib2IfEntryMap[] = {
@@ -502,6 +520,7 @@ static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
     AsnInteger32 *pErrorStatus)
 {
     AsnObjectIdentifier entryOid = DEFINE_OID(mib2IfEntry);
+    BOOL ret = TRUE;
 
     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
         pErrorStatus);
@@ -536,20 +555,21 @@ static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
                         &ifTable->table[tableIndex - 1], item, bPduType,
                         pVarBind);
                     if (bPduType == SNMP_PDU_GETNEXT)
-                        setOidWithItemAndInteger(&pVarBind->name, &entryOid,
-                            item, tableIndex);
+                        ret = setOidWithItemAndInteger(&pVarBind->name,
+                            &entryOid, item, tableIndex);
                 }
             }
         }
         break;
     case SNMP_PDU_SET:
         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
+        ret = FALSE;
         break;
     default:
         FIXME("0x%02x: unsupported PDU type\n", bPduType);
         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
     }
-    return TRUE;
+    return ret;
 }
 
 static UINT mib2Ip[] = { 1,3,6,1,2,1,4 };
@@ -591,6 +611,7 @@ static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind,
 {
     AsnObjectIdentifier myOid = DEFINE_OID(mib2Ip);
     UINT item = 0;
+    BOOL ret = TRUE;
 
     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
         pErrorStatus);
@@ -606,17 +627,18 @@ static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind,
             *pErrorStatus = mapStructEntryToValue(mib2IpMap,
                 DEFINE_SIZEOF(mib2IpMap), &ipStats, item, bPduType, pVarBind);
             if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
-                setOidWithItem(&pVarBind->name, &myOid, item);
+                ret = setOidWithItem(&pVarBind->name, &myOid, item);
         }
         break;
     case SNMP_PDU_SET:
         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
+        ret = FALSE;
         break;
     default:
         FIXME("0x%02x: unsupported PDU type\n", bPduType);
         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
     }
-    return TRUE;
+    return ret;
 }
 
 static UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1 };
@@ -669,6 +691,7 @@ static BOOL mib2IpAddrQuery(BYTE bPduType, SnmpVarBind *pVarBind,
 {
     AsnObjectIdentifier myOid = DEFINE_OID(mib2IpAddr);
     UINT tableIndex = 0, item = 0;
+    BOOL ret = TRUE;
 
     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
         pErrorStatus);
@@ -689,18 +712,19 @@ static BOOL mib2IpAddrQuery(BYTE bPduType, SnmpVarBind *pVarBind,
                 DEFINE_SIZEOF(mib2IpAddrMap),
                 &ipAddrTable->table[tableIndex - 1], item, bPduType, pVarBind);
             if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
-                setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
+                ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
                     ipAddrTable->table[tableIndex - 1].dwAddr);
         }
         break;
     case SNMP_PDU_SET:
         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
+        ret = FALSE;
         break;
     default:
         FIXME("0x%02x: unsupported PDU type\n", bPduType);
         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
     }
-    return TRUE;
+    return ret;
 }
 
 static UINT mib2IpRoute[] = { 1,3,6,1,2,1,4,21,1 };
@@ -760,6 +784,7 @@ static BOOL mib2IpRouteQuery(BYTE bPduType, SnmpVarBind *pVarBind,
 {
     AsnObjectIdentifier myOid = DEFINE_OID(mib2IpRoute);
     UINT tableIndex = 0, item = 0;
+    BOOL ret = TRUE;
 
     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
         pErrorStatus);
@@ -780,18 +805,19 @@ static BOOL mib2IpRouteQuery(BYTE bPduType, SnmpVarBind *pVarBind,
                 DEFINE_SIZEOF(mib2IpRouteMap),
                 &ipRouteTable->table[tableIndex - 1], item, bPduType, pVarBind);
             if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
-                setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
+                ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
                     ipRouteTable->table[tableIndex - 1].dwForwardDest);
         }
         break;
     case SNMP_PDU_SET:
         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
+        ret = FALSE;
         break;
     default:
         FIXME("0x%02x: unsupported PDU type\n", bPduType);
         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
     }
-    return TRUE;
+    return ret;
 }
 
 static UINT mib2IpNet[] = { 1,3,6,1,2,1,4,22,1 };
@@ -828,6 +854,7 @@ static BOOL mib2IpNetQuery(BYTE bPduType, SnmpVarBind *pVarBind,
     AsnInteger32 *pErrorStatus)
 {
     AsnObjectIdentifier myOid = DEFINE_OID(mib2IpNet);
+    BOOL ret = TRUE;
 
     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
         pErrorStatus);
@@ -856,20 +883,21 @@ static BOOL mib2IpNetQuery(BYTE bPduType, SnmpVarBind *pVarBind,
                         DEFINE_SIZEOF(mib2IpNetMap),
                         &ipNetTable[tableIndex - 1], item, bPduType, pVarBind);
                     if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
-                        setOidWithItemAndInteger(&pVarBind->name, &myOid, item,
-                            tableIndex);
+                        ret = setOidWithItemAndInteger(&pVarBind->name, &myOid,
+                            item, tableIndex);
                 }
             }
         }
         break;
     case SNMP_PDU_SET:
         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
+        ret = FALSE;
         break;
     default:
         FIXME("0x%02x: unsupported PDU type\n", bPduType);
         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
     }
-    return TRUE;
+    return ret;
 }
 
 static UINT mib2Icmp[] = { 1,3,6,1,2,1,5 };
@@ -914,6 +942,7 @@ static BOOL mib2IcmpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
 {
     AsnObjectIdentifier myOid = DEFINE_OID(mib2Icmp);
     UINT item = 0;
+    BOOL ret = TRUE;
 
     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
         pErrorStatus);
@@ -930,17 +959,18 @@ static BOOL mib2IcmpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
                 DEFINE_SIZEOF(mib2IcmpMap), &icmpStats, item, bPduType,
                 pVarBind);
             if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
-                setOidWithItem(&pVarBind->name, &myOid, item);
+                ret = setOidWithItem(&pVarBind->name, &myOid, item);
         }
         break;
     case SNMP_PDU_SET:
         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
+        ret = FALSE;
         break;
     default:
         FIXME("0x%02x: unsupported PDU type\n", bPduType);
         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
     }
-    return TRUE;
+    return ret;
 }
 
 static UINT mib2Tcp[] = { 1,3,6,1,2,1,6 };
@@ -974,6 +1004,7 @@ static BOOL mib2TcpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
 {
     AsnObjectIdentifier myOid = DEFINE_OID(mib2Tcp);
     UINT item = 0;
+    BOOL ret = TRUE;
 
     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
         pErrorStatus);
@@ -989,17 +1020,18 @@ static BOOL mib2TcpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
             *pErrorStatus = mapStructEntryToValue(mib2TcpMap,
                 DEFINE_SIZEOF(mib2TcpMap), &tcpStats, item, bPduType, pVarBind);
             if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
-                setOidWithItem(&pVarBind->name, &myOid, item);
+                ret = setOidWithItem(&pVarBind->name, &myOid, item);
         }
         break;
     case SNMP_PDU_SET:
         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
+        ret = FALSE;
         break;
     default:
         FIXME("0x%02x: unsupported PDU type\n", bPduType);
         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
     }
-    return TRUE;
+    return ret;
 }
 
 static UINT mib2Udp[] = { 1,3,6,1,2,1,7 };
@@ -1022,6 +1054,7 @@ static BOOL mib2UdpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
 {
     AsnObjectIdentifier myOid = DEFINE_OID(mib2Udp);
     UINT item;
+    BOOL ret = TRUE;
 
     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
         pErrorStatus);
@@ -1037,17 +1070,18 @@ static BOOL mib2UdpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
             *pErrorStatus = mapStructEntryToValue(mib2UdpMap,
                 DEFINE_SIZEOF(mib2UdpMap), &udpStats, item, bPduType, pVarBind);
             if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
-                setOidWithItem(&pVarBind->name, &myOid, item);
+                ret = setOidWithItem(&pVarBind->name, &myOid, item);
         }
         break;
     case SNMP_PDU_SET:
         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
+        ret = FALSE;
         break;
     default:
         FIXME("0x%02x: unsupported PDU type\n", bPduType);
         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
     }
-    return TRUE;
+    return ret;
 }
 
 static UINT mib2UdpEntry[] = { 1,3,6,1,2,1,7,5,1 };
@@ -1102,6 +1136,7 @@ static BOOL mib2UdpEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
     AsnInteger32 *pErrorStatus)
 {
     AsnObjectIdentifier myOid = DEFINE_OID(mib2UdpEntry);
+    BOOL ret = TRUE;
 
     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
         pErrorStatus);
@@ -1131,23 +1166,27 @@ static BOOL mib2UdpEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
                 {
                     AsnObjectIdentifier oid;
 
-                    setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
+                    ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
                         udpTable->table[tableIndex - 1].dwLocalAddr);
-                    oid.idLength = 1;
-                    oid.ids = &udpTable->table[tableIndex - 1].dwLocalPort;
-                    SnmpUtilOidAppend(&pVarBind->name, &oid);
+                    if (ret)
+                    {
+                        oid.idLength = 1;
+                        oid.ids = &udpTable->table[tableIndex - 1].dwLocalPort;
+                        ret = SnmpUtilOidAppend(&pVarBind->name, &oid);
+                    }
                 }
             }
         }
         break;
     case SNMP_PDU_SET:
         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
+        ret = FALSE;
         break;
     default:
         FIXME("0x%02x: unsupported PDU type\n", bPduType);
         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
     }
-    return TRUE;
+    return ret;
 }
 
 /* This list MUST BE lexicographically sorted */
@@ -1240,6 +1279,7 @@ BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
     AsnObjectIdentifier mib2oid = DEFINE_OID(mib2);
     AsnInteger32 error = SNMP_ERRORSTATUS_NOERROR, errorIndex = 0;
     UINT i;
+    BOOL ret = TRUE;
 
     TRACE("(0x%02x, %p, %p, %p)\n", bPduType, pVarBindList,
         pErrorStatus, pErrorIndex);
@@ -1261,7 +1301,7 @@ BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
                 impl = findSupportedQuery(pVarBindList->list[i].name.ids, len,
                     &matchingIndex);
             if (impl && impl->query)
-                impl->query(bPduType, &pVarBindList->list[i], &error);
+                ret = impl->query(bPduType, &pVarBindList->list[i], &error);
             else
                 error = SNMP_ERRORSTATUS_NOSUCHNAME;
             if (error == SNMP_ERRORSTATUS_NOSUCHNAME &&
@@ -1278,7 +1318,8 @@ BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
                     error = SNMP_ERRORSTATUS_NOERROR;
                     impl = &supportedIDs[matchingIndex];
                     if (impl->query)
-                        impl->query(bPduType, &pVarBindList->list[i], &error);
+                        ret = impl->query(bPduType, &pVarBindList->list[i],
+                            &error);
                     else
                         error = SNMP_ERRORSTATUS_NOSUCHNAME;
                 }
@@ -1288,7 +1329,7 @@ BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
                 if (error == SNMP_ERRORSTATUS_NOSUCHNAME)
                 {
                     SnmpUtilOidFree(&pVarBindList->list[i].name);
-                    SnmpUtilOidCpy(&pVarBindList->list[i].name,
+                    ret = SnmpUtilOidCpy(&pVarBindList->list[i].name,
                         &supportedIDs[matchingIndex - 1].name);
                     pVarBindList->list[i].name.ids[
                         pVarBindList->list[i].name.idLength - 1] += 1;
@@ -1300,7 +1341,7 @@ BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
     }
     *pErrorStatus = error;
     *pErrorIndex = errorIndex;
-    return TRUE;
+    return ret;
 }
 
 /*****************************************************************************
index 0ac6369..5174a1a 100644 (file)
@@ -62,6 +62,11 @@ static inline void * __WINE_ALLOC_SIZE(1) heap_alloc_zero( size_t len )
     return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len );
 }
 
+static inline void * __WINE_ALLOC_SIZE(2) heap_realloc_zero( void * mem, size_t len )
+{
+    return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mem, len );
+}
+
 static inline BOOL heap_free( void *mem )
 {
     return HeapFree( GetProcessHeap(), 0, mem );
index f308e36..79541db 100644 (file)
@@ -80,6 +80,13 @@ typedef struct {
     LPCWSTR  versionsubdir;
 } printenv_t;
 
+typedef struct {
+    LPWSTR name;
+    LPWSTR printername;
+    monitor_t * pm;
+    HANDLE hXcv;
+} printer_t;
+
 /* ############################### */
 
 static struct list monitor_handles = LIST_INIT( monitor_handles );
@@ -88,6 +95,7 @@ static monitor_t * pm_localport;
 static const PRINTPROVIDOR * pprovider = NULL;
 
 static const WCHAR backslashW[] = {'\\',0};
+static const WCHAR bs_ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
@@ -118,20 +126,30 @@ static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
 static const WCHAR portW[] = {'P','o','r','t',0};
 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
+static const WCHAR printersW[] = {'S','y','s','t','e','m','\\',
+                                  'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+                                  'C','o','n','t','r','o','l','\\',
+                                  'P','r','i','n','t','\\',
+                                  'P','r','i','n','t','e','r','s',0};
 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
+static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
+static const WCHAR version0_subdirW[] = {'\\','0',0};
+static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
+static const WCHAR version3_subdirW[] = {'\\','3',0};
 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
-
 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
-static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
-static const WCHAR version0_subdirW[] = {'\\','0',0};
-
+static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
+                                        'M','i','c','r','o','s','o','f','t','\\',
+                                        'W','i','n','d','o','w','s',' ','N','T','\\',
+                                        'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+                                        'P','o','r','t','s',0};
 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
 static const WCHAR x64_subdirW[] = {'x','6','4',0};
 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
-static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
-static const WCHAR version3_subdirW[] = {'\\','3',0};
+static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
+static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
 
 
 static const printenv_t env_x86 =   {x86_envnameW, x86_subdirW, 3,
@@ -273,6 +291,32 @@ static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
     return serverlen;
 }
 
+/******************************************************************
+ * get_basename_from_name  (internal)
+ *
+ * skip over the serverpart from the full name
+ *
+ */
+static LPCWSTR get_basename_from_name(LPCWSTR name)
+{
+    if (name == NULL)  return NULL;
+    if ((name[0] == '\\') && (name[1] == '\\')) {
+        /* skip over the servername and search for the following '\'  */
+        name = strchrW(&name[2], '\\');
+        if ((name) && (name[1])) {
+            /* found a separator ('\') followed by a name:
+               skip over the separator and return the rest */
+            name++;
+        }
+        else
+        {
+            /* no basename present (we found only a servername) */
+            return NULL;
+        }
+    }
+    return name;
+}
+
 /******************************************************************
  * monitor_unload [internal]
  *
@@ -512,6 +556,65 @@ static DWORD monitor_loadall(void)
     return loaded;
 }
 
+/******************************************************************
+ * monitor_load_by_port [internal]
+ *
+ * load a printmonitor for a given port
+ *
+ * On failure, NULL is returned
+ */
+
+static monitor_t * monitor_load_by_port(LPCWSTR portname)
+{
+    HKEY    hroot;
+    HKEY    hport;
+    LPWSTR  buffer;
+    monitor_t * pm = NULL;
+    DWORD   registered = 0;
+    DWORD   id = 0;
+    DWORD   len;
+
+    TRACE("(%s)\n", debugstr_w(portname));
+
+    /* Try the Local Monitor first */
+    if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
+        if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
+            /* found the portname */
+            RegCloseKey(hroot);
+            return monitor_load(localportW, NULL);
+        }
+        RegCloseKey(hroot);
+    }
+
+    len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
+    buffer = heap_alloc(len * sizeof(WCHAR));
+    if (buffer == NULL) return NULL;
+
+    if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
+        EnterCriticalSection(&monitor_handles_cs);
+        RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+
+        while ((pm == NULL) && (id < registered)) {
+            buffer[0] = '\0';
+            RegEnumKeyW(hroot, id, buffer, MAX_PATH);
+            TRACE("testing %s\n", debugstr_w(buffer));
+            len = lstrlenW(buffer);
+            lstrcatW(buffer, bs_ports_bsW);
+            lstrcatW(buffer, portname);
+            if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
+                RegCloseKey(hport);
+                buffer[len] = '\0';             /* use only the Monitor-Name */
+                pm = monitor_load(buffer, NULL);
+            }
+            id++;
+        }
+        LeaveCriticalSection(&monitor_handles_cs);
+        RegCloseKey(hroot);
+    }
+    heap_free(buffer);
+    return pm;
+}
+
 /******************************************************************
  * Return the number of bytes for an multi_sz string.
  * The result includes all \0s
@@ -907,6 +1010,139 @@ static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
     return hui;
 }
 
+/******************************************************************
+ *  printer_free
+ *  free the data pointer of an opened printer
+ */
+static VOID printer_free(printer_t * printer)
+{
+    if (printer->hXcv)
+        printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
+
+    monitor_unload(printer->pm);
+
+    heap_free(printer->printername);
+    heap_free(printer->name);
+    heap_free(printer);
+}
+
+/******************************************************************
+ *  printer_alloc_handle
+ *  alloc a printer handle and remember the data pointer in the printer handle table
+ *
+ */
+static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
+{
+    WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
+    printer_t *printer = NULL;
+    LPCWSTR printername;
+    HKEY    hkeyPrinters;
+    HKEY    hkeyPrinter;
+    DWORD   len;
+
+    if (copy_servername_from_name(name, servername)) {
+        FIXME("server %s not supported\n", debugstr_w(servername));
+        SetLastError(ERROR_INVALID_PRINTER_NAME);
+        return NULL;
+    }
+
+    printername = get_basename_from_name(name);
+    if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
+
+    /* an empty printername is invalid */
+    if (printername && (!printername[0])) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return NULL;
+    }
+
+    printer = heap_alloc_zero(sizeof(printer_t));
+    if (!printer) goto end;
+
+    /* clone the base name. This is NULL for the printserver */
+    printer->printername = strdupW(printername);
+
+    /* clone the full name */
+    printer->name = strdupW(name);
+    if (name && (!printer->name)) {
+        printer_free(printer);
+        printer = NULL;
+    }
+    if (printername) {
+        len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
+        if (strncmpW(printername, XcvMonitorW, len) == 0) {
+            /* OpenPrinter(",XcvMonitor ", ...) detected */
+            TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
+            printer->pm = monitor_load(&printername[len], NULL);
+            if (printer->pm == NULL) {
+                printer_free(printer);
+                SetLastError(ERROR_UNKNOWN_PORT);
+                printer = NULL;
+                goto end;
+            }
+        }
+        else
+        {
+            len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
+            if (strncmpW( printername, XcvPortW, len) == 0) {
+                /* OpenPrinter(",XcvPort ", ...) detected */
+                TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
+                printer->pm = monitor_load_by_port(&printername[len]);
+                if (printer->pm == NULL) {
+                    printer_free(printer);
+                    SetLastError(ERROR_UNKNOWN_PORT);
+                    printer = NULL;
+                    goto end;
+                }
+            }
+        }
+
+        if (printer->pm) {
+            if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
+                printer->pm->monitor->pfnXcvOpenPort(&printername[len],
+                                                    pDefault ? pDefault->DesiredAccess : 0,
+                                                    &printer->hXcv);
+            }
+            if (printer->hXcv == NULL) {
+                printer_free(printer);
+                SetLastError(ERROR_INVALID_PARAMETER);
+                printer = NULL;
+                goto end;
+            }
+        }
+        else
+        {
+            /* Does the Printer exist? */
+            if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
+                ERR("Can't create Printers key\n");
+                printer_free(printer);
+                SetLastError(ERROR_INVALID_PRINTER_NAME);
+                printer = NULL;
+                goto end;
+            }
+            if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
+                WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
+                RegCloseKey(hkeyPrinters);
+                printer_free(printer);
+                SetLastError(ERROR_INVALID_PRINTER_NAME);
+                printer = NULL;
+                goto end;
+            }
+            RegCloseKey(hkeyPrinter);
+            RegCloseKey(hkeyPrinters);
+        }
+    }
+    else
+    {
+        TRACE("using the local printserver\n");
+    }
+
+end:
+
+    TRACE("==> %p\n", printer);
+    return (HANDLE)printer;
+}
+
+
 /******************************************************************************
  *  myAddPrinterDriverEx [internal]
  *
@@ -1213,6 +1449,34 @@ static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDrive
 
     return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
 }
+
+/******************************************************************************
+ * fpClosePrinter [exported through PRINTPROVIDOR]
+ *
+ * Close a printer handle and free associated resources
+ *
+ * PARAMS
+ *  hPrinter [I] Printerhandle to close
+ *
+ * RESULTS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ */
+static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
+{
+    printer_t *printer = (printer_t *) hPrinter;
+
+    TRACE("(%p)\n", hPrinter);
+
+    if (printer) {
+        printer_free(printer);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+
 /******************************************************************
  * fpDeleteMonitor [exported through PRINTPROVIDOR]
  *
@@ -1425,13 +1689,115 @@ emP_cleanup:
     return (res);
 }
 
+/******************************************************************************
+ * fpOpenPrinter [exported through PRINTPROVIDOR]
+ *
+ * Open a Printer / Printserver or a Printer-Object
+ *
+ * PARAMS
+ *  lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
+ *  pPrinter      [O] The resulting Handle is stored here
+ *  pDefaults     [I] PTR to Default Printer Settings or NULL
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  lpPrinterName is one of:
+ *|  Printserver (NT only): "Servername" or NULL for the local Printserver
+ *|  Printer: "PrinterName"
+ *|  Printer-Object: "PrinterName,Job xxx"
+ *|  XcvMonitor: "Servername,XcvMonitor MonitorName"
+ *|  XcvPort: "Servername,XcvPort PortName"
+ *
+ *
+ */
+static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
+                                 LPPRINTER_DEFAULTSW pDefaults)
+{
+
+    TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
+
+    *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
+
+    return (*pPrinter != 0);
+}
+
+/******************************************************************************
+ * fpXcvData [exported through PRINTPROVIDOR]
+ *
+ * Execute commands in the Printmonitor DLL
+ *
+ * PARAMS
+ *  hXcv            [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
+ *  pszDataName     [i] Name of the command to execute
+ *  pInputData      [i] Buffer for extra Input Data (needed only for some commands)
+ *  cbInputData     [i] Size in Bytes of Buffer at pInputData
+ *  pOutputData     [o] Buffer to receive additional Data (needed only for some commands)
+ *  cbOutputData    [i] Size in Bytes of Buffer at pOutputData
+ *  pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
+ *  pdwStatus       [o] PTR to receive the win32 error code from the Printmonitor DLL
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
+ *  The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
+ *
+ *  Minimal List of commands, that a Printmonitor DLL should support:
+ *
+ *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
+ *| "AddPort"   : Add a Port
+ *| "DeletePort": Delete a Port
+ *
+ *  Many Printmonitors support additional commands. Examples for localspl.dll:
+ *  "GetDefaultCommConfig", "SetDefaultCommConfig",
+ *  "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
+ *
+ */
+static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
+                    DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
+                    PDWORD pcbOutputNeeded, PDWORD pdwStatus)
+{
+    printer_t *printer = (printer_t * ) hXcv;
+
+    TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
+          pInputData, cbInputData, pOutputData,
+          cbOutputData, pcbOutputNeeded, pdwStatus);
+
+    if (!printer || (!printer->hXcv)) {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+
+    if (!pcbOutputNeeded) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
+        SetLastError(RPC_X_NULL_REF_POINTER);
+        return FALSE;
+    }
+
+    *pcbOutputNeeded = 0;
+
+    *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
+            pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
+
+    return TRUE;
+}
+
 /*****************************************************
  *  setup_provider [internal]
  */
 void setup_provider(void)
 {
     static const PRINTPROVIDOR backend = {
-        NULL,   /* fpOpenPrinter */
+        fpOpenPrinter,
         NULL,   /* fpSetJob */
         NULL,   /* fpGetJob */
         NULL,   /* fpEnumJobs */
@@ -1462,7 +1828,7 @@ void setup_provider(void)
         NULL,   /* fpGetPrinterData */
         NULL,   /* fpSetPrinterData */
         NULL,   /* fpWaitForPrinterChange */
-        NULL,   /* fpClosePrinter */
+        fpClosePrinter,
         NULL,   /* fpAddForm */
         NULL,   /* fpDeleteForm */
         NULL,   /* fpGetForm */
@@ -1507,7 +1873,7 @@ void setup_provider(void)
         NULL,   /* fpAddPerMachineConnection */
         NULL,   /* fpDeletePerMachineConnection */
         NULL,   /* fpEnumPerMachineConnections */
-        NULL,   /* fpXcvData */
+        fpXcvData,
         fpAddPrinterDriverEx,
         NULL,   /* fpSplReadPrinter */
         NULL,   /* fpDriverUnloadComplete */
index 0435a11..8371227 100644 (file)
@@ -337,6 +337,110 @@ static DWORD MCIQTZ_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpPa
     return 0;
 }
 
+/***************************************************************************
+ *                              MCIQTZ_mciGetDevCaps            [internal]
+ */
+static DWORD MCIQTZ_mciGetDevCaps(UINT wDevID, DWORD dwFlags, LPMCI_GETDEVCAPS_PARMS lpParms)
+{
+    WINE_MCIQTZ* wma;
+
+    TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
+
+    if (!lpParms)
+        return MCIERR_NULL_PARAMETER_BLOCK;
+
+    wma = MCIQTZ_mciGetOpenDev(wDevID);
+    if (!wma)
+        return MCIERR_INVALID_DEVICE_ID;
+
+    if (!(dwFlags & MCI_STATUS_ITEM)) {
+        WARN("No capability item specified\n");
+        return MCIERR_UNRECOGNIZED_COMMAND;
+    }
+
+    switch (lpParms->dwItem) {
+        case MCI_GETDEVCAPS_CAN_RECORD:
+            lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
+            TRACE("MCI_GETDEVCAPS_CAN_RECORD = %08x\n", lpParms->dwReturn);
+            break;
+        case MCI_GETDEVCAPS_HAS_AUDIO:
+            lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
+            TRACE("MCI_GETDEVCAPS_HAS_AUDIO = %08x\n", lpParms->dwReturn);
+            break;
+        case MCI_GETDEVCAPS_HAS_VIDEO:
+            lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
+            TRACE("MCI_GETDEVCAPS_HAS_VIDEO = %08x\n", lpParms->dwReturn);
+            break;
+        case MCI_GETDEVCAPS_DEVICE_TYPE:
+            lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_DIGITAL_VIDEO, MCI_DEVTYPE_DIGITAL_VIDEO);
+            TRACE("MCI_GETDEVCAPS_DEVICE_TYPE = %08x\n", lpParms->dwReturn);
+            break;
+        case MCI_GETDEVCAPS_USES_FILES:
+            lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
+            TRACE("MCI_GETDEVCAPS_USES_FILES = %08x\n", lpParms->dwReturn);
+            break;
+        case MCI_GETDEVCAPS_COMPOUND_DEVICE:
+            lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
+            TRACE("MCI_GETDEVCAPS_COMPOUND_DEVICE = %08x\n", lpParms->dwReturn);
+            break;
+        case MCI_GETDEVCAPS_CAN_EJECT:
+            lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
+            TRACE("MCI_GETDEVCAPS_EJECT = %08x\n", lpParms->dwReturn);
+            break;
+        case MCI_GETDEVCAPS_CAN_PLAY:
+            lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
+            TRACE("MCI_GETDEVCAPS_CAN_PLAY = %08x\n", lpParms->dwReturn);
+            break;
+        case MCI_GETDEVCAPS_CAN_SAVE:
+            lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
+            TRACE("MCI_GETDEVCAPS_CAN_SAVE = %08x\n", lpParms->dwReturn);
+            break;
+        default:
+            ERR("Unknown capability %08x\n", lpParms->dwItem);
+            return MCIERR_UNRECOGNIZED_COMMAND;
+    }
+
+    return MCI_RESOURCE_RETURNED;
+}
+
+/***************************************************************************
+ *                              MCIQTZ_mciSet                   [internal]
+ */
+static DWORD MCIQTZ_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_DGV_SET_PARMS lpParms)
+{
+    WINE_MCIQTZ* wma;
+
+    TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
+
+    if (!lpParms)
+        return MCIERR_NULL_PARAMETER_BLOCK;
+
+    wma = MCIQTZ_mciGetOpenDev(wDevID);
+    if (!wma)
+        return MCIERR_INVALID_DEVICE_ID;
+
+    if (dwFlags & MCI_SET_TIME_FORMAT) {
+        switch (lpParms->dwTimeFormat) {
+            case MCI_FORMAT_MILLISECONDS:
+                TRACE("MCI_SET_TIME_FORMAT = MCI_FORMAT_MILLISECONDS\n");
+                wma->time_format = MCI_FORMAT_MILLISECONDS;
+                break;
+            case MCI_FORMAT_FRAMES:
+                TRACE("MCI_SET_TIME_FORMAT = MCI_FORMAT_FRAMES\n");
+                wma->time_format = MCI_FORMAT_FRAMES;
+                break;
+            default:
+                WARN("Bad time format %u\n", lpParms->dwTimeFormat);
+                return MCIERR_BAD_TIME_FORMAT;
+        }
+    }
+
+    if (dwFlags & ~MCI_SET_TIME_FORMAT)
+        FIXME("Flags not supported yet %08lX\n", dwFlags & ~MCI_SET_TIME_FORMAT);
+
+    return 0;
+}
+
 /***************************************************************************
  *                              MCIQTZ_mciStatus                [internal]
  */
@@ -415,6 +519,90 @@ static DWORD MCIQTZ_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_DGV_STATUS_PARMS
     return 0;
 }
 
+/***************************************************************************
+ *                              MCIQTZ_mciWhere                 [internal]
+ */
+static DWORD MCIQTZ_mciWhere(UINT wDevID, DWORD dwFlags, LPMCI_DGV_RECT_PARMS lpParms)
+{
+    WINE_MCIQTZ* wma;
+    IVideoWindow* pVideoWindow;
+    HRESULT hr;
+    HWND hWnd;
+    RECT rc;
+
+    TRACE("(%04x, %08X, %p)\n", wDevID, dwFlags, lpParms);
+
+    if (!lpParms)
+        return MCIERR_NULL_PARAMETER_BLOCK;
+
+    wma = MCIQTZ_mciGetOpenDev(wDevID);
+    if (!wma)
+        return MCIERR_INVALID_DEVICE_ID;
+
+    /* Find if there is a video stream and get the display window */
+    hr = IGraphBuilder_QueryInterface(wma->pgraph, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
+    if (FAILED(hr)) {
+        ERR("Cannot get IVideoWindow interface (hr = %x)\n", hr);
+        return MCIERR_INTERNAL;
+    }
+
+    hr = IVideoWindow_get_Owner(pVideoWindow, (OAHWND*)&hWnd);
+    IVideoWindow_Release(pVideoWindow);
+    if (FAILED(hr)) {
+        TRACE("No video stream, returning no window error\n");
+        return MCIERR_NO_WINDOW;
+    }
+
+    if (dwFlags & MCI_DGV_WHERE_SOURCE) {
+        if (dwFlags & MCI_DGV_WHERE_MAX)
+            FIXME("MCI_DGV_WHERE_SOURCE_MAX not supported yet\n");
+        else
+            FIXME("MCI_DGV_WHERE_SOURCE not supported yet\n");
+        return MCIERR_UNRECOGNIZED_COMMAND;
+    }
+    if (dwFlags & MCI_DGV_WHERE_DESTINATION) {
+        if (dwFlags & MCI_DGV_WHERE_MAX) {
+            GetClientRect(hWnd, &rc);
+            TRACE("MCI_DGV_WHERE_DESTINATION_MAX %s\n", wine_dbgstr_rect(&rc));
+        } else {
+            FIXME("MCI_DGV_WHERE_DESTINATION not supported yet\n");
+            return MCIERR_UNRECOGNIZED_COMMAND;
+        }
+    }
+    if (dwFlags & MCI_DGV_WHERE_FRAME) {
+        if (dwFlags & MCI_DGV_WHERE_MAX)
+            FIXME("MCI_DGV_WHERE_FRAME_MAX not supported yet\n");
+        else
+            FIXME("MCI_DGV_WHERE_FRAME not supported yet\n");
+        return MCIERR_UNRECOGNIZED_COMMAND;
+    }
+    if (dwFlags & MCI_DGV_WHERE_VIDEO) {
+        if (dwFlags & MCI_DGV_WHERE_MAX)
+            FIXME("MCI_DGV_WHERE_VIDEO_MAX not supported yet\n");
+        else
+            FIXME("MCI_DGV_WHERE_VIDEO not supported yet\n");
+        return MCIERR_UNRECOGNIZED_COMMAND;
+    }
+    if (dwFlags & MCI_DGV_WHERE_WINDOW) {
+        if (dwFlags & MCI_DGV_WHERE_MAX) {
+            GetWindowRect(GetDesktopWindow(), &rc);
+            TRACE("MCI_DGV_WHERE_WINDOW_MAX %s\n", wine_dbgstr_rect(&rc));
+        } else {
+            GetWindowRect(hWnd, &rc);
+            TRACE("MCI_DGV_WHERE_WINDOW %s\n", wine_dbgstr_rect(&rc));
+        }
+    }
+
+    /* In MCI, RECT structure is used differently: rc.right = width & rc.bottom = height
+     * So convert the normal RECT into a MCI RECT before returning */
+    lpParms->rc.left = rc.left;
+    lpParms->rc.top = rc.right;
+    lpParms->rc.right = rc.right - rc.left;
+    lpParms->rc.bottom = rc.bottom - rc.top;
+
+    return 0;
+}
+
 /*======================================================================*
  *                          MCI QTZ entry points                        *
  *======================================================================*/
@@ -451,12 +639,13 @@ LRESULT CALLBACK MCIQTZ_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
         case MCI_PLAY:          return MCIQTZ_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)          dwParam2);
         case MCI_SEEK:          return MCIQTZ_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)          dwParam2);
         case MCI_STOP:          return MCIQTZ_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)       dwParam2);
+        case MCI_GETDEVCAPS:    return MCIQTZ_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)    dwParam2);
+        case MCI_SET:           return MCIQTZ_mciSet       (dwDevID, dwParam1, (LPMCI_DGV_SET_PARMS)       dwParam2);
         case MCI_STATUS:        return MCIQTZ_mciStatus    (dwDevID, dwParam1, (LPMCI_DGV_STATUS_PARMSW)   dwParam2);
+        case MCI_WHERE:         return MCIQTZ_mciWhere     (dwDevID, dwParam1, (LPMCI_DGV_RECT_PARMS)      dwParam2);
         case MCI_RECORD:
-        case MCI_SET:
         case MCI_PAUSE:
         case MCI_RESUME:
-        case MCI_GETDEVCAPS:
         case MCI_INFO:
         case MCI_PUT:
         case MCI_WINDOW:
@@ -466,7 +655,6 @@ LRESULT CALLBACK MCIQTZ_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
         case MCI_REALIZE:
         case MCI_UNFREEZE:
         case MCI_UPDATE:
-        case MCI_WHERE:
         case MCI_STEP:
         case MCI_COPY:
         case MCI_CUT:
index 23945a4..dcfcad0 100644 (file)
@@ -31,6 +31,7 @@ typedef struct {
     IGraphBuilder* pgraph;
     IMediaControl* pmctrl;
     BOOL           started;
+    DWORD          time_format;
 } WINE_MCIQTZ;
 
 #endif  /* __WINE_PRIVATE_MCIQTZ_H */
index 03fbc1c..04b5e1c 100644 (file)
 @ stub StrongNameSignatureGeneration
 @ stub StrongNameSignatureGenerationEx
 @ stub StrongNameSignatureSize
-@ stub StrongNameSignatureVerification
-@ stub StrongNameSignatureVerificationEx
+@ stdcall StrongNameSignatureVerification(wstr long ptr)
+@ stdcall StrongNameSignatureVerificationEx(wstr long ptr)
 @ stub StrongNameSignatureVerificationFromImage
 @ stub StrongNameTokenFromAssembly
 @ stub StrongNameTokenFromAssemblyEx
index 386f4f7..5b45adb 100644 (file)
@@ -324,6 +324,18 @@ HRESULT WINAPI CorBindToCurrentRuntime(LPCWSTR filename, REFCLSID rclsid, REFIID
     return E_NOTIMPL;
 }
 
+BOOL WINAPI StrongNameSignatureVerification(LPCWSTR filename, DWORD inFlags, DWORD* pOutFlags)
+{
+    FIXME("(%s, 0x%X, %p): stub\n", debugstr_w(filename), inFlags, pOutFlags);
+    return FALSE;
+}
+
+BOOL WINAPI StrongNameSignatureVerificationEx(LPCWSTR filename, BOOL forceVerification, BOOL* pVerified)
+{
+    FIXME("(%s, %u, %p): stub\n", debugstr_w(filename), forceVerification, pVerified);
+    return FALSE;
+}
+
 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
 {
     FIXME("(%p, %p, %p): stub\n", rclsid, riid, ppv);
index 648352a..b76bebb 100644 (file)
@@ -144,9 +144,37 @@ static HRESULT WINAPI CategoryMgr_RegisterCategory ( ITfCategoryMgr *iface,
 static HRESULT WINAPI CategoryMgr_UnregisterCategory ( ITfCategoryMgr *iface,
         REFCLSID rclsid, REFGUID rcatid, REFGUID rguid)
 {
+    WCHAR fullkey[110];
+    WCHAR buf[39];
+    WCHAR buf2[39];
+    HKEY tipkey;
     CategoryMgr *This = (CategoryMgr*)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+
+    static const WCHAR ctg[] = {'C','a','t','e','g','o','r','y',0};
+    static const WCHAR itm[] = {'I','t','e','m',0};
+    static const WCHAR fmt[] = {'%','s','\\','%','s',0};
+    static const WCHAR fmt2[] = {'%','s','\\','%','s','\\','%','s','\\','%','s',0};
+
+    TRACE("(%p) %s %s %s\n",This,debugstr_guid(rclsid), debugstr_guid(rcatid), debugstr_guid(rguid));
+
+    StringFromGUID2(rclsid, buf, 39);
+    sprintfW(fullkey,fmt,szwSystemTIPKey,buf);
+
+    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ | KEY_WRITE,
+                &tipkey ) != ERROR_SUCCESS)
+        return E_FAIL;
+
+    StringFromGUID2(rcatid, buf, 39);
+    StringFromGUID2(rguid, buf2, 39);
+    sprintfW(fullkey,fmt2,ctg,ctg,buf,buf2);
+
+    sprintfW(fullkey,fmt2,ctg,itm,buf2,buf);
+    RegDeleteTreeW(tipkey, fullkey);
+    sprintfW(fullkey,fmt2,ctg,itm,buf2,buf);
+    RegDeleteTreeW(tipkey, fullkey);
+
+    RegCloseKey(tipkey);
+    return S_OK;
 }
 
 static HRESULT WINAPI CategoryMgr_EnumCategoriesInItem ( ITfCategoryMgr *iface,
@@ -284,25 +312,77 @@ static HRESULT WINAPI CategoryMgr_RegisterGUID ( ITfCategoryMgr *iface,
         REFGUID rguid, TfGuidAtom *pguidatom
 )
 {
+    DWORD index;
+    GUID *checkguid;
+    DWORD id;
     CategoryMgr *This = (CategoryMgr*)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+
+    TRACE("(%p) %s %p\n",This,debugstr_guid(rguid),pguidatom);
+
+    if (!pguidatom)
+        return E_INVALIDARG;
+
+    index = 0;
+    do {
+        id = enumerate_Cookie(COOKIE_MAGIC_GUIDATOM,&index);
+        if (id && IsEqualGUID(rguid,get_Cookie_data(id)))
+        {
+            *pguidatom = id;
+            return S_OK;
+        }
+    } while(id);
+
+    checkguid = HeapAlloc(GetProcessHeap(),0,sizeof(GUID));
+    *checkguid = *rguid;
+    id = generate_Cookie(COOKIE_MAGIC_GUIDATOM,checkguid);
+
+    if (!id)
+    {
+        HeapFree(GetProcessHeap(),0,checkguid);
+        return E_FAIL;
+    }
+
+    *pguidatom = id;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI CategoryMgr_GetGUID ( ITfCategoryMgr *iface,
         TfGuidAtom guidatom, GUID *pguid)
 {
     CategoryMgr *This = (CategoryMgr*)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+
+    TRACE("(%p) %i\n",This,guidatom);
+
+    if (!pguid)
+        return E_INVALIDARG;
+
+    *pguid = GUID_NULL;
+
+    if (get_Cookie_magic(guidatom) == COOKIE_MAGIC_GUIDATOM)
+        *pguid = *((REFGUID)get_Cookie_data(guidatom));
+
+    return S_OK;
 }
 
 static HRESULT WINAPI CategoryMgr_IsEqualTfGuidAtom ( ITfCategoryMgr *iface,
         TfGuidAtom guidatom, REFGUID rguid, BOOL *pfEqual)
 {
     CategoryMgr *This = (CategoryMgr*)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+
+    TRACE("(%p) %i %s %p\n",This,guidatom,debugstr_guid(rguid),pfEqual);
+
+    if (!pfEqual)
+        return E_INVALIDARG;
+
+    *pfEqual = FALSE;
+    if (get_Cookie_magic(guidatom) == COOKIE_MAGIC_GUIDATOM)
+    {
+        if (IsEqualGUID(rguid,get_Cookie_data(guidatom)))
+            *pfEqual = TRUE;
+    }
+
+    return S_OK;
 }
 
 
index 7df5575..38e9368 100644 (file)
@@ -288,18 +288,61 @@ static HRESULT WINAPI InputProcessorProfiles_ActivateLanguageProfile(
         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
         REFGUID guidProfiles)
 {
+    HRESULT hr;
+    BOOL enabled;
+    TF_LANGUAGEPROFILE LanguageProfile;
     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+
+    TRACE("(%p) %s %x %s\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfiles));
+
+    if (langid != This->currentLanguage) return E_INVALIDARG;
+
+    if (get_active_textservice(rclsid,NULL))
+    {
+        TRACE("Already Active\n");
+        return E_FAIL;
+    }
+
+    hr = ITfInputProcessorProfiles_IsEnabledLanguageProfile(iface, rclsid,
+            langid, guidProfiles, &enabled);
+    if (FAILED(hr) || !enabled)
+    {
+        TRACE("Not Enabled\n");
+        return E_FAIL;
+    }
+
+    LanguageProfile.clsid = *rclsid;
+    LanguageProfile.langid = langid;
+    LanguageProfile.guidProfile = *guidProfiles;
+
+    hr = add_active_textservice(&LanguageProfile);
+
+    return hr;
 }
 
 static HRESULT WINAPI InputProcessorProfiles_GetActiveLanguageProfile(
         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID *plangid,
         GUID *pguidProfile)
 {
+    TF_LANGUAGEPROFILE profile;
     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+
+    TRACE("(%p) %s %p %p\n",This,debugstr_guid(rclsid),plangid,pguidProfile);
+
+    if (!rclsid || !plangid || !pguidProfile)
+        return E_INVALIDARG;
+
+    if (get_active_textservice(rclsid, &profile))
+    {
+        *plangid = profile.langid;
+        *pguidProfile = profile.guidProfile;
+        return S_OK;
+    }
+    else
+    {
+        *pguidProfile = GUID_NULL;
+        return S_FALSE;
+    }
 }
 
 static HRESULT WINAPI InputProcessorProfiles_GetLanguageProfileDescription(
@@ -756,8 +799,7 @@ static INT next_LanguageProfile(EnumTfLanguageProfiles *This, CLSID clsid, TF_LA
 
         tflp->clsid = clsid;
         tflp->langid = This->langid;
-        /* FIXME */
-        tflp->fActive = FALSE;
+        tflp->fActive = get_active_textservice(&clsid, NULL);
         tflp->guidProfile = profile;
         if (ITfCategoryMgr_FindClosestCategory(This->catmgr, &clsid,
                 &tflp->catid, tipcats, 3) != S_OK)
index fac0f9d..c8dd486 100644 (file)
@@ -26,6 +26,7 @@
 #define COBJMACROS
 
 #include "wine/debug.h"
+#include "wine/list.h"
 #include "windef.h"
 #include "winbase.h"
 #include "winreg.h"
@@ -50,11 +51,28 @@ typedef struct
     LPVOID data;
 } CookieInternal;
 
+typedef struct {
+    TF_LANGUAGEPROFILE      LanguageProfile;
+    ITfTextInputProcessor   *pITfTextInputProcessor;
+    ITfThreadMgr            *pITfThreadMgr;
+    TfClientId              tid;
+} ActivatedTextService;
+
+typedef struct
+{
+    struct list entry;
+    ActivatedTextService *ats;
+} AtsEntry;
+
 static CookieInternal *cookies;
 static UINT id_last;
 static UINT array_size;
 
+static struct list AtsList = LIST_INIT(AtsList);
+static UINT activated = 0;
+
 DWORD tlsIndex = 0;
+TfClientId processId = 0;
 
 const WCHAR szwSystemTIPKey[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\','C','T','F','\\','T','I','P',0};
 
@@ -252,6 +270,192 @@ LPVOID remove_Cookie(DWORD id)
     return cookies[index].data;
 }
 
+DWORD enumerate_Cookie(DWORD magic, DWORD *index)
+{
+    int i;
+    for (i = *index; i < id_last; i++)
+        if (cookies[i].id != 0 && cookies[i].magic == magic)
+        {
+            *index = (i+1);
+            return cookies[i].id;
+        }
+    return 0x0;
+}
+
+/*****************************************************************************
+ * Active Text Service Management
+ *****************************************************************************/
+static HRESULT activate_given_ts(ActivatedTextService *actsvr, ITfThreadMgr* tm)
+{
+    HRESULT hr;
+
+    /* Already Active? */
+    if (actsvr->pITfTextInputProcessor)
+        return S_OK;
+
+    hr = CoCreateInstance (&actsvr->LanguageProfile.clsid, NULL, CLSCTX_INPROC_SERVER,
+        &IID_ITfTextInputProcessor, (void**)&actsvr->pITfTextInputProcessor);
+    if (FAILED(hr)) return hr;
+
+    hr = ITfTextInputProcessor_Activate(actsvr->pITfTextInputProcessor, tm, actsvr->tid);
+    if (FAILED(hr))
+    {
+        ITfTextInputProcessor_Release(actsvr->pITfTextInputProcessor);
+        actsvr->pITfTextInputProcessor = NULL;
+        return hr;
+    }
+
+    actsvr->pITfThreadMgr = tm;
+    ITfThreadMgr_AddRef(tm);
+    return hr;
+}
+
+static HRESULT deactivate_given_ts(ActivatedTextService *actsvr)
+{
+    HRESULT hr = S_OK;
+
+    if (actsvr->pITfTextInputProcessor)
+    {
+        hr = ITfTextInputProcessor_Deactivate(actsvr->pITfTextInputProcessor);
+        ITfTextInputProcessor_Release(actsvr->pITfTextInputProcessor);
+        ITfThreadMgr_Release(actsvr->pITfThreadMgr);
+        actsvr->pITfTextInputProcessor = NULL;
+        actsvr->pITfThreadMgr = NULL;
+    }
+
+    return hr;
+}
+
+static void deactivate_remove_conflicting_ts(REFCLSID catid)
+{
+    AtsEntry *ats, *cursor2;
+
+    LIST_FOR_EACH_ENTRY_SAFE(ats, cursor2, &AtsList, AtsEntry, entry)
+    {
+        if (IsEqualCLSID(catid,&ats->ats->LanguageProfile.catid))
+        {
+            deactivate_given_ts(ats->ats);
+            list_remove(&ats->entry);
+            HeapFree(GetProcessHeap(),0,ats->ats);
+            HeapFree(GetProcessHeap(),0,ats);
+            /* we are guarenteeing there is only 1 */
+            break;
+        }
+    }
+}
+
+HRESULT add_active_textservice(TF_LANGUAGEPROFILE *lp)
+{
+    ActivatedTextService *actsvr;
+    ITfCategoryMgr *catmgr;
+    AtsEntry *entry;
+    ITfThreadMgr *tm = (ITfThreadMgr*)TlsGetValue(tlsIndex);
+    ITfClientId *clientid;
+
+    if (!tm) return E_UNEXPECTED;
+
+    actsvr = HeapAlloc(GetProcessHeap(),0,sizeof(ActivatedTextService));
+    if (!actsvr) return E_OUTOFMEMORY;
+
+    entry = HeapAlloc(GetProcessHeap(),0,sizeof(AtsEntry));
+
+    if (!entry)
+    {
+        HeapFree(GetProcessHeap(),0,actsvr);
+        return E_OUTOFMEMORY;
+    }
+
+    ITfThreadMgr_QueryInterface(tm,&IID_ITfClientId,(LPVOID)&clientid);
+    ITfClientId_GetClientId(clientid, &lp->clsid, &actsvr->tid);
+    ITfClientId_Release(clientid);
+
+    if (!actsvr->tid)
+    {
+        HeapFree(GetProcessHeap(),0,actsvr);
+        return E_OUTOFMEMORY;
+    }
+
+    actsvr->pITfTextInputProcessor = NULL;
+    actsvr->LanguageProfile = *lp;
+    actsvr->LanguageProfile.fActive = TRUE;
+
+    /* get TIP category */
+    if (SUCCEEDED(CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr)))
+    {
+        static const GUID *list[3] = {&GUID_TFCAT_TIP_SPEECH, &GUID_TFCAT_TIP_KEYBOARD, &GUID_TFCAT_TIP_HANDWRITING};
+
+        ITfCategoryMgr_FindClosestCategory(catmgr,
+                &actsvr->LanguageProfile.clsid, &actsvr->LanguageProfile.catid,
+                list, 3);
+
+        ITfCategoryMgr_Release(catmgr);
+    }
+    else
+    {
+        ERR("CategoryMgr construction failed\n");
+        actsvr->LanguageProfile.catid = GUID_NULL;
+    }
+
+    if (!IsEqualGUID(&actsvr->LanguageProfile.catid,&GUID_NULL))
+        deactivate_remove_conflicting_ts(&actsvr->LanguageProfile.catid);
+
+    if (activated > 0)
+        activate_given_ts(actsvr, tm);
+
+    entry->ats = actsvr;
+    list_add_head(&AtsList, &entry->entry);
+
+    return S_OK;
+}
+
+BOOL get_active_textservice(REFCLSID rclsid, TF_LANGUAGEPROFILE *profile)
+{
+    AtsEntry *ats;
+
+    LIST_FOR_EACH_ENTRY(ats, &AtsList, AtsEntry, entry)
+    {
+        if (IsEqualCLSID(rclsid,&ats->ats->LanguageProfile.clsid))
+        {
+            if (profile)
+                *profile = ats->ats->LanguageProfile;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+HRESULT activate_textservices(ITfThreadMgr *tm)
+{
+    HRESULT hr = S_OK;
+    AtsEntry *ats;
+
+    activated ++;
+    if (activated > 1)
+        return S_OK;
+
+    LIST_FOR_EACH_ENTRY(ats, &AtsList, AtsEntry, entry)
+    {
+        hr = activate_given_ts(ats->ats, tm);
+        if (FAILED(hr))
+            FIXME("Failed to activate text service\n");
+    }
+    return hr;
+}
+
+HRESULT deactivate_textservices(void)
+{
+    AtsEntry *ats;
+
+    if (activated > 0)
+        activated --;
+
+    if (activated == 0)
+        LIST_FOR_EACH_ENTRY(ats, &AtsList, AtsEntry, entry)
+            deactivate_given_ts(ats->ats);
+
+    return S_OK;
+}
+
 /*************************************************************************
  * MSCTF DllMain
  */
index a9f7982..433b79e 100644 (file)
 
 #define COOKIE_MAGIC_TMSINK  0x0010
 #define COOKIE_MAGIC_CONTEXTSINK 0x0020
+#define COOKIE_MAGIC_GUIDATOM 0x0030
 
 extern DWORD tlsIndex;
+extern TfClientId processId;
 
 extern HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut);
 extern HRESULT DocumentMgr_Constructor(ITfThreadMgrEventSink*, ITfDocumentMgr **ppOut);
@@ -37,6 +39,13 @@ extern DWORD  generate_Cookie(DWORD magic, LPVOID data);
 extern DWORD  get_Cookie_magic(DWORD id);
 extern LPVOID get_Cookie_data(DWORD id);
 extern LPVOID remove_Cookie(DWORD id);
+extern DWORD enumerate_Cookie(DWORD magic, DWORD *index);
+
+/* activated text services functions */
+extern HRESULT add_active_textservice(TF_LANGUAGEPROFILE *lp);
+extern BOOL get_active_textservice(REFCLSID rclsid, TF_LANGUAGEPROFILE *lp);
+extern HRESULT activate_textservices(ITfThreadMgr *tm);
+extern HRESULT deactivate_textservices(void);
 
 extern const WCHAR szwSystemTIPKey[];
 #endif /* __WINE_MSCTF_I_H */
index 2d43a19..2afee39 100644 (file)
@@ -56,15 +56,29 @@ typedef struct tagThreadMgrSink {
     } interfaces;
 } ThreadMgrSink;
 
+typedef struct tagPreservedKey
+{
+    struct list     entry;
+    GUID            guid;
+    TF_PRESERVEDKEY prekey;
+    LPWSTR          description;
+    TfClientId      tid;
+} PreservedKey;
+
 typedef struct tagACLMulti {
     const ITfThreadMgrVtbl *ThreadMgrVtbl;
     const ITfSourceVtbl *SourceVtbl;
     const ITfKeystrokeMgrVtbl *KeystrokeMgrVtbl;
+    const ITfMessagePumpVtbl *MessagePumpVtbl;
+    const ITfClientIdVtbl *ClientIdVtbl;
     LONG refCount;
 
     const ITfThreadMgrEventSinkVtbl *ThreadMgrEventSinkVtbl; /* internal */
 
     ITfDocumentMgr *focus;
+    LONG activationCount;
+
+    struct list CurrentPreservedKeys;
 
     /* kept as separate lists to reduce unnecessary iterations */
     struct list     ActiveLanguageProfileNotifySink;
@@ -85,6 +99,16 @@ static inline ThreadMgr *impl_from_ITfKeystrokeMgrVtbl(ITfKeystrokeMgr *iface)
     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,KeystrokeMgrVtbl));
 }
 
+static inline ThreadMgr *impl_from_ITfMessagePumpVtbl(ITfMessagePump *iface)
+{
+    return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,MessagePumpVtbl));
+}
+
+static inline ThreadMgr *impl_from_ITfClientIdVtbl(ITfClientId *iface)
+{
+    return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,ClientIdVtbl));
+}
+
 static inline ThreadMgr *impl_from_ITfThreadMgrEventSink(ITfThreadMgrEventSink *iface)
 {
     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,ThreadMgrEventSinkVtbl));
@@ -143,6 +167,14 @@ static void ThreadMgr_Destructor(ThreadMgr *This)
         free_sink(sink);
     }
 
+    LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CurrentPreservedKeys)
+    {
+        PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
+        list_remove(cursor);
+        HeapFree(GetProcessHeap(),0,key->description);
+        HeapFree(GetProcessHeap(),0,key);
+    }
+
     HeapFree(GetProcessHeap(),0,This);
 }
 
@@ -163,6 +195,14 @@ static HRESULT WINAPI ThreadMgr_QueryInterface(ITfThreadMgr *iface, REFIID iid,
     {
         *ppvOut = &This->KeystrokeMgrVtbl;
     }
+    else if (IsEqualIID(iid, &IID_ITfMessagePump))
+    {
+        *ppvOut = &This->MessagePumpVtbl;
+    }
+    else if (IsEqualIID(iid, &IID_ITfClientId))
+    {
+        *ppvOut = &This->ClientIdVtbl;
+    }
 
     if (*ppvOut)
     {
@@ -198,23 +238,48 @@ static ULONG WINAPI ThreadMgr_Release(ITfThreadMgr *iface)
 static HRESULT WINAPI ThreadMgr_fnActivate( ITfThreadMgr* iface, TfClientId *ptid)
 {
     ThreadMgr *This = (ThreadMgr *)iface;
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+
+    TRACE("(%p) %p\n",This, ptid);
+
+    if (!ptid)
+        return E_INVALIDARG;
+
+    if (!processId)
+    {
+        GUID guid;
+        CoCreateGuid(&guid);
+        ITfClientId_GetClientId((ITfClientId*)&This->ClientIdVtbl,&guid,&processId);
+    }
+
+    activate_textservices(iface);
+    This->activationCount++;
+    *ptid = processId;
+    return S_OK;
 }
 
 static HRESULT WINAPI ThreadMgr_fnDeactivate( ITfThreadMgr* iface)
 {
     ThreadMgr *This = (ThreadMgr *)iface;
-    FIXME("STUB:(%p)\n",This);
+    TRACE("(%p)\n",This);
 
-    if (This->focus)
+    if (This->activationCount == 0)
+        return E_UNEXPECTED;
+
+    This->activationCount --;
+
+    if (This->activationCount == 0)
     {
-        ITfThreadMgrEventSink_OnSetFocus((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, 0, This->focus);
-        ITfDocumentMgr_Release(This->focus);
-        This->focus = 0;
+        if (This->focus)
+        {
+            ITfThreadMgrEventSink_OnSetFocus((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, 0, This->focus);
+            ITfDocumentMgr_Release(This->focus);
+            This->focus = 0;
+        }
     }
 
-    return E_NOTIMPL;
+    deactivate_textservices();
+
+    return S_OK;
 }
 
 static HRESULT WINAPI ThreadMgr_CreateDocumentMgr( ITfThreadMgr* iface, ITfDocumentMgr
@@ -508,8 +573,25 @@ static HRESULT WINAPI KeystrokeMgr_IsPreservedKey(ITfKeystrokeMgr *iface,
         REFGUID rguid, const TF_PRESERVEDKEY *pprekey, BOOL *pfRegistered)
 {
     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    struct list *cursor;
+
+    TRACE("(%p) %s (%x %x) %p\n",This,debugstr_guid(rguid), (pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0, pfRegistered);
+
+    if (!rguid || !pprekey || !pfRegistered)
+        return E_INVALIDARG;
+
+    LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
+    {
+        PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
+        if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
+        {
+            *pfRegistered = TRUE;
+            return S_OK;
+        }
+    }
+
+    *pfRegistered = FALSE;
+    return S_FALSE;
 }
 
 static HRESULT WINAPI KeystrokeMgr_PreserveKey(ITfKeystrokeMgr *iface,
@@ -517,16 +599,71 @@ static HRESULT WINAPI KeystrokeMgr_PreserveKey(ITfKeystrokeMgr *iface,
         const WCHAR *pchDesc, ULONG cchDesc)
 {
     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    struct list *cursor;
+    PreservedKey *newkey;
+
+    TRACE("(%p) %x %s (%x,%x) %s\n",This,tid, debugstr_guid(rguid),(prekey)?prekey->uVKey:0,(prekey)?prekey->uModifiers:0,debugstr_wn(pchDesc,cchDesc));
+
+    if (!tid || ! rguid || !prekey || (cchDesc && !pchDesc))
+        return E_INVALIDARG;
+
+    LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
+    {
+        PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
+        if (IsEqualGUID(rguid,&key->guid) && prekey->uVKey == key->prekey.uVKey && prekey->uModifiers == key->prekey.uModifiers)
+            return TF_E_ALREADY_EXISTS;
+    }
+
+    newkey = HeapAlloc(GetProcessHeap(),0,sizeof(PreservedKey));
+    if (!newkey)
+        return E_OUTOFMEMORY;
+
+    newkey->guid  = *rguid;
+    newkey->prekey = *prekey;
+    newkey->tid = tid;
+    if (cchDesc)
+    {
+        newkey->description = HeapAlloc(GetProcessHeap(),0,cchDesc * sizeof(WCHAR));
+        if (!newkey->description)
+        {
+            HeapFree(GetProcessHeap(),0,newkey);
+            return E_OUTOFMEMORY;
+        }
+        memcpy(newkey->description, pchDesc, cchDesc*sizeof(WCHAR));
+    }
+
+    list_add_head(&This->CurrentPreservedKeys,&newkey->entry);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI KeystrokeMgr_UnpreserveKey(ITfKeystrokeMgr *iface,
         REFGUID rguid, const TF_PRESERVEDKEY *pprekey)
 {
     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
-    FIXME("STUB:(%p)\n",This);
-    return E_NOTIMPL;
+    PreservedKey* key = NULL;
+    struct list *cursor;
+    TRACE("(%p) %s (%x %x)\n",This,debugstr_guid(rguid),(pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0);
+
+    if (!pprekey || !rguid)
+        return E_INVALIDARG;
+
+    LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
+    {
+        key = LIST_ENTRY(cursor,PreservedKey,entry);
+        if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
+            break;
+        key = NULL;
+    }
+
+    if (!key)
+        return CONNECT_E_NOCONNECTION;
+
+    list_remove(&key->entry);
+    HeapFree(GetProcessHeap(),0,key->description);
+    HeapFree(GetProcessHeap(),0,key);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI KeystrokeMgr_SetPreservedKeyDescription(ITfKeystrokeMgr *iface,
@@ -575,6 +712,128 @@ static const ITfKeystrokeMgrVtbl ThreadMgr_KeystrokeMgrVtbl =
     KeystrokeMgr_SimulatePreservedKey
 };
 
+/*****************************************************
+ * ITfMessagePump functions
+ *****************************************************/
+
+static HRESULT WINAPI MessagePump_QueryInterface(ITfMessagePump *iface, REFIID iid, LPVOID *ppvOut)
+{
+    ThreadMgr *This = impl_from_ITfMessagePumpVtbl(iface);
+    return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
+}
+
+static ULONG WINAPI MessagePump_AddRef(ITfMessagePump *iface)
+{
+    ThreadMgr *This = impl_from_ITfMessagePumpVtbl(iface);
+    return ThreadMgr_AddRef((ITfThreadMgr*)This);
+}
+
+static ULONG WINAPI MessagePump_Release(ITfMessagePump *iface)
+{
+    ThreadMgr *This = impl_from_ITfMessagePumpVtbl(iface);
+    return ThreadMgr_Release((ITfThreadMgr *)This);
+}
+
+static HRESULT WINAPI MessagePump_PeekMessageA(ITfMessagePump *iface,
+        LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
+        UINT wRemoveMsg, BOOL *pfResult)
+{
+    if (!pfResult)
+        return E_INVALIDARG;
+    *pfResult = PeekMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
+    return S_OK;
+}
+
+static HRESULT WINAPI MessagePump_GetMessageA(ITfMessagePump *iface,
+        LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
+        BOOL *pfResult)
+{
+    if (!pfResult)
+        return E_INVALIDARG;
+    *pfResult = GetMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
+    return S_OK;
+}
+
+static HRESULT WINAPI MessagePump_PeekMessageW(ITfMessagePump *iface,
+        LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
+        UINT wRemoveMsg, BOOL *pfResult)
+{
+    if (!pfResult)
+        return E_INVALIDARG;
+    *pfResult = PeekMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
+    return S_OK;
+}
+
+static HRESULT WINAPI MessagePump_GetMessageW(ITfMessagePump *iface,
+        LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
+        BOOL *pfResult)
+{
+    if (!pfResult)
+        return E_INVALIDARG;
+    *pfResult = GetMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
+    return S_OK;
+}
+
+static const ITfMessagePumpVtbl ThreadMgr_MessagePumpVtbl =
+{
+    MessagePump_QueryInterface,
+    MessagePump_AddRef,
+    MessagePump_Release,
+
+    MessagePump_PeekMessageA,
+    MessagePump_GetMessageA,
+    MessagePump_PeekMessageW,
+    MessagePump_GetMessageW
+};
+
+/*****************************************************
+ * ITfClientId functions
+ *****************************************************/
+
+static HRESULT WINAPI ClientId_QueryInterface(ITfClientId *iface, REFIID iid, LPVOID *ppvOut)
+{
+    ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
+    return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
+}
+
+static ULONG WINAPI ClientId_AddRef(ITfClientId *iface)
+{
+    ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
+    return ThreadMgr_AddRef((ITfThreadMgr*)This);
+}
+
+static ULONG WINAPI ClientId_Release(ITfClientId *iface)
+{
+    ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
+    return ThreadMgr_Release((ITfThreadMgr *)This);
+}
+
+static HRESULT WINAPI ClientId_GetClientId(ITfClientId *iface,
+    REFCLSID rclsid, TfClientId *ptid)
+
+{
+    HRESULT hr;
+    ITfCategoryMgr *catmgr;
+    ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
+
+    TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
+
+    CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr);
+    hr = ITfCategoryMgr_RegisterGUID(catmgr,rclsid,ptid);
+    ITfCategoryMgr_Release(catmgr);
+
+    return hr;
+}
+
+static const ITfClientIdVtbl ThreadMgr_ClientIdVtbl =
+{
+    ClientId_QueryInterface,
+    ClientId_AddRef,
+    ClientId_Release,
+
+    ClientId_GetClientId
+};
+
 /*****************************************************
  * ITfThreadMgrEventSink functions  (internal)
  *****************************************************/
@@ -718,10 +977,14 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
     This->ThreadMgrVtbl= &ThreadMgr_ThreadMgrVtbl;
     This->SourceVtbl = &ThreadMgr_SourceVtbl;
     This->KeystrokeMgrVtbl= &ThreadMgr_KeystrokeMgrVtbl;
+    This->MessagePumpVtbl= &ThreadMgr_MessagePumpVtbl;
+    This->ClientIdVtbl = &ThreadMgr_ClientIdVtbl;
     This->ThreadMgrEventSinkVtbl = &ThreadMgr_ThreadMgrEventSinkVtbl;
     This->refCount = 1;
     TlsSetValue(tlsIndex,This);
 
+    list_init(&This->CurrentPreservedKeys);
+
     list_init(&This->ActiveLanguageProfileNotifySink);
     list_init(&This->DisplayAttributeNotifySink);
     list_init(&This->KeyTraceEventSink);