| /* |
| * handling of SHELL32.DLL OLE-Objects |
| * |
| * Copyright 1997 Marcus Meissner |
| * Copyright 1998 Juergen Schmied <juergen.schmied@metronet.de> |
| * |
| * 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> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #define COBJMACROS |
| #define NONAMELESSUNION |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "shellapi.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| #include "shlobj.h" |
| #include "shlguid.h" |
| #include "shldisp.h" |
| #include "gdiplus.h" |
| #include "shimgdata.h" |
| #include "winreg.h" |
| #include "winerror.h" |
| |
| #include "undocshell.h" |
| #include "wine/unicode.h" |
| #include "shell32_main.h" |
| |
| #include "wine/debug.h" |
| #include "shlwapi.h" |
| #include "debughlp.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(shell); |
| |
| extern INT WINAPI SHStringFromGUIDW(REFGUID guid, LPWSTR lpszDest, INT cchMax); /* shlwapi.24 */ |
| static HRESULT WINAPI ShellImageDataFactory_Constructor(IUnknown *outer, REFIID riid, void **obj); |
| |
| /************************************************************************** |
| * Default ClassFactory types |
| */ |
| typedef HRESULT (CALLBACK *LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject); |
| static IClassFactory * IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, REFIID riidInst); |
| |
| /* this table contains all CLSIDs of shell32 objects */ |
| static const struct { |
| REFIID clsid; |
| LPFNCREATEINSTANCE lpfnCI; |
| } InterfaceTable[] = { |
| |
| {&CLSID_ApplicationAssociationRegistration, ApplicationAssociationRegistration_Constructor}, |
| {&CLSID_ApplicationDestinations, ApplicationDestinations_Constructor}, |
| {&CLSID_AutoComplete, IAutoComplete_Constructor}, |
| {&CLSID_ControlPanel, IControlPanel_Constructor}, |
| {&CLSID_DragDropHelper, IDropTargetHelper_Constructor}, |
| {&CLSID_FolderShortcut, FolderShortcut_Constructor}, |
| {&CLSID_MyComputer, ISF_MyComputer_Constructor}, |
| {&CLSID_MyDocuments, MyDocuments_Constructor}, |
| {&CLSID_NetworkPlaces, ISF_NetworkPlaces_Constructor}, |
| {&CLSID_Printers, Printers_Constructor}, |
| {&CLSID_QueryAssociations, QueryAssociations_Constructor}, |
| {&CLSID_RecycleBin, RecycleBin_Constructor}, |
| {&CLSID_ShellDesktop, ISF_Desktop_Constructor}, |
| {&CLSID_ShellFSFolder, IFSFolder_Constructor}, |
| {&CLSID_ShellItem, IShellItem_Constructor}, |
| {&CLSID_ShellLink, IShellLink_Constructor}, |
| {&CLSID_UnixDosFolder, UnixDosFolder_Constructor}, |
| {&CLSID_UnixFolder, UnixFolder_Constructor}, |
| {&CLSID_ExplorerBrowser,ExplorerBrowser_Constructor}, |
| {&CLSID_KnownFolderManager, KnownFolderManager_Constructor}, |
| {&CLSID_Shell, IShellDispatch_Constructor}, |
| {&CLSID_DestinationList, CustomDestinationList_Constructor}, |
| {&CLSID_ShellImageDataFactory, ShellImageDataFactory_Constructor}, |
| {NULL, NULL} |
| }; |
| |
| /************************************************************************* |
| * SHCoCreateInstance [SHELL32.102] |
| * |
| * Equivalent to CoCreateInstance. Under Windows 9x this function could sometimes |
| * use the shell32 built-in "mini-COM" without the need to load ole32.dll - see |
| * SHLoadOLE for details. |
| * |
| * Under wine if a "LoadWithoutCOM" value is present or the object resides in |
| * shell32.dll the function will load the object manually without the help of ole32 |
| * |
| * NOTES |
| * exported by ordinal |
| * |
| * SEE ALSO |
| * CoCreateInstance, SHLoadOLE |
| */ |
| HRESULT WINAPI SHCoCreateInstance( |
| LPCWSTR aclsid, |
| const CLSID *clsid, |
| LPUNKNOWN pUnkOuter, |
| REFIID refiid, |
| LPVOID *ppv) |
| { |
| DWORD hres; |
| IID iid; |
| const CLSID * myclsid = clsid; |
| WCHAR sKeyName[MAX_PATH]; |
| static const WCHAR sCLSID[] = {'C','L','S','I','D','\\','\0'}; |
| WCHAR sClassID[60]; |
| static const WCHAR sInProcServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2','\0'}; |
| static const WCHAR sLoadWithoutCOM[] = {'L','o','a','d','W','i','t','h','o','u','t','C','O','M','\0'}; |
| WCHAR sDllPath[MAX_PATH]; |
| HKEY hKey = 0; |
| DWORD dwSize; |
| IClassFactory * pcf = NULL; |
| |
| if(!ppv) return E_POINTER; |
| *ppv=NULL; |
| |
| /* if the clsid is a string, convert it */ |
| if (!clsid) |
| { |
| if (!aclsid) return REGDB_E_CLASSNOTREG; |
| SHCLSIDFromStringW(aclsid, &iid); |
| myclsid = &iid; |
| } |
| |
| TRACE("(%p,%s,unk:%p,%s,%p)\n", |
| aclsid,shdebugstr_guid(myclsid),pUnkOuter,shdebugstr_guid(refiid),ppv); |
| |
| if (SUCCEEDED(DllGetClassObject(myclsid, &IID_IClassFactory,(LPVOID*)&pcf))) |
| { |
| hres = IClassFactory_CreateInstance(pcf, pUnkOuter, refiid, ppv); |
| IClassFactory_Release(pcf); |
| goto end; |
| } |
| |
| /* we look up the dll path in the registry */ |
| SHStringFromGUIDW(myclsid, sClassID, sizeof(sClassID)/sizeof(WCHAR)); |
| lstrcpyW(sKeyName, sCLSID); |
| lstrcatW(sKeyName, sClassID); |
| lstrcatW(sKeyName, sInProcServer32); |
| |
| if (RegOpenKeyExW(HKEY_CLASSES_ROOT, sKeyName, 0, KEY_READ, &hKey)) |
| return E_ACCESSDENIED; |
| |
| /* if a special registry key is set, we load a shell extension without help of OLE32 */ |
| if (!SHQueryValueExW(hKey, sLoadWithoutCOM, 0, 0, 0, 0)) |
| { |
| /* load an external dll without ole32 */ |
| HANDLE hLibrary; |
| typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv); |
| DllGetClassObjectFunc DllGetClassObject; |
| |
| dwSize = sizeof(sDllPath); |
| SHQueryValueExW(hKey, NULL, 0,0, sDllPath, &dwSize ); |
| |
| if ((hLibrary = LoadLibraryExW(sDllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) { |
| ERR("couldn't load InprocServer32 dll %s\n", debugstr_w(sDllPath)); |
| hres = E_ACCESSDENIED; |
| goto end; |
| } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) { |
| ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(sDllPath)); |
| FreeLibrary( hLibrary ); |
| hres = E_ACCESSDENIED; |
| goto end; |
| } else if (FAILED(hres = DllGetClassObject(myclsid, &IID_IClassFactory, (LPVOID*)&pcf))) { |
| TRACE("GetClassObject failed 0x%08x\n", hres); |
| goto end; |
| } |
| |
| hres = IClassFactory_CreateInstance(pcf, pUnkOuter, refiid, ppv); |
| IClassFactory_Release(pcf); |
| } else { |
| |
| /* load an external dll in the usual way */ |
| hres = CoCreateInstance(myclsid, pUnkOuter, CLSCTX_INPROC_SERVER, refiid, ppv); |
| } |
| |
| end: |
| if (hKey) RegCloseKey(hKey); |
| if(hres!=S_OK) |
| { |
| ERR("failed (0x%08x) to create CLSID:%s IID:%s\n", |
| hres, shdebugstr_guid(myclsid), shdebugstr_guid(refiid)); |
| ERR("class not found in registry\n"); |
| } |
| |
| TRACE("-- instance: %p\n",*ppv); |
| return hres; |
| } |
| |
| /************************************************************************* |
| * DllGetClassObject [SHELL32.@] |
| * SHDllGetClassObject [SHELL32.128] |
| */ |
| HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) |
| { |
| IClassFactory * pcf = NULL; |
| HRESULT hres; |
| int i; |
| |
| TRACE("CLSID:%s,IID:%s\n",shdebugstr_guid(rclsid),shdebugstr_guid(iid)); |
| |
| if (!ppv) return E_INVALIDARG; |
| *ppv = NULL; |
| |
| /* search our internal interface table */ |
| for(i=0;InterfaceTable[i].clsid;i++) { |
| if(IsEqualIID(InterfaceTable[i].clsid, rclsid)) { |
| TRACE("index[%u]\n", i); |
| pcf = IDefClF_fnConstructor(InterfaceTable[i].lpfnCI, NULL, NULL); |
| break; |
| } |
| } |
| |
| if (!pcf) { |
| FIXME("failed for CLSID=%s\n", shdebugstr_guid(rclsid)); |
| return CLASS_E_CLASSNOTAVAILABLE; |
| } |
| |
| hres = IClassFactory_QueryInterface(pcf, iid, ppv); |
| IClassFactory_Release(pcf); |
| |
| TRACE("-- pointer to class factory: %p\n",*ppv); |
| return hres; |
| } |
| |
| /************************************************************************* |
| * SHCLSIDFromString [SHELL32.147] |
| * |
| * Under Windows 9x this was an ANSI version of CLSIDFromString. It also allowed |
| * to avoid dependency on ole32.dll (see SHLoadOLE for details). |
| * |
| * Under Windows NT/2000/XP this is equivalent to CLSIDFromString |
| * |
| * NOTES |
| * exported by ordinal |
| * |
| * SEE ALSO |
| * CLSIDFromString, SHLoadOLE |
| */ |
| DWORD WINAPI SHCLSIDFromStringA (LPCSTR clsid, CLSID *id) |
| { |
| WCHAR buffer[40]; |
| TRACE("(%p(%s) %p)\n", clsid, clsid, id); |
| if (!MultiByteToWideChar( CP_ACP, 0, clsid, -1, buffer, sizeof(buffer)/sizeof(WCHAR) )) |
| return CO_E_CLASSSTRING; |
| return CLSIDFromString( buffer, id ); |
| } |
| DWORD WINAPI SHCLSIDFromStringW (LPCWSTR clsid, CLSID *id) |
| { |
| TRACE("(%p(%s) %p)\n", clsid, debugstr_w(clsid), id); |
| return CLSIDFromString(clsid, id); |
| } |
| DWORD WINAPI SHCLSIDFromStringAW (LPCVOID clsid, CLSID *id) |
| { |
| if (SHELL_OsIsUnicode()) |
| return SHCLSIDFromStringW (clsid, id); |
| return SHCLSIDFromStringA (clsid, id); |
| } |
| |
| /************************************************************************* |
| * SHGetMalloc [SHELL32.@] |
| * |
| * Equivalent to CoGetMalloc(MEMCTX_TASK, ...). Under Windows 9x this function |
| * could use the shell32 built-in "mini-COM" without the need to load ole32.dll - |
| * see SHLoadOLE for details. |
| * |
| * PARAMS |
| * lpmal [O] Destination for IMalloc interface. |
| * |
| * RETURNS |
| * Success: S_OK. lpmal contains the shells IMalloc interface. |
| * Failure. An HRESULT error code. |
| * |
| * SEE ALSO |
| * CoGetMalloc, SHLoadOLE |
| */ |
| HRESULT WINAPI SHGetMalloc(LPMALLOC *lpmal) |
| { |
| TRACE("(%p)\n", lpmal); |
| return CoGetMalloc(MEMCTX_TASK, lpmal); |
| } |
| |
| /************************************************************************* |
| * SHAlloc [SHELL32.196] |
| * |
| * Equivalent to CoTaskMemAlloc. Under Windows 9x this function could use |
| * the shell32 built-in "mini-COM" without the need to load ole32.dll - |
| * see SHLoadOLE for details. |
| * |
| * NOTES |
| * exported by ordinal |
| * |
| * SEE ALSO |
| * CoTaskMemAlloc, SHLoadOLE |
| */ |
| LPVOID WINAPI SHAlloc(DWORD len) |
| { |
| LPVOID ret; |
| |
| ret = CoTaskMemAlloc(len); |
| TRACE("%u bytes at %p\n",len, ret); |
| return ret; |
| } |
| |
| /************************************************************************* |
| * SHFree [SHELL32.195] |
| * |
| * Equivalent to CoTaskMemFree. Under Windows 9x this function could use |
| * the shell32 built-in "mini-COM" without the need to load ole32.dll - |
| * see SHLoadOLE for details. |
| * |
| * NOTES |
| * exported by ordinal |
| * |
| * SEE ALSO |
| * CoTaskMemFree, SHLoadOLE |
| */ |
| void WINAPI SHFree(LPVOID pv) |
| { |
| TRACE("%p\n",pv); |
| CoTaskMemFree(pv); |
| } |
| |
| /************************************************************************* |
| * SHGetDesktopFolder [SHELL32.@] |
| */ |
| HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf) |
| { |
| HRESULT hres; |
| |
| TRACE("(%p)\n", psf); |
| |
| if(!psf) return E_INVALIDARG; |
| |
| *psf = NULL; |
| hres = ISF_Desktop_Constructor(NULL, &IID_IShellFolder, (LPVOID*)psf); |
| |
| TRACE("-- %p->(%p) 0x%08x\n", psf, *psf, hres); |
| return hres; |
| } |
| /************************************************************************** |
| * Default ClassFactory Implementation |
| * |
| * SHCreateDefClassObject |
| * |
| * NOTES |
| * Helper function for dlls without their own classfactory. |
| * A generic classfactory is returned. |
| * When the CreateInstance of the cf is called the callback is executed. |
| */ |
| |
| typedef struct |
| { |
| IClassFactory IClassFactory_iface; |
| LONG ref; |
| CLSID *rclsid; |
| LPFNCREATEINSTANCE lpfnCI; |
| const IID * riidInst; |
| LONG * pcRefDll; /* pointer to refcounter in external dll (ugrrr...) */ |
| } IDefClFImpl; |
| |
| static inline IDefClFImpl *impl_from_IClassFactory(IClassFactory *iface) |
| { |
| return CONTAINING_RECORD(iface, IDefClFImpl, IClassFactory_iface); |
| } |
| |
| static const IClassFactoryVtbl dclfvt; |
| |
| /************************************************************************** |
| * IDefClF_fnConstructor |
| */ |
| |
| static IClassFactory * IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, REFIID riidInst) |
| { |
| IDefClFImpl* lpclf; |
| |
| lpclf = HeapAlloc(GetProcessHeap(),0,sizeof(IDefClFImpl)); |
| lpclf->ref = 1; |
| lpclf->IClassFactory_iface.lpVtbl = &dclfvt; |
| lpclf->lpfnCI = lpfnCI; |
| lpclf->pcRefDll = pcRefDll; |
| |
| if (pcRefDll) InterlockedIncrement(pcRefDll); |
| lpclf->riidInst = riidInst; |
| |
| TRACE("(%p)%s\n",lpclf, shdebugstr_guid(riidInst)); |
| return (LPCLASSFACTORY)lpclf; |
| } |
| /************************************************************************** |
| * IDefClF_fnQueryInterface |
| */ |
| static HRESULT WINAPI IDefClF_fnQueryInterface( |
| LPCLASSFACTORY iface, REFIID riid, LPVOID *ppvObj) |
| { |
| IDefClFImpl *This = impl_from_IClassFactory(iface); |
| |
| TRACE("(%p)->(%s)\n",This,shdebugstr_guid(riid)); |
| |
| *ppvObj = NULL; |
| |
| if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) { |
| *ppvObj = This; |
| InterlockedIncrement(&This->ref); |
| return S_OK; |
| } |
| |
| TRACE("-- E_NOINTERFACE\n"); |
| return E_NOINTERFACE; |
| } |
| /****************************************************************************** |
| * IDefClF_fnAddRef |
| */ |
| static ULONG WINAPI IDefClF_fnAddRef(LPCLASSFACTORY iface) |
| { |
| IDefClFImpl *This = impl_from_IClassFactory(iface); |
| ULONG refCount = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p)->(count=%u)\n", This, refCount - 1); |
| |
| return refCount; |
| } |
| /****************************************************************************** |
| * IDefClF_fnRelease |
| */ |
| static ULONG WINAPI IDefClF_fnRelease(LPCLASSFACTORY iface) |
| { |
| IDefClFImpl *This = impl_from_IClassFactory(iface); |
| ULONG refCount = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p)->(count=%u)\n", This, refCount + 1); |
| |
| if (!refCount) |
| { |
| if (This->pcRefDll) InterlockedDecrement(This->pcRefDll); |
| |
| TRACE("-- destroying IClassFactory(%p)\n",This); |
| HeapFree(GetProcessHeap(),0,This); |
| return 0; |
| } |
| return refCount; |
| } |
| /****************************************************************************** |
| * IDefClF_fnCreateInstance |
| */ |
| static HRESULT WINAPI IDefClF_fnCreateInstance( |
| LPCLASSFACTORY iface, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject) |
| { |
| IDefClFImpl *This = impl_from_IClassFactory(iface); |
| |
| TRACE("%p->(%p,%s,%p)\n",This,pUnkOuter,shdebugstr_guid(riid),ppvObject); |
| |
| *ppvObject = NULL; |
| |
| if ( This->riidInst==NULL || |
| IsEqualCLSID(riid, This->riidInst) || |
| IsEqualCLSID(riid, &IID_IUnknown) ) |
| { |
| return This->lpfnCI(pUnkOuter, riid, ppvObject); |
| } |
| |
| ERR("unknown IID requested %s\n",shdebugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| /****************************************************************************** |
| * IDefClF_fnLockServer |
| */ |
| static HRESULT WINAPI IDefClF_fnLockServer(LPCLASSFACTORY iface, BOOL fLock) |
| { |
| IDefClFImpl *This = impl_from_IClassFactory(iface); |
| TRACE("%p->(0x%x), not implemented\n",This, fLock); |
| return E_NOTIMPL; |
| } |
| |
| static const IClassFactoryVtbl dclfvt = |
| { |
| IDefClF_fnQueryInterface, |
| IDefClF_fnAddRef, |
| IDefClF_fnRelease, |
| IDefClF_fnCreateInstance, |
| IDefClF_fnLockServer |
| }; |
| |
| /****************************************************************************** |
| * SHCreateDefClassObject [SHELL32.70] |
| */ |
| HRESULT WINAPI SHCreateDefClassObject( |
| REFIID riid, |
| LPVOID* ppv, |
| LPFNCREATEINSTANCE lpfnCI, /* [in] create instance callback entry */ |
| LPDWORD pcRefDll, /* [in/out] ref count of the dll */ |
| REFIID riidInst) /* [in] optional interface to the instance */ |
| { |
| IClassFactory * pcf; |
| |
| TRACE("%s %p %p %p %s\n", |
| shdebugstr_guid(riid), ppv, lpfnCI, pcRefDll, shdebugstr_guid(riidInst)); |
| |
| if (! IsEqualCLSID(riid, &IID_IClassFactory) ) return E_NOINTERFACE; |
| if (! (pcf = IDefClF_fnConstructor(lpfnCI, (PLONG)pcRefDll, riidInst))) return E_OUTOFMEMORY; |
| *ppv = pcf; |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * DragAcceptFiles [SHELL32.@] |
| */ |
| void WINAPI DragAcceptFiles(HWND hWnd, BOOL b) |
| { |
| LONG exstyle; |
| |
| if( !IsWindow(hWnd) ) return; |
| exstyle = GetWindowLongA(hWnd,GWL_EXSTYLE); |
| if (b) |
| exstyle |= WS_EX_ACCEPTFILES; |
| else |
| exstyle &= ~WS_EX_ACCEPTFILES; |
| SetWindowLongA(hWnd,GWL_EXSTYLE,exstyle); |
| } |
| |
| /************************************************************************* |
| * DragFinish [SHELL32.@] |
| */ |
| void WINAPI DragFinish(HDROP h) |
| { |
| TRACE("\n"); |
| GlobalFree(h); |
| } |
| |
| /************************************************************************* |
| * DragQueryPoint [SHELL32.@] |
| */ |
| BOOL WINAPI DragQueryPoint(HDROP hDrop, POINT *p) |
| { |
| DROPFILES *lpDropFileStruct; |
| BOOL bRet; |
| |
| TRACE("\n"); |
| |
| lpDropFileStruct = GlobalLock(hDrop); |
| |
| *p = lpDropFileStruct->pt; |
| bRet = lpDropFileStruct->fNC; |
| |
| GlobalUnlock(hDrop); |
| return bRet; |
| } |
| |
| /************************************************************************* |
| * DragQueryFileA [SHELL32.@] |
| * DragQueryFile [SHELL32.@] |
| */ |
| UINT WINAPI DragQueryFileA( |
| HDROP hDrop, |
| UINT lFile, |
| LPSTR lpszFile, |
| UINT lLength) |
| { |
| LPSTR lpDrop; |
| UINT i = 0; |
| DROPFILES *lpDropFileStruct = GlobalLock(hDrop); |
| |
| TRACE("(%p, %x, %p, %u)\n", hDrop,lFile,lpszFile,lLength); |
| |
| if(!lpDropFileStruct) goto end; |
| |
| lpDrop = (LPSTR) lpDropFileStruct + lpDropFileStruct->pFiles; |
| |
| if(lpDropFileStruct->fWide) { |
| LPWSTR lpszFileW = NULL; |
| |
| if(lpszFile && lFile != 0xFFFFFFFF) { |
| lpszFileW = HeapAlloc(GetProcessHeap(), 0, lLength*sizeof(WCHAR)); |
| if(lpszFileW == NULL) { |
| goto end; |
| } |
| } |
| i = DragQueryFileW(hDrop, lFile, lpszFileW, lLength); |
| |
| if(lpszFileW) { |
| WideCharToMultiByte(CP_ACP, 0, lpszFileW, -1, lpszFile, lLength, 0, NULL); |
| HeapFree(GetProcessHeap(), 0, lpszFileW); |
| } |
| goto end; |
| } |
| |
| while (i++ < lFile) |
| { |
| while (*lpDrop++); /* skip filename */ |
| if (!*lpDrop) |
| { |
| i = (lFile == 0xFFFFFFFF) ? i : 0; |
| goto end; |
| } |
| } |
| |
| i = strlen(lpDrop); |
| if (!lpszFile ) goto end; /* needed buffer size */ |
| lstrcpynA (lpszFile, lpDrop, lLength); |
| end: |
| GlobalUnlock(hDrop); |
| return i; |
| } |
| |
| /************************************************************************* |
| * DragQueryFileW [SHELL32.@] |
| */ |
| UINT WINAPI DragQueryFileW( |
| HDROP hDrop, |
| UINT lFile, |
| LPWSTR lpszwFile, |
| UINT lLength) |
| { |
| LPWSTR lpwDrop; |
| UINT i = 0; |
| DROPFILES *lpDropFileStruct = GlobalLock(hDrop); |
| |
| TRACE("(%p, %x, %p, %u)\n", hDrop,lFile,lpszwFile,lLength); |
| |
| if(!lpDropFileStruct) goto end; |
| |
| lpwDrop = (LPWSTR) ((LPSTR)lpDropFileStruct + lpDropFileStruct->pFiles); |
| |
| if(lpDropFileStruct->fWide == FALSE) { |
| LPSTR lpszFileA = NULL; |
| |
| if(lpszwFile && lFile != 0xFFFFFFFF) { |
| lpszFileA = HeapAlloc(GetProcessHeap(), 0, lLength); |
| if(lpszFileA == NULL) { |
| goto end; |
| } |
| } |
| i = DragQueryFileA(hDrop, lFile, lpszFileA, lLength); |
| |
| if(lpszFileA) { |
| MultiByteToWideChar(CP_ACP, 0, lpszFileA, -1, lpszwFile, lLength); |
| HeapFree(GetProcessHeap(), 0, lpszFileA); |
| } |
| goto end; |
| } |
| |
| i = 0; |
| while (i++ < lFile) |
| { |
| while (*lpwDrop++); /* skip filename */ |
| if (!*lpwDrop) |
| { |
| i = (lFile == 0xFFFFFFFF) ? i : 0; |
| goto end; |
| } |
| } |
| |
| i = strlenW(lpwDrop); |
| if ( !lpszwFile) goto end; /* needed buffer size */ |
| lstrcpynW (lpszwFile, lpwDrop, lLength); |
| end: |
| GlobalUnlock(hDrop); |
| return i; |
| } |
| |
| /************************************************************************* |
| * SHPropStgCreate [SHELL32.685] |
| */ |
| HRESULT WINAPI SHPropStgCreate(IPropertySetStorage *psstg, REFFMTID fmtid, |
| const CLSID *pclsid, DWORD grfFlags, DWORD grfMode, |
| DWORD dwDisposition, IPropertyStorage **ppstg, UINT *puCodePage) |
| { |
| PROPSPEC prop; |
| PROPVARIANT ret; |
| HRESULT hres; |
| |
| TRACE("%p %s %s %x %x %x %p %p\n", psstg, debugstr_guid(fmtid), debugstr_guid(pclsid), |
| grfFlags, grfMode, dwDisposition, ppstg, puCodePage); |
| |
| hres = IPropertySetStorage_Open(psstg, fmtid, grfMode, ppstg); |
| |
| switch(dwDisposition) { |
| case CREATE_ALWAYS: |
| if(SUCCEEDED(hres)) { |
| IPropertyStorage_Release(*ppstg); |
| hres = IPropertySetStorage_Delete(psstg, fmtid); |
| if(FAILED(hres)) |
| return hres; |
| hres = E_FAIL; |
| } |
| |
| case OPEN_ALWAYS: |
| case CREATE_NEW: |
| if(FAILED(hres)) |
| hres = IPropertySetStorage_Create(psstg, fmtid, pclsid, |
| grfFlags, grfMode, ppstg); |
| |
| case OPEN_EXISTING: |
| if(FAILED(hres)) |
| return hres; |
| |
| if(puCodePage) { |
| prop.ulKind = PRSPEC_PROPID; |
| prop.u.propid = PID_CODEPAGE; |
| hres = IPropertyStorage_ReadMultiple(*ppstg, 1, &prop, &ret); |
| if(FAILED(hres) || ret.vt!=VT_I2) |
| *puCodePage = 0; |
| else |
| *puCodePage = ret.u.iVal; |
| } |
| } |
| |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * SHPropStgReadMultiple [SHELL32.688] |
| */ |
| HRESULT WINAPI SHPropStgReadMultiple(IPropertyStorage *pps, UINT uCodePage, |
| ULONG cpspec, const PROPSPEC *rgpspec, PROPVARIANT *rgvar) |
| { |
| STATPROPSETSTG stat; |
| HRESULT hres; |
| |
| FIXME("%p %u %u %p %p\n", pps, uCodePage, cpspec, rgpspec, rgvar); |
| |
| memset(rgvar, 0, cpspec*sizeof(PROPVARIANT)); |
| hres = IPropertyStorage_ReadMultiple(pps, cpspec, rgpspec, rgvar); |
| if(FAILED(hres)) |
| return hres; |
| |
| if(!uCodePage) { |
| PROPSPEC prop; |
| PROPVARIANT ret; |
| |
| prop.ulKind = PRSPEC_PROPID; |
| prop.u.propid = PID_CODEPAGE; |
| hres = IPropertyStorage_ReadMultiple(pps, 1, &prop, &ret); |
| if(FAILED(hres) || ret.vt!=VT_I2) |
| return S_OK; |
| |
| uCodePage = ret.u.iVal; |
| } |
| |
| hres = IPropertyStorage_Stat(pps, &stat); |
| if(FAILED(hres)) |
| return S_OK; |
| |
| /* TODO: do something with codepage and stat */ |
| return S_OK; |
| } |
| |
| /************************************************************************* |
| * SHPropStgWriteMultiple [SHELL32.689] |
| */ |
| HRESULT WINAPI SHPropStgWriteMultiple(IPropertyStorage *pps, UINT *uCodePage, |
| ULONG cpspec, const PROPSPEC *rgpspec, PROPVARIANT *rgvar, PROPID propidNameFirst) |
| { |
| STATPROPSETSTG stat; |
| UINT codepage; |
| HRESULT hres; |
| |
| FIXME("%p %p %u %p %p %d\n", pps, uCodePage, cpspec, rgpspec, rgvar, propidNameFirst); |
| |
| hres = IPropertyStorage_Stat(pps, &stat); |
| if(FAILED(hres)) |
| return hres; |
| |
| if(uCodePage && *uCodePage) |
| codepage = *uCodePage; |
| else { |
| PROPSPEC prop; |
| PROPVARIANT ret; |
| |
| prop.ulKind = PRSPEC_PROPID; |
| prop.u.propid = PID_CODEPAGE; |
| hres = IPropertyStorage_ReadMultiple(pps, 1, &prop, &ret); |
| if(FAILED(hres)) |
| return hres; |
| if(ret.vt!=VT_I2 || !ret.u.iVal) |
| return E_FAIL; |
| |
| codepage = ret.u.iVal; |
| if(uCodePage) |
| *uCodePage = codepage; |
| } |
| |
| /* TODO: do something with codepage and stat */ |
| |
| hres = IPropertyStorage_WriteMultiple(pps, cpspec, rgpspec, rgvar, propidNameFirst); |
| return hres; |
| } |
| |
| /************************************************************************* |
| * SHCreateQueryCancelAutoPlayMoniker [SHELL32.@] |
| */ |
| HRESULT WINAPI SHCreateQueryCancelAutoPlayMoniker(IMoniker **moniker) |
| { |
| TRACE("%p\n", moniker); |
| |
| if (!moniker) return E_INVALIDARG; |
| return CreateClassMoniker(&CLSID_QueryCancelAutoPlay, moniker); |
| } |
| |
| static HRESULT gpstatus_to_hresult(GpStatus status) |
| { |
| switch (status) |
| { |
| case Ok: |
| return S_OK; |
| case InvalidParameter: |
| return E_INVALIDARG; |
| case OutOfMemory: |
| return E_OUTOFMEMORY; |
| case NotImplemented: |
| return E_NOTIMPL; |
| default: |
| return E_FAIL; |
| } |
| } |
| |
| /* IShellImageData */ |
| typedef struct |
| { |
| IShellImageData IShellImageData_iface; |
| LONG ref; |
| |
| WCHAR *path; |
| GpImage *image; |
| } ShellImageData; |
| |
| static inline ShellImageData *impl_from_IShellImageData(IShellImageData *iface) |
| { |
| return CONTAINING_RECORD(iface, ShellImageData, IShellImageData_iface); |
| } |
| |
| static HRESULT WINAPI ShellImageData_QueryInterface(IShellImageData *iface, REFIID riid, void **obj) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| TRACE("%p, %s, %p\n", This, debugstr_guid(riid), obj); |
| |
| if (IsEqualIID(riid, &IID_IShellImageData) || IsEqualIID(riid, &IID_IUnknown)) |
| { |
| *obj = &This->IShellImageData_iface; |
| IShellImageData_AddRef(iface); |
| return S_OK; |
| } |
| |
| *obj = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI ShellImageData_AddRef(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| ULONG ref = InterlockedIncrement(&This->ref); |
| |
| TRACE("%p, %u\n", This, ref); |
| |
| return ref; |
| } |
| |
| static ULONG WINAPI ShellImageData_Release(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("%p, %u\n", This, ref); |
| |
| if (!ref) |
| { |
| GdipDisposeImage(This->image); |
| HeapFree(GetProcessHeap(), 0, This->path); |
| SHFree(This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI ShellImageData_Decode(IShellImageData *iface, DWORD flags, ULONG cx_desired, ULONG cy_desired) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| GpImage *image; |
| HRESULT hr; |
| |
| TRACE("%p, %#x, %u, %u\n", This, flags, cx_desired, cy_desired); |
| |
| if (This->image) |
| return S_FALSE; |
| |
| if (flags & SHIMGDEC_LOADFULL) |
| FIXME("LOADFULL flag ignored\n"); |
| |
| hr = gpstatus_to_hresult(GdipLoadImageFromFile(This->path, &image)); |
| if (FAILED(hr)) |
| return hr; |
| |
| if (flags & SHIMGDEC_THUMBNAIL) |
| { |
| hr = gpstatus_to_hresult(GdipGetImageThumbnail(image, cx_desired, cy_desired, &This->image, NULL, NULL)); |
| GdipDisposeImage(image); |
| } |
| else |
| This->image = image; |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI ShellImageData_Draw(IShellImageData *iface, HDC hdc, RECT *dest, RECT *src) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| GpGraphics *graphics; |
| HRESULT hr; |
| |
| TRACE("%p, %p, %s, %s\n", This, hdc, wine_dbgstr_rect(dest), wine_dbgstr_rect(src)); |
| |
| if (!This->image) |
| return E_FAIL; |
| |
| if (!dest) |
| return E_INVALIDARG; |
| |
| if (!src) |
| return S_OK; |
| |
| hr = gpstatus_to_hresult(GdipCreateFromHDC(hdc, &graphics)); |
| if (FAILED(hr)) |
| return hr; |
| |
| hr = gpstatus_to_hresult(GdipDrawImageRectRectI(graphics, This->image, dest->left, dest->top, dest->right - dest->left, |
| dest->bottom - dest->top, src->left, src->top, src->right - src->left, src->bottom - src->top, |
| UnitPixel, NULL, NULL, NULL)); |
| GdipDeleteGraphics(graphics); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI ShellImageData_NextFrame(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p: stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_NextPage(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p: stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_PrevPage(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p: stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_IsTransparent(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p: stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_IsAnimated(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p: stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_IsVector(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p: stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_IsMultipage(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p: stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_IsEditable(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p: stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_IsPrintable(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p: stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_IsDecoded(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p: stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_GetCurrentPage(IShellImageData *iface, ULONG *page) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p: stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_GetPageCount(IShellImageData *iface, ULONG *count) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %p: stub\n", This, count); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageDate_SelectPage(IShellImageData *iface, ULONG page) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %u: stub\n", This, page); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_GetSize(IShellImageData *iface, SIZE *size) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| REAL cx, cy; |
| HRESULT hr; |
| |
| TRACE("%p, %p\n", This, size); |
| |
| if (!This->image) |
| return E_FAIL; |
| |
| hr = gpstatus_to_hresult(GdipGetImageDimension(This->image, &cx, &cy)); |
| if (SUCCEEDED(hr)) |
| { |
| size->cx = cx; |
| size->cy = cy; |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI ShellImageData_GetRawDataFormat(IShellImageData *iface, GUID *format) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %p: stub\n", This, format); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_GetPixelFormat(IShellImageData *iface, PixelFormat *format) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %p: stub\n", This, format); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_GetDelay(IShellImageData *iface, DWORD *delay) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %p: stub\n", This, delay); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_GetProperties(IShellImageData *iface, DWORD mode, IPropertySetStorage **props) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %#x, %p: stub\n", This, mode, props); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_Rotate(IShellImageData *iface, DWORD angle) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %u: stub\n", This, angle); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_Scale(IShellImageData *iface, ULONG cx, ULONG cy, InterpolationMode mode) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %u, %u, %#x: stub\n", This, cx, cy, mode); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_DiscardEdit(IShellImageData *iface) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p: stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageDate_SetEncoderParams(IShellImageData *iface, IPropertyBag *params) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %p: stub\n", This, params); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_DisplayName(IShellImageData *iface, LPWSTR name, UINT count) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %p, %u: stub\n", This, name, count); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_GetResolution(IShellImageData *iface, ULONG *res_x, ULONG *res_y) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %p, %p: stub\n", This, res_x, res_y); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_GetEncoderParams(IShellImageData *iface, GUID *format, EncoderParameters **params) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %p, %p: stub\n", This, format, params); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_RegisterAbort(IShellImageData *iface, IShellImageDataAbort *abort, |
| IShellImageDataAbort **prev) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %p, %p: stub\n", This, abort, prev); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_CloneFrame(IShellImageData *iface, Image **frame) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %p: stub\n", This, frame); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageData_ReplaceFrame(IShellImageData *iface, Image *frame) |
| { |
| ShellImageData *This = impl_from_IShellImageData(iface); |
| |
| FIXME("%p, %p: stub\n", This, frame); |
| |
| return E_NOTIMPL; |
| } |
| |
| static const IShellImageDataVtbl ShellImageDataVtbl = |
| { |
| ShellImageData_QueryInterface, |
| ShellImageData_AddRef, |
| ShellImageData_Release, |
| ShellImageData_Decode, |
| ShellImageData_Draw, |
| ShellImageData_NextFrame, |
| ShellImageData_NextPage, |
| ShellImageData_PrevPage, |
| ShellImageData_IsTransparent, |
| ShellImageData_IsAnimated, |
| ShellImageData_IsVector, |
| ShellImageData_IsMultipage, |
| ShellImageData_IsEditable, |
| ShellImageData_IsPrintable, |
| ShellImageData_IsDecoded, |
| ShellImageData_GetCurrentPage, |
| ShellImageData_GetPageCount, |
| ShellImageDate_SelectPage, |
| ShellImageData_GetSize, |
| ShellImageData_GetRawDataFormat, |
| ShellImageData_GetPixelFormat, |
| ShellImageData_GetDelay, |
| ShellImageData_GetProperties, |
| ShellImageData_Rotate, |
| ShellImageData_Scale, |
| ShellImageData_DiscardEdit, |
| ShellImageDate_SetEncoderParams, |
| ShellImageData_DisplayName, |
| ShellImageData_GetResolution, |
| ShellImageData_GetEncoderParams, |
| ShellImageData_RegisterAbort, |
| ShellImageData_CloneFrame, |
| ShellImageData_ReplaceFrame, |
| }; |
| |
| static HRESULT create_shellimagedata_from_path(const WCHAR *path, IShellImageData **data) |
| { |
| ShellImageData *This; |
| |
| This = SHAlloc(sizeof(*This)); |
| |
| This->IShellImageData_iface.lpVtbl = &ShellImageDataVtbl; |
| This->ref = 1; |
| |
| This->path = strdupW(path); |
| This->image = NULL; |
| |
| *data = &This->IShellImageData_iface; |
| return S_OK; |
| } |
| |
| /* IShellImageDataFactory */ |
| static HRESULT WINAPI ShellImageDataFactory_QueryInterface(IShellImageDataFactory *iface, REFIID riid, void **obj) |
| { |
| TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), obj); |
| |
| if (IsEqualIID(&IID_IShellImageDataFactory, riid) || IsEqualIID(&IID_IUnknown, riid)) |
| { |
| *obj = iface; |
| } |
| else |
| { |
| FIXME("not implemented for %s\n", debugstr_guid(riid)); |
| *obj = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IUnknown_AddRef((IUnknown*)*obj); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI ShellImageDataFactory_AddRef(IShellImageDataFactory *iface) |
| { |
| TRACE("(%p)\n", iface); |
| |
| return 2; |
| } |
| |
| static ULONG WINAPI ShellImageDataFactory_Release(IShellImageDataFactory *iface) |
| { |
| TRACE("(%p)\n", iface); |
| |
| return 1; |
| } |
| |
| static HRESULT WINAPI ShellImageDataFactory_CreateIShellImageData(IShellImageDataFactory *iface, IShellImageData **data) |
| { |
| FIXME("%p, %p: stub\n", iface, data); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageDataFactory_CreateImageFromFile(IShellImageDataFactory *iface, const WCHAR *path, |
| IShellImageData **data) |
| { |
| TRACE("%p, %s, %p\n", iface, debugstr_w(path), data); |
| |
| return create_shellimagedata_from_path(path, data); |
| } |
| |
| static HRESULT WINAPI ShellImageDataFactory_CreateImageFromStream(IShellImageDataFactory *iface, IStream *stream, |
| IShellImageData **data) |
| { |
| FIXME("%p, %p, %p: stub\n", iface, stream, data); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellImageDataFactory_GetDataFormatFromPath(IShellImageDataFactory *iface, const WCHAR *path, |
| GUID *format) |
| { |
| FIXME("%p, %s, %p: stub\n", iface, debugstr_w(path), format); |
| |
| return E_NOTIMPL; |
| } |
| |
| static const IShellImageDataFactoryVtbl ShellImageDataFactoryVtbl = |
| { |
| ShellImageDataFactory_QueryInterface, |
| ShellImageDataFactory_AddRef, |
| ShellImageDataFactory_Release, |
| ShellImageDataFactory_CreateIShellImageData, |
| ShellImageDataFactory_CreateImageFromFile, |
| ShellImageDataFactory_CreateImageFromStream, |
| ShellImageDataFactory_GetDataFormatFromPath, |
| }; |
| |
| static IShellImageDataFactory ShellImageDataFactory = { &ShellImageDataFactoryVtbl }; |
| |
| HRESULT WINAPI ShellImageDataFactory_Constructor(IUnknown *outer, REFIID riid, void **obj) |
| { |
| TRACE("%p %s %p\n", outer, debugstr_guid(riid), obj); |
| |
| if (outer) |
| return CLASS_E_NOAGGREGATION; |
| |
| return IShellImageDataFactory_QueryInterface(&ShellImageDataFactory, riid, obj); |
| } |