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?
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=40206 --- configure | 26 +- configure.ac | 1 + dlls/portabledeviceapi/Makefile.in | 7 + dlls/portabledeviceapi/portabledeviceapi.c | 138 ++++++++++ dlls/portabledeviceapi/portabledeviceapi.spec | 4 + .../portabledeviceapi_classes.idl | 21 ++ .../portabledeviceapi_private.h | 26 ++ include/Makefile.in | 1 + include/portabledeviceapi.idl | 71 +++++ include/wine/com.h | 256 ++++++++++++++++++ 10 files changed, 533 insertions(+), 18 deletions(-) create mode 100644 dlls/portabledeviceapi/Makefile.in create mode 100644 dlls/portabledeviceapi/portabledeviceapi.c create mode 100644 dlls/portabledeviceapi/portabledeviceapi.spec create mode 100644 dlls/portabledeviceapi/portabledeviceapi_classes.idl create mode 100644 dlls/portabledeviceapi/portabledeviceapi_private.h create mode 100644 include/portabledeviceapi.idl create mode 100644 include/wine/com.h
diff --git a/configure b/configure index 7f9786f6eb..b4f79e01cc 100755 --- a/configure +++ b/configure @@ -805,7 +805,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -1477,6 +1476,7 @@ enable_packager enable_pdh enable_photometadatahandler enable_pidgen +enable_portabledeviceapi enable_powrprof enable_printui enable_prntvpt @@ -1879,7 +1879,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -2132,15 +2131,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;;
- -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -2278,7 +2268,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=$$ac_var # Remove trailing slashes. @@ -2431,7 +2421,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -6822,7 +6811,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -6868,7 +6857,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -6892,7 +6881,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -6937,7 +6926,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -6961,7 +6950,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -19746,6 +19735,7 @@ wine_fn_config_makefile dlls/pdh enable_pdh wine_fn_config_makefile dlls/pdh/tests enable_tests wine_fn_config_makefile dlls/photometadatahandler enable_photometadatahandler wine_fn_config_makefile dlls/pidgen enable_pidgen +wine_fn_config_makefile dlls/portabledeviceapi enable_portabledeviceapi wine_fn_config_makefile dlls/powrprof enable_powrprof wine_fn_config_makefile dlls/printui enable_printui wine_fn_config_makefile dlls/prntvpt enable_prntvpt diff --git a/configure.ac b/configure.ac index efec221113..a3aa4cb839 100644 --- a/configure.ac +++ b/configure.ac @@ -3595,6 +3595,7 @@ WINE_CONFIG_MAKEFILE(dlls/pdh) WINE_CONFIG_MAKEFILE(dlls/pdh/tests) WINE_CONFIG_MAKEFILE(dlls/photometadatahandler) WINE_CONFIG_MAKEFILE(dlls/pidgen) +WINE_CONFIG_MAKEFILE(dlls/portabledeviceapi) WINE_CONFIG_MAKEFILE(dlls/powrprof) WINE_CONFIG_MAKEFILE(dlls/printui) WINE_CONFIG_MAKEFILE(dlls/prntvpt) diff --git a/dlls/portabledeviceapi/Makefile.in b/dlls/portabledeviceapi/Makefile.in new file mode 100644 index 0000000000..f57ef8b57b --- /dev/null +++ b/dlls/portabledeviceapi/Makefile.in @@ -0,0 +1,7 @@ +MODULE = portabledeviceapi.dll +IMPORTS = uuid ole32 + +C_SRCS = \ + portabledeviceapi.c + +IDL_SRCS = portabledeviceapi_classes.idl diff --git a/dlls/portabledeviceapi/portabledeviceapi.c b/dlls/portabledeviceapi/portabledeviceapi.c new file mode 100644 index 0000000000..da91af9aca --- /dev/null +++ b/dlls/portabledeviceapi/portabledeviceapi.c @@ -0,0 +1,138 @@ +/* + * 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 + */ + +#include "config.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(deviceapi); + +#define WINE_COM_MAIN +#include "wine/com.h" + +#include "portabledeviceapi_private.h" + +#include "initguid.h" +#include "portabledeviceapi.h" + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + return com_main(instance, reason, reserved); +} + +static const com_object_creation_info object_creation[] = +{ + { &CLSID_PortableDeviceManager, &PortableDeviceManager_create }, +}; + +HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) +{ + return com_get_class_object(object_creation, ARRAY_SIZE(object_creation), rclsid, riid, ppv); +} + +HRESULT WINAPI DllCanUnloadNow(void) +{ + return S_FALSE; +} + +HRESULT WINAPI DllRegisterServer(void) +{ + return __wine_register_resources(instance_dll); +} + +HRESULT WINAPI DllUnregisterServer(void) +{ + return __wine_unregister_resources(instance_dll); +} + +COM_DEFINE_OBJECT_WITH_SINGLE_INTERFACE(PortableDeviceManager, IPortableDeviceManager) +COM_DEFINE_QueryInterface(PortableDeviceManager, IPortableDeviceManager) +COM_DEFINE_AddRef(PortableDeviceManager, IPortableDeviceManager) +COM_DEFINE_Release(PortableDeviceManager, IPortableDeviceManager) + +static HRESULT WINAPI IPortableDeviceManager_impl_GetDevices(IPortableDeviceManager *iface, + LPWSTR *pPnPDeviceIDs, DWORD *pcPnPDeviceIDs) +{ + FIXME("(%p, %p): stub!\n", pPnPDeviceIDs, pcPnPDeviceIDs); + + return E_NOTIMPL; +} + +static HRESULT WINAPI IPortableDeviceManager_impl_RefreshDeviceList(IPortableDeviceManager *iface) +{ + FIXME("(): stub!\n"); + + return E_NOTIMPL; +} + +static HRESULT WINAPI IPortableDeviceManager_impl_GetDeviceFriendlyName(IPortableDeviceManager *iface, + LPCWSTR pszPnPDeviceID, WCHAR *pDeviceFriendlyName, DWORD* pcchDeviceFriendlyName) +{ + FIXME("(%s, %p): stub!\n", debugstr_w(pszPnPDeviceID), pDeviceFriendlyName); + + return E_NOTIMPL; +} + +static HRESULT WINAPI IPortableDeviceManager_impl_GetDeviceDescription(IPortableDeviceManager *iface, + LPCWSTR pszPnPDeviceID, WCHAR *pDeviceDescription, DWORD *pcchDeviceDescription) +{ + FIXME("(%s, %p, %p): stub!\n", debugstr_w(pszPnPDeviceID), pDeviceDescription, pcchDeviceDescription); + + return E_NOTIMPL; +} + +static HRESULT WINAPI IPortableDeviceManager_impl_GetDeviceManufacturer(IPortableDeviceManager *iface, + LPCWSTR pszPnPDeviceID, WCHAR *pDeviceManufacturer, DWORD *pcchDeviceManufacturer) +{ + FIXME("(%s, %p, %p): stub!\n", debugstr_w(pszPnPDeviceID), pDeviceManufacturer, pcchDeviceManufacturer); + + return E_NOTIMPL; +} + +static HRESULT WINAPI IPortableDeviceManager_impl_GetDeviceProperty(IPortableDeviceManager *iface, + LPCWSTR pszPnPDeviceID, LPCWSTR pszDevicePropertyName, BYTE *pData, DWORD *pcbData, DWORD *pdwType) +{ + FIXME("(%s, %s, %p, %p, %p): stub!\n", + debugstr_w(pszPnPDeviceID), debugstr_w(pszDevicePropertyName), pData, pcbData, pdwType); + + return E_NOTIMPL; +} + +static HRESULT WINAPI IPortableDeviceManager_impl_GetPrivateDevices(IPortableDeviceManager *iface, + LPWSTR *pPnPDeviceIDs, DWORD *pcPnPDeviceIDs) +{ + FIXME("(%p, %p): stub!\n", pPnPDeviceIDs, pcPnPDeviceIDs); + + return E_NOTIMPL; +} + +static const IPortableDeviceManagerVtbl IPortableDeviceManager_vtbl = +{ + IPortableDeviceManager_impl_QueryInterface, + IPortableDeviceManager_impl_AddRef, + IPortableDeviceManager_impl_Release, + IPortableDeviceManager_impl_GetDevices, + IPortableDeviceManager_impl_RefreshDeviceList, + IPortableDeviceManager_impl_GetDeviceFriendlyName, + IPortableDeviceManager_impl_GetDeviceDescription, + IPortableDeviceManager_impl_GetDeviceManufacturer, + IPortableDeviceManager_impl_GetDeviceProperty, + IPortableDeviceManager_impl_GetPrivateDevices +}; + +COM_DEFINE_CREATE_FOR_OBJECT_WITH_SINGLE_INTERFACE(PortableDeviceManager, IPortableDeviceManager, IPortableDeviceManager_vtbl) diff --git a/dlls/portabledeviceapi/portabledeviceapi.spec b/dlls/portabledeviceapi/portabledeviceapi.spec new file mode 100644 index 0000000000..b16365d0c9 --- /dev/null +++ b/dlls/portabledeviceapi/portabledeviceapi.spec @@ -0,0 +1,4 @@ +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetClassObject(ptr ptr ptr) +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer() diff --git a/dlls/portabledeviceapi/portabledeviceapi_classes.idl b/dlls/portabledeviceapi/portabledeviceapi_classes.idl new file mode 100644 index 0000000000..0da8f228da --- /dev/null +++ b/dlls/portabledeviceapi/portabledeviceapi_classes.idl @@ -0,0 +1,21 @@ +/* + * 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 + */ + +#pragma makedep register + +#include "portabledeviceapi.idl" diff --git a/dlls/portabledeviceapi/portabledeviceapi_private.h b/dlls/portabledeviceapi/portabledeviceapi_private.h new file mode 100644 index 0000000000..0624a814af --- /dev/null +++ b/dlls/portabledeviceapi/portabledeviceapi_private.h @@ -0,0 +1,26 @@ +/* + * 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 __PORTABLEDEVICEAPI_PRIVATE_INCLUDED__ +#define __PORTABLEDEVICEAPI_PRIVATE_INCLUDED__ + +#include "unknwn.h" + +HRESULT PortableDeviceManager_create(IUnknown *unk_outer, void **obj) DECLSPEC_HIDDEN; + +#endif /* __PORTABLEDEVICEAPI_PRIVATE_INCLUDED__ */ diff --git a/include/Makefile.in b/include/Makefile.in index cc78b1c154..cf4fa317f0 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -511,6 +511,7 @@ SOURCES = \ physicalmonitorenumerationapi.h \ pktdef.h \ poppack.h \ + portabledeviceapi.idl \ powrprof.h \ prntvpt.h \ profinfo.h \ diff --git a/include/portabledeviceapi.idl b/include/portabledeviceapi.idl new file mode 100644 index 0000000000..523da782f0 --- /dev/null +++ b/include/portabledeviceapi.idl @@ -0,0 +1,71 @@ +/* + * 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 + */ + +#include "unknwn.idl" + +[ + object, + uuid(a1567595-4c2f-4574-a6fa-ecef917b9a40), + local +] +interface IPortableDeviceManager : IUnknown +{ + HRESULT GetDevices( + [in, out] LPWSTR *pPnPDeviceIDs, + [in, out] DWORD *pcPnPDeviceIDs + ); + + HRESULT RefreshDeviceList(); + + HRESULT GetDeviceFriendlyName( + [in] LPCWSTR pszPnPDeviceID, + [in, out] WCHAR *pDeviceFriendlyName, + [in, out] DWORD *pcchDeviceFriendlyName + ); + + HRESULT GetDeviceDescription( + [in] LPCWSTR pszPnPDeviceID, + [in, out] WCHAR *pDeviceDescription, + [in, out] DWORD *pcchDeviceDescription + ); + + HRESULT GetDeviceManufacturer( + [in] LPCWSTR pszPnPDeviceID, + [in, out] WCHAR *pDeviceManufacturer, + [in, out] DWORD *pcchDeviceManufacturer + ); + + HRESULT GetDeviceProperty( + [in] LPCWSTR pszPnPDeviceID, + [in] LPCWSTR pszDevicePropertyName, + [in, out] BYTE *pData, + [in, out] DWORD *pcbData, + [in, out] DWORD *pdwType + ); + + HRESULT GetPrivateDevices( + [in, out] LPWSTR *pPnPDeviceIDs, + [in, out] DWORD *pcPnPDeviceIDs + ); +}; + +[ + threading(both), + uuid(0af10cec-2ecd-4b92-9581-34f6ae0637f3) +] +coclass PortableDeviceManager { interface IPortableDeviceManager; } 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 @@ -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 inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface) +{ + return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface); +} + +static HRESULT WINAPI classfactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj) +{ + IClassFactoryImpl *impl = impl_from_IClassFactory(iface); + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IClassFactory)) + { + IClassFactory_AddRef(iface); + *ppobj = &impl->IClassFactory_iface; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", impl, debugstr_guid(riid), ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI classfactory_AddRef(IClassFactory *iface) +{ + IClassFactoryImpl *This = impl_from_IClassFactory(iface); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI classfactory_Release(IClassFactory *iface) +{ + IClassFactoryImpl *impl = impl_from_IClassFactory(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + + if (ref == 0) + HeapFree(GetProcessHeap(), 0, impl); + + return ref; +} + +static HRESULT WINAPI classfactory_CreateInstance(IClassFactory *iface, IUnknown *outer_unk, REFIID riid, void **ppobj) +{ + IClassFactoryImpl *impl = impl_from_IClassFactory(iface); + HRESULT hres; + IUnknown *unk; + + TRACE("(%p)->(%p,%s,%p)\n", impl, outer_unk, debugstr_guid(riid), ppobj); + + *ppobj = NULL; + hres = impl->pfnCreateInstance(outer_unk, (void **) &unk); + if (SUCCEEDED(hres)) + { + hres = IUnknown_QueryInterface(unk, riid, ppobj); + IUnknown_Release(unk); + } + return hres; +} + +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; +} + +#endif /* WINE_COM_MAIN */ + +#define COM_DEFINE_OBJECT_WITH_SINGLE_INTERFACE(CLASS, INTERFACE) \ + typedef struct { \ + INTERFACE INTERFACE##_iface; \ + LONG ref; \ + } CLASS##_impl; \ + \ + static inline CLASS##_impl *impl_from_##INTERFACE(INTERFACE *iface) \ + { \ + return CONTAINING_RECORD(iface, CLASS##_impl, INTERFACE##_iface); \ + } \ + +#define COM_DEFINE_QueryInterface(CLASS, INTERFACE) \ + static HRESULT WINAPI INTERFACE##_impl_QueryInterface(INTERFACE *iface, \ + REFIID riid, void **obj) \ + { \ + CLASS##_impl *impl = impl_from_##INTERFACE(iface); \ + TRACE("(%p/%p)->(%s,%p)\n", iface, impl, debugstr_guid(riid), obj); \ + if (IsEqualGUID(riid, &IID_IUnknown) \ + || IsEqualGUID(riid, &IID_##INTERFACE)) \ + { \ + IUnknown_AddRef(iface); \ + *obj = &impl->INTERFACE##_iface; \ + return S_OK; \ + } \ + ERR("(%p)->(%s,%p),not found\n", impl, debugstr_guid(riid), obj); \ + return E_NOINTERFACE; \ + } + +#define COM_DEFINE_AddRef(CLASS, INTERFACE) \ + static ULONG WINAPI INTERFACE##_impl_AddRef(INTERFACE *iface) \ + { \ + CLASS##_impl *impl = impl_from_##INTERFACE(iface); \ + ULONG ref = InterlockedIncrement(&impl->ref); \ + TRACE("(%p/%p)->(): new ref %d\n", iface, impl, ref); \ + return ref; \ + } \ + +#define COM_DEFINE_Release(CLASS, INTERFACE) \ + static ULONG WINAPI INTERFACE##_impl_Release(INTERFACE *iface) \ + { \ + CLASS##_impl *impl = impl_from_##INTERFACE(iface); \ + ULONG ref = InterlockedDecrement(&impl->ref); \ + TRACE("(%p/%p)->(): new ref %d\n", iface, impl, ref); \ + if (!ref) \ + HeapFree(GetProcessHeap(), 0, impl); \ + return ref; \ + } + +#define COM_DEFINE_CREATE_FOR_OBJECT_WITH_SINGLE_INTERFACE(CLASS, INTERFACE, TABLE) \ + HRESULT CLASS##_create(IUnknown *unk_outer, void **obj) \ + { \ + CLASS##_impl *impl; \ + TRACE("(%p,%p)\n", unk_outer, obj); \ + impl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLASS##_impl)); \ + if (!impl) \ + return E_OUTOFMEMORY; \ + impl->INTERFACE##_iface.lpVtbl = &TABLE; \ + impl->ref = 1; \ + *obj = &impl->INTERFACE##_iface; \ + return S_OK; \ + } + +#ifdef __cplusplus +} +#endif + +#endif /* __WINE_WINE_COM_H */