|  | /* | 
|  | * Helper functions for debugging | 
|  | * | 
|  | * Copyright 1998, 2002 Juergen Schmied | 
|  | * | 
|  | * 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 <ctype.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  | #include <stdio.h> | 
|  | #include "windef.h" | 
|  | #include "wingdi.h" | 
|  | #include "pidl.h" | 
|  | #include "shldisp.h" | 
|  | #include "wine/debug.h" | 
|  | #include "debughlp.h" | 
|  | #include "docobj.h" | 
|  | #include "shell32_main.h" | 
|  |  | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(pidl); | 
|  |  | 
|  | static | 
|  | LPITEMIDLIST _dbg_ILGetNext(LPCITEMIDLIST pidl) | 
|  | { | 
|  | WORD len; | 
|  |  | 
|  | if(pidl) | 
|  | { | 
|  | len =  pidl->mkid.cb; | 
|  | if (len) | 
|  | { | 
|  | return (LPITEMIDLIST) (((LPBYTE)pidl)+len); | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static | 
|  | BOOL _dbg_ILIsDesktop(LPCITEMIDLIST pidl) | 
|  | { | 
|  | return ( !pidl || (pidl && pidl->mkid.cb == 0x00) ); | 
|  | } | 
|  |  | 
|  | static | 
|  | LPPIDLDATA _dbg_ILGetDataPointer(LPCITEMIDLIST pidl) | 
|  | { | 
|  | if(pidl && pidl->mkid.cb != 0x00) | 
|  | return (LPPIDLDATA)pidl->mkid.abID; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static | 
|  | LPSTR _dbg_ILGetTextPointer(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl); | 
|  |  | 
|  | if (pdata) | 
|  | { | 
|  | switch (pdata->type) | 
|  | { | 
|  | case PT_GUID: | 
|  | case PT_SHELLEXT: | 
|  | case PT_YAGUID: | 
|  | return NULL; | 
|  |  | 
|  | case PT_DRIVE: | 
|  | case PT_DRIVE1: | 
|  | case PT_DRIVE2: | 
|  | case PT_DRIVE3: | 
|  | return pdata->u.drive.szDriveName; | 
|  |  | 
|  | case PT_FOLDER: | 
|  | case PT_FOLDER1: | 
|  | case PT_VALUE: | 
|  | case PT_IESPECIAL1: | 
|  | case PT_IESPECIAL2: | 
|  | return pdata->u.file.szNames; | 
|  |  | 
|  | case PT_WORKGRP: | 
|  | case PT_COMP: | 
|  | case PT_NETWORK: | 
|  | case PT_NETPROVIDER: | 
|  | case PT_SHARE: | 
|  | return pdata->u.network.szNames; | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static | 
|  | LPWSTR _dbg_ILGetTextPointerW(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl); | 
|  |  | 
|  | if (pdata) | 
|  | { | 
|  | switch (pdata->type) | 
|  | { | 
|  | case PT_GUID: | 
|  | case PT_SHELLEXT: | 
|  | case PT_YAGUID: | 
|  | return NULL; | 
|  |  | 
|  | case PT_DRIVE: | 
|  | case PT_DRIVE1: | 
|  | case PT_DRIVE2: | 
|  | case PT_DRIVE3: | 
|  | /* return (LPSTR)&(pdata->u.drive.szDriveName);*/ | 
|  | return NULL; | 
|  |  | 
|  | case PT_FOLDER: | 
|  | case PT_FOLDER1: | 
|  | case PT_VALUE: | 
|  | case PT_IESPECIAL1: | 
|  | case PT_IESPECIAL2: | 
|  | /* return (LPSTR)&(pdata->u.file.szNames); */ | 
|  | return NULL; | 
|  |  | 
|  | case PT_WORKGRP: | 
|  | case PT_COMP: | 
|  | case PT_NETWORK: | 
|  | case PT_NETPROVIDER: | 
|  | case PT_SHARE: | 
|  | /* return (LPSTR)&(pdata->u.network.szNames); */ | 
|  | return NULL; | 
|  |  | 
|  | case PT_VALUEW: | 
|  | return (LPWSTR)pdata->u.file.szNames; | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | static | 
|  | LPSTR _dbg_ILGetSTextPointer(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl); | 
|  |  | 
|  | if (pdata) | 
|  | { | 
|  | switch (pdata->type) | 
|  | { | 
|  | case PT_FOLDER: | 
|  | case PT_VALUE: | 
|  | case PT_IESPECIAL1: | 
|  | case PT_IESPECIAL2: | 
|  | return pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1; | 
|  |  | 
|  | case PT_WORKGRP: | 
|  | return pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1; | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static | 
|  | LPWSTR _dbg_ILGetSTextPointerW(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl); | 
|  |  | 
|  | if (pdata) | 
|  | { | 
|  | switch (pdata->type) | 
|  | { | 
|  | case PT_FOLDER: | 
|  | case PT_VALUE: | 
|  | case PT_IESPECIAL1: | 
|  | case PT_IESPECIAL2: | 
|  | /*return (LPSTR)(pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1); */ | 
|  | return NULL; | 
|  |  | 
|  | case PT_WORKGRP: | 
|  | /* return (LPSTR)(pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1); */ | 
|  | return NULL; | 
|  |  | 
|  | case PT_VALUEW: | 
|  | return (LPWSTR)(pdata->u.file.szNames + lstrlenW ((LPWSTR)pdata->u.file.szNames) + 1); | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | static | 
|  | IID* _dbg_ILGetGUIDPointer(LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPPIDLDATA pdata =_ILGetDataPointer(pidl); | 
|  |  | 
|  | if (pdata) | 
|  | { | 
|  | switch (pdata->type) | 
|  | { | 
|  | case PT_SHELLEXT: | 
|  | case PT_GUID: | 
|  | case PT_YAGUID: | 
|  | return &(pdata->u.guid.guid); | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static | 
|  | void _dbg_ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize) | 
|  | { | 
|  | LPSTR		szSrc; | 
|  | LPWSTR		szSrcW; | 
|  | GUID const * 	riid; | 
|  |  | 
|  | if (!pidl) return; | 
|  |  | 
|  | if (szOut) | 
|  | *szOut = 0; | 
|  |  | 
|  | if (_dbg_ILIsDesktop(pidl)) | 
|  | { | 
|  | /* desktop */ | 
|  | if (szOut) lstrcpynA(szOut, "Desktop", uOutSize); | 
|  | } | 
|  | else if (( szSrc = _dbg_ILGetTextPointer(pidl) )) | 
|  | { | 
|  | /* filesystem */ | 
|  | if (szOut) lstrcpynA(szOut, szSrc, uOutSize); | 
|  | } | 
|  | else if (( szSrcW = _dbg_ILGetTextPointerW(pidl) )) | 
|  | { | 
|  | CHAR tmp[MAX_PATH]; | 
|  | /* unicode filesystem */ | 
|  | WideCharToMultiByte(CP_ACP,0,szSrcW, -1, tmp, MAX_PATH, NULL, NULL); | 
|  | if (szOut) lstrcpynA(szOut, tmp, uOutSize); | 
|  | } | 
|  | else if (( riid = _dbg_ILGetGUIDPointer(pidl) )) | 
|  | { | 
|  | if (szOut) | 
|  | sprintf( szOut, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", | 
|  | riid->Data1, riid->Data2, riid->Data3, | 
|  | riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3], | 
|  | riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7] ); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | void pdump (LPCITEMIDLIST pidl) | 
|  | { | 
|  | LPCITEMIDLIST pidltemp = pidl; | 
|  |  | 
|  | if (!TRACE_ON(pidl)) return; | 
|  |  | 
|  | if (! pidltemp) | 
|  | { | 
|  | MESSAGE ("-------- pidl=NULL (Desktop)\n"); | 
|  | } | 
|  | else | 
|  | { | 
|  | MESSAGE ("-------- pidl=%p\n", pidl); | 
|  | if (pidltemp->mkid.cb) | 
|  | { | 
|  | do | 
|  | { | 
|  | if (_ILIsUnicode(pidltemp)) | 
|  | { | 
|  | DWORD dwAttrib = 0; | 
|  | LPPIDLDATA pData   = _dbg_ILGetDataPointer(pidltemp); | 
|  | DWORD type = pData ? pData->type : 0; | 
|  | LPWSTR szLongName   = _dbg_ILGetTextPointerW(pidltemp); | 
|  | LPWSTR szShortName  = _dbg_ILGetSTextPointerW(pidltemp); | 
|  | char szName[MAX_PATH]; | 
|  |  | 
|  | _dbg_ILSimpleGetText(pidltemp, szName, MAX_PATH); | 
|  | if ( pData && (PT_FOLDER == type || PT_VALUE == type) ) | 
|  | dwAttrib = pData->u.file.uFileAttribs; | 
|  |  | 
|  | MESSAGE ("[%p] size=%04u type=%x attr=0x%08x name=%s (%s,%s)\n", | 
|  | pidltemp, pidltemp->mkid.cb, type, dwAttrib, | 
|  | debugstr_a(szName), debugstr_w(szLongName), debugstr_w(szShortName)); | 
|  | } | 
|  | else | 
|  | { | 
|  | DWORD dwAttrib = 0; | 
|  | LPPIDLDATA pData   = _dbg_ILGetDataPointer(pidltemp); | 
|  | DWORD type = pData ? pData->type : 0; | 
|  | LPSTR szLongName   = _dbg_ILGetTextPointer(pidltemp); | 
|  | LPSTR szShortName  = _dbg_ILGetSTextPointer(pidltemp); | 
|  | char szName[MAX_PATH]; | 
|  |  | 
|  | _dbg_ILSimpleGetText(pidltemp, szName, MAX_PATH); | 
|  | if ( pData && (PT_FOLDER == type || PT_VALUE == type) ) | 
|  | dwAttrib = pData->u.file.uFileAttribs; | 
|  |  | 
|  | MESSAGE ("[%p] size=%04u type=%x attr=0x%08x name=%s (%s,%s)\n", | 
|  | pidltemp, pidltemp->mkid.cb, type, dwAttrib, | 
|  | debugstr_a(szName), debugstr_a(szLongName), debugstr_a(szShortName)); | 
|  | } | 
|  |  | 
|  | pidltemp = _dbg_ILGetNext(pidltemp); | 
|  |  | 
|  | } while (pidltemp && pidltemp->mkid.cb); | 
|  | } | 
|  | else | 
|  | { | 
|  | MESSAGE ("empty pidl (Desktop)\n"); | 
|  | } | 
|  | pcheck(pidl); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void dump_pidl_hex( LPCITEMIDLIST pidl ) | 
|  | { | 
|  | const unsigned char *p = (const unsigned char *)pidl; | 
|  | const int max_bytes = 0x80; | 
|  | #define max_line 0x10 | 
|  | char szHex[max_line*3+1], szAscii[max_line+1]; | 
|  | int i, n; | 
|  |  | 
|  | n = pidl->mkid.cb; | 
|  | if( n>max_bytes ) | 
|  | n = max_bytes; | 
|  | for( i=0; i<n; i++ ) | 
|  | { | 
|  | sprintf( &szHex[ (i%max_line)*3 ], "%02X ", p[i] ); | 
|  | szAscii[ (i%max_line) ] = isprint( p[i] ) ? p[i] : '.'; | 
|  |  | 
|  | /* print out at the end of each line and when we're finished */ | 
|  | if( i!=(n-1) && (i%max_line) != (max_line-1) ) | 
|  | continue; | 
|  | szAscii[ (i%max_line)+1 ] = 0; | 
|  | ERR("%-*s   %s\n", max_line*3, szHex, szAscii ); | 
|  | } | 
|  | } | 
|  |  | 
|  | BOOL pcheck( LPCITEMIDLIST pidl ) | 
|  | { | 
|  | DWORD type; | 
|  | LPCITEMIDLIST pidltemp = pidl; | 
|  |  | 
|  | while( pidltemp && pidltemp->mkid.cb ) | 
|  | { | 
|  | type = _dbg_ILGetDataPointer(pidltemp)->type; | 
|  | switch( type ) | 
|  | { | 
|  | case PT_CPLAPPLET: | 
|  | case PT_GUID: | 
|  | case PT_SHELLEXT: | 
|  | case PT_DRIVE: | 
|  | case PT_DRIVE1: | 
|  | case PT_DRIVE2: | 
|  | case PT_DRIVE3: | 
|  | case PT_FOLDER: | 
|  | case PT_VALUE: | 
|  | case PT_VALUEW: | 
|  | case PT_FOLDER1: | 
|  | case PT_WORKGRP: | 
|  | case PT_COMP: | 
|  | case PT_NETPROVIDER: | 
|  | case PT_NETWORK: | 
|  | case PT_IESPECIAL1: | 
|  | case PT_YAGUID: | 
|  | case PT_IESPECIAL2: | 
|  | case PT_SHARE: | 
|  | break; | 
|  | default: | 
|  | ERR("unknown IDLIST %p [%p] size=%u type=%x\n", | 
|  | pidl, pidltemp, pidltemp->mkid.cb,type ); | 
|  | dump_pidl_hex( pidltemp ); | 
|  | return FALSE; | 
|  | } | 
|  | pidltemp = _dbg_ILGetNext(pidltemp); | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static const struct { | 
|  | REFIID riid; | 
|  | const char *name; | 
|  | } InterfaceDesc[] = { | 
|  | {&IID_IUnknown,			"IID_IUnknown"}, | 
|  | {&IID_IClassFactory,		"IID_IClassFactory"}, | 
|  | {&IID_IShellView,		"IID_IShellView"}, | 
|  | {&IID_IOleCommandTarget,	"IID_IOleCommandTarget"}, | 
|  | {&IID_IDropTarget,		"IID_IDropTarget"}, | 
|  | {&IID_IDropSource,		"IID_IDropSource"}, | 
|  | {&IID_IViewObject,		"IID_IViewObject"}, | 
|  | {&IID_IContextMenu,		"IID_IContextMenu"}, | 
|  | {&IID_IShellExtInit,		"IID_IShellExtInit"}, | 
|  | {&IID_IShellFolder,		"IID_IShellFolder"}, | 
|  | {&IID_IShellFolder2,		"IID_IShellFolder2"}, | 
|  | {&IID_IPersist,			"IID_IPersist"}, | 
|  | {&IID_IPersistFolder,		"IID_IPersistFolder"}, | 
|  | {&IID_IPersistFolder2,		"IID_IPersistFolder2"}, | 
|  | {&IID_IPersistFolder3,		"IID_IPersistFolder3"}, | 
|  | {&IID_IExtractIconA,		"IID_IExtractIconA"}, | 
|  | {&IID_IExtractIconW,		"IID_IExtractIconW"}, | 
|  | {&IID_IDataObject,		"IID_IDataObject"}, | 
|  | {&IID_IAutoComplete,            "IID_IAutoComplete"}, | 
|  | {&IID_IAutoComplete2,           "IID_IAutoComplete2"}, | 
|  | {&IID_IShellLinkA,              "IID_IShellLinkA"}, | 
|  | {&IID_IShellLinkW,              "IID_IShellLinkW"}, | 
|  | {NULL,NULL}}; | 
|  |  | 
|  | const char * shdebugstr_guid( const struct _GUID *id ) | 
|  | { | 
|  | int i; | 
|  | const char* name = NULL; | 
|  | char clsidbuf[100]; | 
|  |  | 
|  | if (!id) return "(null)"; | 
|  |  | 
|  | for (i=0;InterfaceDesc[i].riid && !name;i++) { | 
|  | if (IsEqualIID(InterfaceDesc[i].riid, id)) name = InterfaceDesc[i].name; | 
|  | } | 
|  | if (!name) { | 
|  | if (HCR_GetClassNameA(id, clsidbuf, 100)) | 
|  | name = clsidbuf; | 
|  | } | 
|  |  | 
|  | return wine_dbg_sprintf( "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x} (%s)", | 
|  | id->Data1, id->Data2, id->Data3, | 
|  | id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], | 
|  | id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], name ? name : "unknown" ); | 
|  | } |