Hi Fabian,
This is a first try to generalize COM implementations. I find it useful to not repeat all that code for every new implementation. Feedback appreciated, can we go that route?
diff --git a/include/wine/com.h b/include/wine/com.h new file mode 100644 index 0000000000..2f73bfcbd0 --- /dev/null +++ b/include/wine/com.h
I'm skeptical about this being general COM helper. A header just
for class factory could be better.
@@ -0,0 +1,256 @@ +/* + * COM helper functions + * + * Copyright 2018 Fabian Maurer + * + * 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 + */ + +#ifndef __WINE_WINE_COM_H +#define __WINE_WINE_COM_H + +#define COBJMACROS +#include "unknwn.h" + +#include <stdarg.h> +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "rpcproxy.h" + +#include "wine/debug.h" + +#ifdef __WINE_WINE_TEST_H +#error This file should not be used in Wine tests +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static HINSTANCE instance_dll; + +#ifdef WINE_COM_MAIN + +typedef struct +{ + const CLSID *clsid; + HRESULT (*pfnCreateInstance)(IUnknown *unk_outer, void **ppobj); +} com_object_creation_info;
+ +typedef struct +{ + IClassFactory IClassFactory_iface; + + LONG ref;
+ HRESULT (*pfnCreateInstance)(IUnknown *unk_outer, void **ppobj);
+} IClassFactoryImpl;
+ +static inline BOOL WINAPI com_main(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + TRACE("(0x%p, %d, %p)\n", instance, reason, reserved); + + switch (reason) + { + case DLL_WINE_PREATTACH: + return FALSE; /* prefer native version */ + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(instance); + instance_dll = instance; + break; + } + + return TRUE; +}
+static HRESULT WINAPI classfactory_LockServer(IClassFactory *iface, BOOL dolock) +{ + IClassFactoryImpl *impl = impl_from_IClassFactory(iface); + FIXME("(%p)->(%d), stub!\n", impl, dolock);
+ return S_OK; +} + +static const IClassFactoryVtbl classfactory_Vtbl = +{ + classfactory_QueryInterface, + classfactory_AddRef, + classfactory_Release, + classfactory_CreateInstance, + classfactory_LockServer +}; + +HRESULT WINAPI com_get_class_object(const com_object_creation_info *object_creation, int object_creation_length, + REFCLSID rclsid, REFIID riid, void **ppv) +{ + unsigned int i; + IClassFactoryImpl *factory; + + TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + + if (!IsEqualGUID(&IID_IClassFactory, riid) + && !IsEqualGUID( &IID_IUnknown, riid)) + return E_NOINTERFACE; + + for (i = 0; i < object_creation_length; i++) + { + if (IsEqualGUID(object_creation[i].clsid, rclsid)) + break; + } + + if (i == object_creation_length) + { + FIXME("%s: no class found.\n", debugstr_guid(rclsid)); + return CLASS_E_CLASSNOTAVAILABLE; + } + + factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory)); + if (factory == NULL) + return E_OUTOFMEMORY; + + factory->IClassFactory_iface.lpVtbl = &classfactory_Vtbl; + factory->ref = 1; + + factory->pfnCreateInstance = object_creation[i].pfnCreateInstance; + + *ppv = &factory->IClassFactory_iface; + return S_OK; +}