| /* | 
 |  * COM proxy/stub factory (CStdPSFactory) implementation | 
 |  * | 
 |  * Copyright 2001 Ove Kåven, TransGaming Technologies | 
 |  * | 
 |  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
 |  */ | 
 |  | 
 | #include <stdarg.h> | 
 | #include <stdio.h> | 
 | #include <string.h> | 
 |  | 
 | #include "windef.h" | 
 | #include "winbase.h" | 
 | #include "winerror.h" | 
 | #include "winreg.h" | 
 |  | 
 | #include "objbase.h" | 
 |  | 
 | #include "rpcproxy.h" | 
 |  | 
 | #include "wine/debug.h" | 
 |  | 
 | #include "cpsf.h" | 
 |  | 
 | WINE_DEFAULT_DEBUG_CHANNEL(ole); | 
 |  | 
 | static BOOL FindProxyInfo(const ProxyFileInfo **pProxyFileList, REFIID riid, const ProxyFileInfo **pProxyInfo, int *pIndex) | 
 | { | 
 |   while (*pProxyFileList) { | 
 |     if ((*pProxyFileList)->pIIDLookupRtn(riid, pIndex)) { | 
 |       *pProxyInfo = *pProxyFileList; | 
 |       TRACE("found: ProxyInfo %p Index %d\n", *pProxyInfo, *pIndex); | 
 |       return TRUE; | 
 |     } | 
 |     pProxyFileList++; | 
 |   } | 
 |   TRACE("not found\n"); | 
 |   return FALSE; | 
 | } | 
 |  | 
 | static HRESULT WINAPI CStdPSFactory_QueryInterface(LPPSFACTORYBUFFER iface, | 
 |                                                   REFIID riid, | 
 |                                                   LPVOID *obj) | 
 | { | 
 |   ICOM_THIS(CStdPSFactoryBuffer,iface); | 
 |   TRACE("(%p)->QueryInterface(%s,%p)\n",iface,debugstr_guid(riid),obj); | 
 |   if (IsEqualGUID(&IID_IUnknown,riid) || | 
 |       IsEqualGUID(&IID_IPSFactoryBuffer,riid)) { | 
 |     *obj = This; | 
 |     This->RefCount++; | 
 |     return S_OK; | 
 |   } | 
 |   return E_NOINTERFACE; | 
 | } | 
 |  | 
 | static ULONG WINAPI CStdPSFactory_AddRef(LPPSFACTORYBUFFER iface) | 
 | { | 
 |   ICOM_THIS(CStdPSFactoryBuffer,iface); | 
 |   TRACE("(%p)->AddRef()\n",iface); | 
 |   return ++(This->RefCount); | 
 | } | 
 |  | 
 | static ULONG WINAPI CStdPSFactory_Release(LPPSFACTORYBUFFER iface) | 
 | { | 
 |   ICOM_THIS(CStdPSFactoryBuffer,iface); | 
 |   TRACE("(%p)->Release()\n",iface); | 
 |   return --(This->RefCount); | 
 | } | 
 |  | 
 | static HRESULT WINAPI CStdPSFactory_CreateProxy(LPPSFACTORYBUFFER iface, | 
 |                                                LPUNKNOWN pUnkOuter, | 
 |                                                REFIID riid, | 
 |                                                LPRPCPROXYBUFFER *ppProxy, | 
 |                                                LPVOID *ppv) | 
 | { | 
 |   ICOM_THIS(CStdPSFactoryBuffer,iface); | 
 |   const ProxyFileInfo *ProxyInfo; | 
 |   int Index; | 
 |   TRACE("(%p)->CreateProxy(%p,%s,%p,%p)\n",iface,pUnkOuter, | 
 |        debugstr_guid(riid),ppProxy,ppv); | 
 |   if (!FindProxyInfo(This->pProxyFileList,riid,&ProxyInfo,&Index)) | 
 |     return E_NOINTERFACE; | 
 |   return StdProxy_Construct(riid, pUnkOuter, ProxyInfo->pNamesArray[Index], | 
 |                             ProxyInfo->pProxyVtblList[Index], | 
 |                             ProxyInfo->pStubVtblList[Index], iface, ppProxy, ppv); | 
 | } | 
 |  | 
 | static HRESULT WINAPI CStdPSFactory_CreateStub(LPPSFACTORYBUFFER iface, | 
 |                                               REFIID riid, | 
 |                                               LPUNKNOWN pUnkServer, | 
 |                                               LPRPCSTUBBUFFER *ppStub) | 
 | { | 
 |   ICOM_THIS(CStdPSFactoryBuffer,iface); | 
 |   const ProxyFileInfo *ProxyInfo; | 
 |   int Index; | 
 |   TRACE("(%p)->CreateStub(%s,%p,%p)\n",iface,debugstr_guid(riid), | 
 |        pUnkServer,ppStub); | 
 |   if (!FindProxyInfo(This->pProxyFileList,riid,&ProxyInfo,&Index)) | 
 |     return E_NOINTERFACE; | 
 |   return CStdStubBuffer_Construct(riid, pUnkServer, ProxyInfo->pNamesArray[Index], | 
 |                                   ProxyInfo->pStubVtblList[Index], iface, ppStub); | 
 | } | 
 |  | 
 | static ICOM_VTABLE(IPSFactoryBuffer) CStdPSFactory_Vtbl = | 
 | { | 
 |   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE | 
 |   CStdPSFactory_QueryInterface, | 
 |   CStdPSFactory_AddRef, | 
 |   CStdPSFactory_Release, | 
 |   CStdPSFactory_CreateProxy, | 
 |   CStdPSFactory_CreateStub | 
 | }; | 
 |  | 
 | /*********************************************************************** | 
 |  *           NdrDllGetClassObject [RPCRT4.@] | 
 |  */ | 
 | HRESULT WINAPI NdrDllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv, | 
 |                                    const ProxyFileInfo **pProxyFileList, | 
 |                                    const CLSID *pclsid, | 
 |                                    CStdPSFactoryBuffer *pPSFactoryBuffer) | 
 | { | 
 |   *ppv = NULL; | 
 |   if (!pPSFactoryBuffer->lpVtbl) { | 
 |     pPSFactoryBuffer->lpVtbl = &CStdPSFactory_Vtbl; | 
 |     pPSFactoryBuffer->RefCount = 0; | 
 |     pPSFactoryBuffer->pProxyFileList = pProxyFileList; | 
 |   } | 
 |   if (IsEqualGUID(rclsid, pclsid)) | 
 |     return IPSFactoryBuffer_QueryInterface((LPPSFACTORYBUFFER)pPSFactoryBuffer, iid, ppv); | 
 |   return CLASS_E_CLASSNOTAVAILABLE; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           NdrDllCanUnloadNow [RPCRT4.@] | 
 |  */ | 
 | HRESULT WINAPI NdrDllCanUnloadNow(CStdPSFactoryBuffer *pPSFactoryBuffer) | 
 | { | 
 |   return !(pPSFactoryBuffer->RefCount); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           NdrDllRegisterProxy [RPCRT4.@] | 
 |  */ | 
 | HRESULT WINAPI NdrDllRegisterProxy(HMODULE hDll, | 
 |                                   const ProxyFileInfo **pProxyFileList, | 
 |                                   const CLSID *pclsid) | 
 | { | 
 |   LPSTR clsid; | 
 |   char keyname[120], module[MAX_PATH]; | 
 |   HKEY key, subkey; | 
 |   DWORD len; | 
 |  | 
 |   TRACE("(%p,%p,%s)\n", hDll, pProxyFileList, debugstr_guid(pclsid)); | 
 |   UuidToStringA((UUID*)pclsid, (unsigned char**)&clsid); | 
 |  | 
 |   /* register interfaces to point to clsid */ | 
 |   while (*pProxyFileList) { | 
 |     unsigned u; | 
 |     for (u=0; u<(*pProxyFileList)->TableSize; u++) { | 
 |       CInterfaceStubVtbl *proxy = (*pProxyFileList)->pStubVtblList[u]; | 
 |       PCInterfaceName name = (*pProxyFileList)->pNamesArray[u]; | 
 |       LPSTR iid; | 
 |  | 
 |       TRACE("registering %s %s => %s\n", name, debugstr_guid(proxy->header.piid), clsid); | 
 |  | 
 |       UuidToStringA((UUID*)proxy->header.piid, (unsigned char**)&iid); | 
 |       snprintf(keyname, sizeof(keyname), "Interface\\{%s}", iid); | 
 |       RpcStringFreeA((unsigned char**)&iid); | 
 |       if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyname, 0, NULL, 0, | 
 |                           KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { | 
 |         if (name) | 
 |           RegSetValueExA(key, NULL, 0, REG_SZ, name, strlen(name)); | 
 |         if (RegCreateKeyExA(key, "ProxyStubClsid32", 0, NULL, 0, | 
 |                             KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS) { | 
 |           snprintf(module, sizeof(module), "{%s}", clsid); | 
 |           RegSetValueExA(subkey, NULL, 0, REG_SZ, module, strlen(module)); | 
 |           RegCloseKey(subkey); | 
 |         } | 
 |         RegCloseKey(key); | 
 |       } | 
 |     } | 
 |     pProxyFileList++; | 
 |   } | 
 |  | 
 |   /* register clsid to point to module */ | 
 |   snprintf(keyname, sizeof(keyname), "CLSID\\{%s}", clsid); | 
 |   len = GetModuleFileNameA(hDll, module, sizeof(module)); | 
 |   if (len && len < sizeof(module)) { | 
 |     TRACE("registering CLSID %s => %s\n", clsid, module); | 
 |     if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyname, 0, NULL, 0, | 
 |                         KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { | 
 |       if (RegCreateKeyExA(key, "InProcServer32", 0, NULL, 0, | 
 |                           KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS) { | 
 |         RegSetValueExA(subkey, NULL, 0, REG_SZ, module, strlen(module)); | 
 |         RegCloseKey(subkey); | 
 |       } | 
 |       RegCloseKey(key); | 
 |     } | 
 |   } | 
 |  | 
 |   /* done */ | 
 |   RpcStringFreeA((unsigned char**)&clsid); | 
 |   return S_OK; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *           NdrDllUnregisterProxy [RPCRT4.@] | 
 |  */ | 
 | HRESULT WINAPI NdrDllUnregisterProxy(HMODULE hDll, | 
 |                                     const ProxyFileInfo **pProxyFileList, | 
 |                                     const CLSID *pclsid) | 
 | { | 
 |   LPSTR clsid; | 
 |   char keyname[120], module[MAX_PATH]; | 
 |   DWORD len; | 
 |  | 
 |   TRACE("(%p,%p,%s)\n", hDll, pProxyFileList, debugstr_guid(pclsid)); | 
 |   UuidToStringA((UUID*)pclsid, (unsigned char**)&clsid); | 
 |  | 
 |   /* unregister interfaces */ | 
 |   while (*pProxyFileList) { | 
 |     unsigned u; | 
 |     for (u=0; u<(*pProxyFileList)->TableSize; u++) { | 
 |       CInterfaceStubVtbl *proxy = (*pProxyFileList)->pStubVtblList[u]; | 
 |       PCInterfaceName name = (*pProxyFileList)->pNamesArray[u]; | 
 |       LPSTR iid; | 
 |  | 
 |       TRACE("unregistering %s %s <= %s\n", name, debugstr_guid(proxy->header.piid), clsid); | 
 |  | 
 |       UuidToStringA((UUID*)proxy->header.piid, (unsigned char**)&iid); | 
 |       snprintf(keyname, sizeof(keyname), "Interface\\{%s}", iid); | 
 |       RpcStringFreeA((unsigned char**)&iid); | 
 |       RegDeleteKeyA(HKEY_CLASSES_ROOT, keyname); | 
 |     } | 
 |     pProxyFileList++; | 
 |   } | 
 |  | 
 |   /* unregister clsid */ | 
 |   snprintf(keyname, sizeof(keyname), "CLSID\\{%s}", clsid); | 
 |   len = GetModuleFileNameA(hDll, module, sizeof(module)); | 
 |   if (len && len < sizeof(module)) { | 
 |     TRACE("unregistering CLSID %s <= %s\n", clsid, module); | 
 |     RegDeleteKeyA(HKEY_CLASSES_ROOT, keyname); | 
 |   } | 
 |  | 
 |   /* done */ | 
 |   RpcStringFreeA((unsigned char**)&clsid); | 
 |   return S_OK; | 
 | } |