Implementation of InprocServer32 CoGetClassObject.

diff --git a/include/ole.h b/include/ole.h
index c21f067..dfaab17 100644
--- a/include/ole.h
+++ b/include/ole.h
@@ -27,6 +27,17 @@
 #define OLESTR32(x) L##x	/* probably wrong */
 #define OLESTR WINELIB_NAME(OLESTR)
 
+typedef enum tagCLSCTX
+{
+    CLSCTX_INPROC_SERVER   = 0x1,
+    CLSCTX_INPROC_HANDLER  = 0x2,
+    CLSCTX_LOCAL_SERVER    = 0x4,
+    CLSCTX_REMOTE_SERVER   = 0x10,
+} CLSCTX;
+
+#define CLSCTX_SERVER (CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER)
+#define CLSCTX_ALL    (CLSCTX_INPROC_HANDLER|CLSCTX_SERVER)
+
 typedef unsigned short VARTYPE;
 typedef LONG DISPID;
 
diff --git a/include/winerror.h b/include/winerror.h
index 309617c..429ba2c 100644
--- a/include/winerror.h
+++ b/include/winerror.h
@@ -169,4 +169,9 @@
 /* Obtained from lcc-win32 include files */
 #define GDI_ERROR			0xffffffff
 
+
+/* registry errors */
+#define REGDB_E_READREGDB               0x80040150
+#define REGDB_E_CLASSNOTREG             0x80040154
+
 #endif  /* __WINE_WINERROR_H */
diff --git a/ole/compobj.c b/ole/compobj.c
index 051290a..03f89d3 100644
--- a/ole/compobj.c
+++ b/ole/compobj.c
@@ -507,20 +507,93 @@
                         LPVOID pvReserved, REFIID iid, LPVOID *ppv)
 {
     char xclsid[50],xiid[50];
-    LPCLASSFACTORY lpclf;
     HRESULT hres = E_UNEXPECTED;
+    char dllName[MAX_PATH+1];
+    LONG dllNameLen = MAX_PATH+1;
+    HINSTANCE32 hLibrary;
+    typedef HRESULT (*DllGetClassObjectFunc)(REFCLSID clsid,
+                            REFIID iid, LPVOID *ppv);
+    DllGetClassObjectFunc DllGetClassObject;
+
+    HKEY CLSIDkey;
+    char buf[MAX_PATH + 1];
+    int i;
+    int found;
 
     WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
     WINE_StringFromCLSID((LPCLSID)iid,xiid);
     TRACE(ole,"\n\tCLSID:\t%s,\n\tIID:\t%s\n",xclsid,xiid);
 
-    *ppv = NULL;
-    lpclf = IClassFactory_Constructor();
-    if (lpclf)
-    {
-        hres = lpclf->lpvtbl->fnQueryInterface(lpclf,iid, ppv);
-        lpclf->lpvtbl->fnRelease(lpclf);
+    /* out of process and remote servers not supported yet */
+    if ((CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER) & dwClsContext) {
+        FIXME(ole, "CLSCTX_LOCAL_SERVER and CLSCTX_REMOTE_SERVER not supported!\n");
+       return E_ACCESSDENIED;
     }
+
+    if ((CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER) & dwClsContext) {
+
+        /* lookup CLSID in registry key HKCR/CLSID */
+        hres = RegOpenKeyEx32A(HKEY_CLASSES_ROOT, "CLSID", 0,
+                              KEY_ENUMERATE_SUB_KEYS, &CLSIDkey);
+
+       if (hres != ERROR_SUCCESS) {
+           return REGDB_E_READREGDB;
+       }
+
+       /* search all the subkeys for a match to xclsid */
+       found=FALSE;
+       for (i=0; i<100000; i++) {
+
+           char clsidKeyPath[MAX_PATH + 1];
+           HKEY key;
+           LONG res;
+
+           res = RegEnumKey32A(CLSIDkey, i, buf, MAX_PATH);
+           if (res == ERROR_NO_MORE_ITEMS)
+               break;
+           if (res != ERROR_SUCCESS)
+               continue;
+
+           sprintf(clsidKeyPath, "CLSID\\%s", buf);
+
+           if (lstrcmpi32A(buf, xclsid) != 0)
+               continue;
+
+           res = RegOpenKeyEx32A(HKEY_CLASSES_ROOT, clsidKeyPath, 0,
+                                 KEY_QUERY_VALUE, &key);
+           if (res != ERROR_SUCCESS) {
+               return REGDB_E_READREGDB;
+           }
+           hres = RegQueryValue32A(key, "InprocServer32", dllName, &dllNameLen);
+           if (res != ERROR_SUCCESS) {
+               return REGDB_E_READREGDB;
+           }
+           TRACE(ole,"found InprocServer32 dll %s\n", dllName);
+           found = TRUE;
+           break;
+       }
+
+       if (!found) {
+           return REGDB_E_CLASSNOTREG;
+       }
+
+       /* open dll, call DllGetClassFactory */
+       hLibrary = LoadLibrary32A(dllName);
+
+       if (hLibrary == 0) {
+           TRACE(ole,"couldn't load InprocServer32 dll %s\n", dllName);
+
+           return E_ACCESSDENIED; /* or should this be CO_E_DLLNOTFOUND? */
+       }
+
+       DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress32(hLibrary, "DllGetClassObject");
+       if (DllGetClassObject == NULL) {
+           TRACE(ole,"couldn't find function DllGetClassObject in %s\n", dllName);
+           return E_ACCESSDENIED;
+       }
+       return DllGetClassObject(rclsid, iid, ppv);
+    }
+
     return hres;
 }
 
@@ -563,7 +636,8 @@
 	HRESULT hres;
 	LPCLASSFACTORY lpclf = 0;
 
-	CoGetClassObject(rclsid, dwClsContext, NULL, &IID_IClassFactory, (LPVOID)&lpclf);
+        hres = CoGetClassObject(rclsid, dwClsContext, NULL, &IID_IClassFactory, (LPVOID)&lpclf);
+        if (!SUCCEEDED(hres)) return hres;
 	hres = lpclf->lpvtbl->fnCreateInstance(lpclf, pUnkOuter, iid, ppv);
 	lpclf->lpvtbl->fnRelease(lpclf);
 	return hres;