| /* |
| * Copyright 2014 Andrew Eikum for CodeWeavers |
| * |
| * 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 <stdarg.h> |
| |
| #define COBJMACROS |
| #include "initguid.h" |
| #include "windef.h" |
| #include "winbase.h" |
| #include "ole2.h" |
| #include "rpcproxy.h" |
| #include "shellapi.h" |
| #include "shlwapi.h" |
| |
| #include "wine/debug.h" |
| |
| #include "packager_classes.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(packager); |
| |
| static HINSTANCE g_instance; |
| |
| struct Package { |
| IOleObject IOleObject_iface; |
| IPersistStorage IPersistStorage_iface; |
| |
| LONG ref; |
| |
| WCHAR filename[MAX_PATH]; |
| |
| IOleClientSite *clientsite; |
| }; |
| |
| static inline struct Package *impl_from_IOleObject(IOleObject *iface) |
| { |
| return CONTAINING_RECORD(iface, struct Package, IOleObject_iface); |
| } |
| |
| static inline struct Package *impl_from_IPersistStorage(IPersistStorage *iface) |
| { |
| return CONTAINING_RECORD(iface, struct Package, IPersistStorage_iface); |
| } |
| |
| static HRESULT WINAPI OleObject_QueryInterface(IOleObject *iface, REFIID riid, void **obj) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| |
| if(IsEqualGUID(riid, &IID_IUnknown) || |
| IsEqualGUID(riid, &IID_IOleObject)) { |
| TRACE("(%p)->(IID_IOleObject, %p)\n", This, obj); |
| *obj = &This->IOleObject_iface; |
| }else if(IsEqualGUID(riid, &IID_IPersistStorage)){ |
| TRACE("(%p)->(IID_IPersistStorage, %p)\n", This, obj); |
| *obj = &This->IPersistStorage_iface; |
| }else { |
| FIXME("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj); |
| *obj = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IUnknown_AddRef((IUnknown*)*obj); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI OleObject_AddRef(IOleObject *iface) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| LONG ref = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p) ref=%d\n", This, ref); |
| |
| return ref; |
| } |
| |
| static ULONG WINAPI OleObject_Release(IOleObject *iface) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| LONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p) ref=%d\n", This, ref); |
| |
| if(!ref){ |
| if(This->clientsite) |
| IOleClientSite_Release(This->clientsite); |
| |
| if(*This->filename) |
| DeleteFileW(This->filename); |
| |
| HeapFree(GetProcessHeap(), 0, This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI OleObject_SetClientSite(IOleObject *iface, IOleClientSite *pClientSite) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| |
| TRACE("(%p)->(%p)\n", This, pClientSite); |
| |
| if(This->clientsite) |
| IOleClientSite_Release(This->clientsite); |
| |
| This->clientsite = pClientSite; |
| if(pClientSite) |
| IOleClientSite_AddRef(pClientSite); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI OleObject_GetClientSite(IOleObject *iface, IOleClientSite **ppClientSite) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%p)\n", This, ppClientSite); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_SetHostNames(IOleObject *iface, LPCOLESTR szContainerApp, LPCOLESTR szContainerObj) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%s, %s)\n", This, debugstr_w(szContainerApp), debugstr_w(szContainerObj)); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_Close(IOleObject *iface, DWORD dwSaveOption) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| |
| TRACE("(%p)->(0x%x)\n", This, dwSaveOption); |
| |
| if(dwSaveOption == OLECLOSE_SAVEIFDIRTY || |
| dwSaveOption == OLECLOSE_PROMPTSAVE) |
| WARN("Saving unsupported\n"); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI OleObject_SetMoniker(IOleObject *iface, DWORD dwWhichMoniker, IMoniker *pmk) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%d, %p)\n", This, dwWhichMoniker, pmk); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_GetMoniker(IOleObject *iface, DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%d, %d, %p)\n", This, dwAssign, dwWhichMoniker, ppmk); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_InitFromData(IOleObject *iface, IDataObject *pDataObject, BOOL fCreation, |
| DWORD dwReserved) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%p, 0x%x, %d)\n", This, pDataObject, fCreation, dwReserved); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_GetClipboardData(IOleObject *iface, DWORD dwReserved, IDataObject **ppDataObject) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%d, %p)\n", This, dwReserved, ppDataObject); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT do_activate_object(struct Package *This, HWND parent) |
| { |
| static const WCHAR openW[] = {'o','p','e','n',0}; |
| ShellExecuteW(parent, openW, This->filename, NULL, NULL, SW_SHOW); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI OleObject_DoVerb(IOleObject *iface, LONG iVerb, LPMSG lpmsg, IOleClientSite *pActiveSite, |
| LONG lindex, HWND hwndParent, LPCRECT lprcPosRect) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| |
| TRACE("(%p)->(%d)\n", This, iVerb); |
| |
| switch(iVerb){ |
| case 0: |
| return do_activate_object(This, hwndParent); |
| } |
| |
| return E_INVALIDARG; |
| } |
| |
| static HRESULT WINAPI OleObject_EnumVerbs(IOleObject *iface, IEnumOLEVERB **ppEnumOleVerb) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%p)\n", This, ppEnumOleVerb); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_Update(IOleObject *iface) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_IsUpToDate(IOleObject *iface) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_GetUserClassID(IOleObject *iface, CLSID *pClsid) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%p)\n", This, pClsid); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_GetUserType(IOleObject *iface, DWORD dwFormOfType, LPOLESTR *pszUserType) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%d, %p)\n", This, dwFormOfType, pszUserType); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_SetExtent(IOleObject *iface, DWORD dwDrawAspect, SIZEL *psizel) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%d, %p)\n", This, dwDrawAspect, psizel); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_GetExtent(IOleObject *iface, DWORD dwDrawAspect, SIZEL *psizel) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%d, %p)\n", This, dwDrawAspect, psizel); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_Advise(IOleObject *iface, IAdviseSink *pAdvSink, DWORD *pdwConnection) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%p, %p)\n", This, pAdvSink, pdwConnection); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_Unadvise(IOleObject *iface, DWORD dwConnection) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%d)\n", This, dwConnection); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_EnumAdvise(IOleObject *iface, IEnumSTATDATA **ppenumAdvise) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%p)\n", This, ppenumAdvise); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI OleObject_GetMiscStatus(IOleObject *iface, DWORD dwAspect, DWORD *pdwStatus) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| |
| TRACE("(%p)->(%d, %p)\n", This, dwAspect, pdwStatus); |
| |
| if(!pdwStatus) |
| return E_INVALIDARG; |
| |
| *pdwStatus = OLEMISC_ONLYICONIC; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI OleObject_SetColorScheme(IOleObject *iface, LOGPALETTE *pLogpal) |
| { |
| struct Package *This = impl_from_IOleObject(iface); |
| FIXME("(%p)->(%p)\n", This, pLogpal); |
| return E_NOTIMPL; |
| } |
| |
| static const IOleObjectVtbl OleObject_Vtbl = { |
| OleObject_QueryInterface, |
| OleObject_AddRef, |
| OleObject_Release, |
| OleObject_SetClientSite, |
| OleObject_GetClientSite, |
| OleObject_SetHostNames, |
| OleObject_Close, |
| OleObject_SetMoniker, |
| OleObject_GetMoniker, |
| OleObject_InitFromData, |
| OleObject_GetClipboardData, |
| OleObject_DoVerb, |
| OleObject_EnumVerbs, |
| OleObject_Update, |
| OleObject_IsUpToDate, |
| OleObject_GetUserClassID, |
| OleObject_GetUserType, |
| OleObject_SetExtent, |
| OleObject_GetExtent, |
| OleObject_Advise, |
| OleObject_Unadvise, |
| OleObject_EnumAdvise, |
| OleObject_GetMiscStatus, |
| OleObject_SetColorScheme |
| }; |
| |
| static HRESULT WINAPI PersistStorage_QueryInterface(IPersistStorage* iface, |
| REFIID riid, void **ppvObject) |
| { |
| struct Package *This = impl_from_IPersistStorage(iface); |
| |
| return OleObject_QueryInterface(&This->IOleObject_iface, riid, ppvObject); |
| } |
| |
| static ULONG WINAPI PersistStorage_AddRef(IPersistStorage* iface) |
| { |
| struct Package *This = impl_from_IPersistStorage(iface); |
| |
| return OleObject_AddRef(&This->IOleObject_iface); |
| } |
| |
| static ULONG WINAPI PersistStorage_Release(IPersistStorage* iface) |
| { |
| struct Package *This = impl_from_IPersistStorage(iface); |
| |
| return OleObject_Release(&This->IOleObject_iface); |
| } |
| |
| static HRESULT WINAPI PersistStorage_GetClassID(IPersistStorage* iface, |
| CLSID *pClassID) |
| { |
| struct Package *This = impl_from_IPersistStorage(iface); |
| FIXME("(%p)->(%p)\n", This, pClassID); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI PersistStorage_IsDirty(IPersistStorage* iface) |
| { |
| struct Package *This = impl_from_IPersistStorage(iface); |
| FIXME("(%p)\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI PersistStorage_InitNew(IPersistStorage* iface, |
| IStorage *pStg) |
| { |
| struct Package *This = impl_from_IPersistStorage(iface); |
| FIXME("(%p)->(%p)\n", This, pStg); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT discard_string(struct Package *This, IStream *stream) |
| { |
| ULONG nbytes; |
| HRESULT hr; |
| char chr = 0; |
| |
| do{ |
| hr = IStream_Read(stream, &chr, 1, &nbytes); |
| if(FAILED(hr) || !nbytes){ |
| TRACE("Unexpected end of stream or Read failed with %08x\n", hr); |
| return (hr == S_OK || hr == S_FALSE) ? E_FAIL : hr; |
| } |
| }while(chr); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI PersistStorage_Load(IPersistStorage* iface, |
| IStorage *pStg) |
| { |
| struct Package *This = impl_from_IPersistStorage(iface); |
| IStream *stream; |
| DWORD payload_size, len, stream_filename_len, filenameA_len, i, bytes_read; |
| ULARGE_INTEGER payload_pos; |
| LARGE_INTEGER seek; |
| HRESULT hr; |
| HANDLE file = INVALID_HANDLE_VALUE; |
| WCHAR filenameW[MAX_PATH]; |
| char filenameA[MAX_PATH]; |
| WCHAR *stream_filename; |
| WCHAR *base_end, extension[MAX_PATH]; |
| |
| static const WCHAR ole10nativeW[] = {0x0001,'O','l','e','1','0','N','a','t','i','v','e',0}; |
| |
| TRACE("(%p)->(%p)\n", This, pStg); |
| |
| hr = IStorage_OpenStream(pStg, ole10nativeW, NULL, |
| STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream); |
| if(FAILED(hr)){ |
| TRACE("OpenStream gave: %08x\n", hr); |
| return hr; |
| } |
| |
| /* skip stream size & two unknown bytes */ |
| seek.QuadPart = 6; |
| hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); |
| if(FAILED(hr)) |
| goto exit; |
| |
| /* read and discard label */ |
| hr = discard_string(This, stream); |
| if(FAILED(hr)) |
| goto exit; |
| |
| /* read and discard filename */ |
| hr = discard_string(This, stream); |
| if(FAILED(hr)) |
| goto exit; |
| |
| /* skip more unknown data */ |
| seek.QuadPart = 4; |
| hr = IStream_Seek(stream, seek, STREAM_SEEK_CUR, NULL); |
| if(FAILED(hr)) |
| goto exit; |
| |
| /* ASCIIZ filename */ |
| hr = IStream_Read(stream, &filenameA_len, 4, NULL); |
| if(FAILED(hr)) |
| goto exit; |
| |
| hr = IStream_Read(stream, filenameA, filenameA_len, NULL); |
| if(FAILED(hr)) |
| goto exit; |
| |
| /* skip payload for now */ |
| hr = IStream_Read(stream, &payload_size, 4, NULL); |
| if(FAILED(hr)) |
| goto exit; |
| |
| seek.QuadPart = 0; |
| hr = IStream_Seek(stream, seek, STREAM_SEEK_CUR, &payload_pos); |
| if(FAILED(hr)) |
| goto exit; |
| |
| seek.QuadPart = payload_size; |
| hr = IStream_Seek(stream, seek, STREAM_SEEK_CUR, NULL); |
| if(FAILED(hr)) |
| goto exit; |
| |
| /* read WCHAR filename, if present */ |
| hr = IStream_Read(stream, &len, 4, &bytes_read); |
| if(SUCCEEDED(hr) && bytes_read == 4 && len > 0){ |
| hr = IStream_Read(stream, filenameW, len * sizeof(WCHAR), NULL); |
| if(FAILED(hr)) |
| goto exit; |
| }else{ |
| len = MultiByteToWideChar(CP_ACP, 0, filenameA, filenameA_len, |
| filenameW, sizeof(filenameW) / sizeof(*filenameW)); |
| } |
| |
| stream_filename = filenameW + len - 1; |
| while(stream_filename != filenameW && |
| *stream_filename != '\\') |
| --stream_filename; |
| if(*stream_filename == '\\') |
| ++stream_filename; |
| stream_filename_len = len - (stream_filename - filenameW); |
| |
| len = GetTempPathW(sizeof(This->filename)/sizeof(WCHAR), This->filename); |
| memcpy(This->filename + len, stream_filename, stream_filename_len * sizeof(WCHAR)); |
| This->filename[len + stream_filename_len] = 0; |
| |
| /* read & write payload */ |
| memcpy(&seek, &payload_pos, sizeof(seek)); /* STREAM_SEEK_SET treats as ULARGE_INTEGER */ |
| hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); |
| if(FAILED(hr)) |
| goto exit; |
| |
| base_end = PathFindExtensionW(This->filename); |
| lstrcpyW(extension, base_end); |
| i = 1; |
| |
| file = CreateFileW(This->filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, |
| CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); |
| while(file == INVALID_HANDLE_VALUE){ |
| static const WCHAR fmtW[] = {' ','(','%','u',')',0}; |
| |
| if(GetLastError() != ERROR_FILE_EXISTS){ |
| WARN("CreateFile failed: %u\n", GetLastError()); |
| hr = E_FAIL; |
| goto exit; |
| } |
| |
| /* file exists, so increment file name and try again */ |
| ++i; |
| wsprintfW(base_end, fmtW, i); |
| lstrcatW(base_end, extension); |
| |
| file = CreateFileW(This->filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, |
| CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); |
| } |
| TRACE("Final filename: %s\n", wine_dbgstr_w(This->filename)); |
| |
| while(payload_size){ |
| ULONG nbytes; |
| BYTE data[4096]; |
| DWORD written; |
| |
| hr = IStream_Read(stream, data, min(sizeof(data), payload_size), &nbytes); |
| if(FAILED(hr) || nbytes == 0){ |
| TRACE("Unexpected end of file, or Read failed with %08x\n", hr); |
| if(hr == S_OK || hr == S_FALSE) |
| hr = E_FAIL; |
| goto exit; |
| } |
| |
| payload_size -= nbytes; |
| |
| WriteFile(file, data, nbytes, &written, NULL); |
| } |
| |
| hr = S_OK; |
| |
| exit: |
| if(file != INVALID_HANDLE_VALUE){ |
| CloseHandle(file); |
| if(FAILED(hr)) |
| DeleteFileW(This->filename); |
| } |
| IStream_Release(stream); |
| |
| TRACE("Returning: %08x\n", hr); |
| return hr; |
| } |
| |
| static HRESULT WINAPI PersistStorage_Save(IPersistStorage* iface, |
| IStorage *pStgSave, BOOL fSameAsLoad) |
| { |
| struct Package *This = impl_from_IPersistStorage(iface); |
| FIXME("(%p)->(%p, %u)\n", This, pStgSave, fSameAsLoad); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI PersistStorage_SaveCompleted(IPersistStorage* iface, |
| IStorage *pStgNew) |
| { |
| struct Package *This = impl_from_IPersistStorage(iface); |
| FIXME("(%p)->(%p)\n", This, pStgNew); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI PersistStorage_HandsOffStorage(IPersistStorage* iface) |
| { |
| struct Package *This = impl_from_IPersistStorage(iface); |
| FIXME("(%p)\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static IPersistStorageVtbl PersistStorage_Vtbl = { |
| PersistStorage_QueryInterface, |
| PersistStorage_AddRef, |
| PersistStorage_Release, |
| PersistStorage_GetClassID, |
| PersistStorage_IsDirty, |
| PersistStorage_InitNew, |
| PersistStorage_Load, |
| PersistStorage_Save, |
| PersistStorage_SaveCompleted, |
| PersistStorage_HandsOffStorage |
| }; |
| |
| static HRESULT WINAPI PackageCF_QueryInterface(IClassFactory *iface, REFIID riid, void **obj) |
| { |
| TRACE("(static)->(%s, %p)\n", debugstr_guid(riid), obj); |
| |
| if(IsEqualGUID(&IID_IUnknown, riid) || |
| IsEqualGUID(&IID_IClassFactory, riid)) |
| *obj = iface; |
| else |
| *obj = NULL; |
| |
| if(*obj){ |
| IUnknown_AddRef((IUnknown*)*obj); |
| return S_OK; |
| } |
| |
| FIXME("Unknown interface: %s\n", debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI PackageCF_AddRef(IClassFactory *iface) |
| { |
| TRACE("(static)\n"); |
| return 2; |
| } |
| |
| static ULONG WINAPI PackageCF_Release(IClassFactory *iface) |
| { |
| TRACE("(static)\n"); |
| return 1; |
| } |
| |
| static HRESULT WINAPI PackageCF_CreateInstance(IClassFactory *iface, IUnknown *outer, |
| REFIID iid, void **obj) |
| { |
| struct Package *package; |
| |
| TRACE("(static)->(%p, %s, %p)\n", outer, wine_dbgstr_guid(iid), obj); |
| |
| package = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*package)); |
| if(!package) |
| return E_OUTOFMEMORY; |
| |
| package->IOleObject_iface.lpVtbl = &OleObject_Vtbl; |
| package->IPersistStorage_iface.lpVtbl = &PersistStorage_Vtbl; |
| |
| return IOleObject_QueryInterface(&package->IOleObject_iface, iid, obj); |
| } |
| |
| static HRESULT WINAPI PackageCF_LockServer(IClassFactory *iface, BOOL fLock) |
| { |
| TRACE("(%p)->(%x)\n", iface, fLock); |
| return S_OK; |
| } |
| |
| static const IClassFactoryVtbl PackageCF_Vtbl = { |
| PackageCF_QueryInterface, |
| PackageCF_AddRef, |
| PackageCF_Release, |
| PackageCF_CreateInstance, |
| PackageCF_LockServer |
| }; |
| |
| static IClassFactory PackageCF = { |
| &PackageCF_Vtbl |
| }; |
| |
| HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **obj) |
| { |
| TRACE("(%s, %s, %p)\n", wine_dbgstr_guid(clsid), wine_dbgstr_guid(iid), obj); |
| |
| if(IsEqualGUID(clsid, &CLSID_Package)) |
| return IClassFactory_QueryInterface(&PackageCF, iid, obj); |
| |
| FIXME("Unknown CLSID: %s\n", wine_dbgstr_guid(clsid)); |
| |
| return CLASS_E_CLASSNOTAVAILABLE; |
| } |
| |
| HRESULT WINAPI DllCanUnloadNow(void) |
| { |
| return S_OK; |
| } |
| |
| HRESULT WINAPI DllRegisterServer(void) |
| { |
| return __wine_register_resources(g_instance); |
| } |
| |
| HRESULT WINAPI DllUnregisterServer(void) |
| { |
| return __wine_unregister_resources(g_instance); |
| } |
| |
| BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) |
| { |
| TRACE("(%p, %u, %p)\n", instance, reason, reserved); |
| |
| switch(reason){ |
| case DLL_PROCESS_ATTACH: |
| g_instance = instance; |
| DisableThreadLibraryCalls(instance); |
| break; |
| } |
| |
| return TRUE; |
| } |