| /* |
| * 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 |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "shellapi.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| #include "shlobj.h" |
| #include "shlguid.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 HRESULT WINAPI IFSFolder_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); |
| |
| static const WCHAR sShell32[12] = {'S','H','E','L','L','3','2','.','D','L','L','\0'}; |
| static const WCHAR sOLE32[10] = {'O','L','E','3','2','.','D','L','L','\0'}; |
| |
| /************************************************************************** |
| * Default ClassFactory types |
| */ |
| typedef HRESULT (CALLBACK *LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject); |
| IClassFactory * IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, REFIID riidInst); |
| |
| /* this table contains all CLSID's of shell32 objects */ |
| static const struct { |
| REFIID riid; |
| LPFNCREATEINSTANCE lpfnCI; |
| } InterfaceTable[] = { |
| {&CLSID_ShellFSFolder, &IFSFolder_Constructor}, |
| {&CLSID_MyComputer, &ISF_MyComputer_Constructor}, |
| {&CLSID_ShellDesktop, &ISF_Desktop_Constructor}, |
| {&CLSID_ShellLink, &IShellLink_Constructor}, |
| {&CLSID_DragDropHelper, &IDropTargetHelper_Constructor}, |
| {&CLSID_ControlPanel, &IControlPanel_Constructor}, |
| {&CLSID_AutoComplete, &IAutoComplete_Constructor}, |
| {&CLSID_UnixFolder, &UnixFolder_Constructor}, |
| {&CLSID_UnixDosFolder, &UnixDosFolder_Constructor}, |
| {&CLSID_FolderShortcut, &FolderShortcut_Constructor}, |
| {&CLSID_MyDocuments, &MyDocuments_Constructor}, |
| {&CLSID_RecycleBin, &RecycleBin_Constructor}, |
| {NULL,NULL} |
| }; |
| |
| |
| /* FIXME: this should be SHLWAPI.24 since we can't yet import by ordinal */ |
| |
| DWORD WINAPI __SHGUIDToStringW (REFGUID guid, LPWSTR str) |
| { |
| WCHAR sFormat[52] = {'{','%','0','8','l','x','-','%','0','4', |
| 'x','-','%','0','4','x','-','%','0','2', |
| 'x','%','0','2','x','-','%','0','2','x', |
| '%','0','2','x','%','0','2','x','%','0', |
| '2','x','%','0','2','x','%','0','2','x', |
| '}','\0'}; |
| |
| return wsprintfW ( str, sFormat, |
| guid->Data1, guid->Data2, guid->Data3, |
| guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], |
| guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] ); |
| |
| } |
| |
| /************************************************************************* |
| * 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 |
| * CoCreateInstace, SHLoadOLE |
| */ |
| HRESULT WINAPI SHCoCreateInstance( |
| LPCWSTR aclsid, |
| const CLSID *clsid, |
| LPUNKNOWN pUnkOuter, |
| REFIID refiid, |
| LPVOID *ppv) |
| { |
| DWORD hres; |
| IID iid; |
| CLSID * myclsid = (CLSID*)clsid; |
| WCHAR sKeyName[MAX_PATH]; |
| const WCHAR sCLSID[7] = {'C','L','S','I','D','\\','\0'}; |
| WCHAR sClassID[60]; |
| const WCHAR sInProcServer32[16] ={'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2','\0'}; |
| const WCHAR sLoadWithoutCOM[15] ={'L','o','a','d','W','i','t','h','o','u','t','C','O','M','\0'}; |
| WCHAR sDllPath[MAX_PATH]; |
| HKEY hKey; |
| DWORD dwSize; |
| BOOLEAN bLoadFromShell32 = FALSE; |
| BOOLEAN bLoadWithoutCOM = FALSE; |
| 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); |
| |
| /* we look up the dll path in the registry */ |
| __SHGUIDToStringW(myclsid, sClassID); |
| lstrcpyW(sKeyName, sCLSID); |
| lstrcatW(sKeyName, sClassID); |
| lstrcatW(sKeyName, sInProcServer32); |
| |
| if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_CLASSES_ROOT, sKeyName, 0, KEY_READ, &hKey)) { |
| dwSize = sizeof(sDllPath); |
| SHQueryValueExW(hKey, NULL, 0,0, sDllPath, &dwSize ); |
| |
| /* if a special registry key is set, we load a shell extension without help of OLE32 */ |
| bLoadWithoutCOM = (ERROR_SUCCESS == SHQueryValueExW(hKey, sLoadWithoutCOM, 0, 0, 0, 0)); |
| |
| /* if the com object is inside shell32, omit use of ole32 */ |
| bLoadFromShell32 = (0==lstrcmpiW( PathFindFileNameW(sDllPath), sShell32)); |
| |
| RegCloseKey (hKey); |
| } else { |
| /* since we can't find it in the registry we try internally */ |
| bLoadFromShell32 = TRUE; |
| } |
| |
| TRACE("WithoutCom=%u FromShell=%u\n", bLoadWithoutCOM, bLoadFromShell32); |
| |
| /* now we create an instance */ |
| if (bLoadFromShell32) { |
| if (! SUCCEEDED(DllGetClassObject(myclsid, &IID_IClassFactory,(LPVOID*)&pcf))) { |
| ERR("LoadFromShell failed for CLSID=%s\n", shdebugstr_guid(myclsid)); |
| } |
| } else if (bLoadWithoutCOM) { |
| |
| /* load an external dll without ole32 */ |
| HANDLE hLibrary; |
| typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv); |
| DllGetClassObjectFunc DllGetClassObject; |
| |
| 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 (! SUCCEEDED(hres = DllGetClassObject(myclsid, &IID_IClassFactory, (LPVOID*)&pcf))) { |
| TRACE("GetClassObject failed 0x%08lx\n", hres); |
| goto end; |
| } |
| |
| } else { |
| |
| /* load an external dll in the usual way */ |
| hres = CoCreateInstance(myclsid, pUnkOuter, CLSCTX_INPROC_SERVER, refiid, ppv); |
| goto end; |
| } |
| |
| /* here we should have a ClassFactory */ |
| if (!pcf) return E_ACCESSDENIED; |
| |
| hres = IClassFactory_CreateInstance(pcf, pUnkOuter, refiid, ppv); |
| IClassFactory_Release(pcf); |
| end: |
| if(hres!=S_OK) |
| { |
| ERR("failed (0x%08lx) 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) |
| { |
| HRESULT hres = E_OUTOFMEMORY; |
| IClassFactory * pcf = NULL; |
| 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].riid;i++) { |
| if(IsEqualIID(InterfaceTable[i].riid, rclsid)) { |
| TRACE("index[%u]\n", i); |
| pcf = IDefClF_fnConstructor(InterfaceTable[i].lpfnCI, NULL, NULL); |
| } |
| } |
| |
| 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((LPWSTR)clsid, id); |
| } |
| DWORD WINAPI SHCLSIDFromStringAW (LPVOID 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("%lu 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 = S_OK; |
| TRACE("\n"); |
| |
| if(!psf) return E_INVALIDARG; |
| *psf = NULL; |
| hres = ISF_Desktop_Constructor(NULL, &IID_IShellFolder,(LPVOID*)psf); |
| |
| TRACE("-- %p->(%p)\n",psf, *psf); |
| 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 |
| { |
| const IClassFactoryVtbl *lpVtbl; |
| LONG ref; |
| CLSID *rclsid; |
| LPFNCREATEINSTANCE lpfnCI; |
| const IID * riidInst; |
| LONG * pcRefDll; /* pointer to refcounter in external dll (ugrrr...) */ |
| } IDefClFImpl; |
| |
| static const IClassFactoryVtbl dclfvt; |
| |
| /************************************************************************** |
| * IDefClF_fnConstructor |
| */ |
| |
| IClassFactory * IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, REFIID riidInst) |
| { |
| IDefClFImpl* lpclf; |
| |
| lpclf = HeapAlloc(GetProcessHeap(),0,sizeof(IDefClFImpl)); |
| lpclf->ref = 1; |
| lpclf->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 = (IDefClFImpl *)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 = (IDefClFImpl *)iface; |
| ULONG refCount = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p)->(count=%lu)\n", This, refCount - 1); |
| |
| return refCount; |
| } |
| /****************************************************************************** |
| * IDefClF_fnRelease |
| */ |
| static ULONG WINAPI IDefClF_fnRelease(LPCLASSFACTORY iface) |
| { |
| IDefClFImpl *This = (IDefClFImpl *)iface; |
| ULONG refCount = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p)->(count=%lu)\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 = (IDefClFImpl *)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 = (IDefClFImpl *)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 NOERROR; |
| } |
| |
| /************************************************************************* |
| * 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((HGLOBAL)h); |
| } |
| |
| /************************************************************************* |
| * DragQueryPoint [SHELL32.@] |
| */ |
| BOOL WINAPI DragQueryPoint(HDROP hDrop, POINT *p) |
| { |
| DROPFILES *lpDropFileStruct; |
| BOOL bRet; |
| |
| TRACE("\n"); |
| |
| lpDropFileStruct = (DROPFILES *) 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 = (DROPFILES *) 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) { |
| 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); |
| i++; |
| if (!lpszFile ) goto end; /* needed buffer size */ |
| i = (lLength > i) ? i : lLength; |
| lstrcpynA (lpszFile, lpDrop, i); |
| 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 = (DROPFILES *) 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) { |
| 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); |
| i++; |
| if ( !lpszwFile) goto end; /* needed buffer size */ |
| |
| i = (lLength > i) ? i : lLength; |
| lstrcpynW (lpszwFile, lpwDrop, i); |
| end: |
| GlobalUnlock(hDrop); |
| return i; |
| } |