xref: /reactos/dll/win32/shell32/debughlp.cpp (revision 9cfd8dd9)
1 /*
2  * Helper functions for debugging
3  *
4  * Copyright 1998, 2002 Juergen Schmied
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include "precomp.h"
22 
23 WINE_DEFAULT_DEBUG_CHANNEL(pidl);
24 
25 static
26 LPITEMIDLIST _dbg_ILGetNext(LPCITEMIDLIST pidl)
27 {
28     WORD len;
29 
30     if(pidl)
31     {
32       len =  pidl->mkid.cb;
33       if (len)
34       {
35         return (LPITEMIDLIST) (((LPBYTE)pidl)+len);
36       }
37     }
38     return NULL;
39 }
40 
41 static
42 BOOL _dbg_ILIsDesktop(LPCITEMIDLIST pidl)
43 {
44     return ( !pidl || (pidl && pidl->mkid.cb == 0x00) );
45 }
46 
47 static
48 LPPIDLDATA _dbg_ILGetDataPointer(LPCITEMIDLIST pidl)
49 {
50     if(pidl && pidl->mkid.cb != 0x00)
51       return (LPPIDLDATA) &(pidl->mkid.abID);
52     return NULL;
53 }
54 
55 static
56 LPSTR _dbg_ILGetTextPointer(LPCITEMIDLIST pidl)
57 {
58     LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl);
59 
60     if (pdata)
61     {
62       switch (pdata->type)
63       {
64         case PT_GUID:
65         case PT_SHELLEXT:
66         case PT_YAGUID:
67           return NULL;
68 
69         case PT_DRIVE:
70         case PT_DRIVE1:
71         case PT_DRIVE2:
72         case PT_DRIVE3:
73           return (LPSTR)&(pdata->u.drive.szDriveName);
74 
75         case PT_FOLDER:
76         case PT_FOLDER1:
77         case PT_VALUE:
78         case PT_IESPECIAL1:
79         case PT_IESPECIAL2:
80           return (LPSTR)&(pdata->u.file.szNames);
81 
82         case PT_WORKGRP:
83         case PT_COMP:
84         case PT_NETWORK:
85         case PT_NETPROVIDER:
86         case PT_SHARE:
87           return (LPSTR)&(pdata->u.network.szNames);
88       }
89     }
90     return NULL;
91 }
92 
93 static
94 LPWSTR _dbg_ILGetTextPointerW(LPCITEMIDLIST pidl)
95 {
96     LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl);
97 
98     if (pdata)
99     {
100       switch (pdata->type)
101       {
102         case PT_GUID:
103         case PT_SHELLEXT:
104         case PT_YAGUID:
105           return NULL;
106 
107         case PT_DRIVE:
108         case PT_DRIVE1:
109         case PT_DRIVE2:
110         case PT_DRIVE3:
111           /* return (LPSTR)&(pdata->u.drive.szDriveName);*/
112           return NULL;
113 
114         case PT_FOLDER:
115         case PT_FOLDER1:
116         case PT_VALUE:
117         case PT_IESPECIAL1:
118         case PT_IESPECIAL2:
119           /* return (LPSTR)&(pdata->u.file.szNames); */
120           return NULL;
121 
122         case PT_WORKGRP:
123         case PT_COMP:
124         case PT_NETWORK:
125         case PT_NETPROVIDER:
126         case PT_SHARE:
127           /* return (LPSTR)&(pdata->u.network.szNames); */
128           return NULL;
129 
130         case PT_VALUEW:
131           return (LPWSTR)&(pdata->u.file.szNames);
132       }
133     }
134     return NULL;
135 }
136 
137 
138 static
139 LPSTR _dbg_ILGetSTextPointer(LPCITEMIDLIST pidl)
140 {
141     LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl);
142 
143     if (pdata)
144     {
145       switch (pdata->type)
146       {
147         case PT_FOLDER:
148         case PT_VALUE:
149         case PT_IESPECIAL1:
150         case PT_IESPECIAL2:
151           return (LPSTR)(pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1);
152 
153         case PT_WORKGRP:
154           return (LPSTR)(pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1);
155       }
156     }
157     return NULL;
158 }
159 
160 static
161 LPWSTR _dbg_ILGetSTextPointerW(LPCITEMIDLIST pidl)
162 {
163     LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl);
164 
165     if (pdata)
166     {
167       switch (pdata->type)
168       {
169         case PT_FOLDER:
170         case PT_VALUE:
171         case PT_IESPECIAL1:
172         case PT_IESPECIAL2:
173           /*return (LPSTR)(pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1); */
174           return NULL;
175 
176         case PT_WORKGRP:
177           /* return (LPSTR)(pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1); */
178           return NULL;
179 
180         case PT_VALUEW:
181           return (LPWSTR)(pdata->u.file.szNames + wcslen ((LPWSTR)pdata->u.file.szNames) + 1);
182       }
183     }
184     return NULL;
185 }
186 
187 
188 static
189 IID* _dbg_ILGetGUIDPointer(LPCITEMIDLIST pidl)
190 {
191     LPPIDLDATA pdata =_ILGetDataPointer(pidl);
192 
193     if (pdata)
194     {
195       switch (pdata->type)
196       {
197         case PT_SHELLEXT:
198         case PT_GUID:
199             case PT_YAGUID:
200           return &(pdata->u.guid.guid);
201       }
202     }
203     return NULL;
204 }
205 
206 static
207 void _dbg_ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize)
208 {
209     LPSTR        szSrc;
210     LPWSTR        szSrcW;
211     GUID const *     riid;
212 
213     if (!pidl) return;
214 
215     if (szOut)
216       *szOut = 0;
217 
218     if (_dbg_ILIsDesktop(pidl))
219     {
220      /* desktop */
221       if (szOut) lstrcpynA(szOut, "Desktop", uOutSize);
222     }
223     else if (( szSrc = _dbg_ILGetTextPointer(pidl) ))
224     {
225       /* filesystem */
226       if (szOut) lstrcpynA(szOut, szSrc, uOutSize);
227     }
228     else if (( szSrcW = _dbg_ILGetTextPointerW(pidl) ))
229     {
230       CHAR tmp[MAX_PATH];
231       /* unicode filesystem */
232       WideCharToMultiByte(CP_ACP,0,szSrcW, -1, tmp, MAX_PATH, NULL, NULL);
233       if (szOut) lstrcpynA(szOut, tmp, uOutSize);
234     }
235     else if (( riid = _dbg_ILGetGUIDPointer(pidl) ))
236     {
237       if (szOut)
238             sprintf( szOut, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
239                  riid->Data1, riid->Data2, riid->Data3,
240                  riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
241                  riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7] );
242     }
243 }
244 
245 
246 
247 
248 static void pdump_impl (LPCITEMIDLIST pidl)
249 {
250     LPCITEMIDLIST pidltemp = pidl;
251 
252 
253     if (! pidltemp)
254     {
255       MESSAGE ("-------- pidl=NULL (Desktop)\n");
256     }
257     else
258     {
259       MESSAGE ("-------- pidl=%p\n", pidl);
260       if (pidltemp->mkid.cb)
261       {
262         do
263         {
264           if (_ILIsUnicode(pidltemp))
265           {
266               DWORD dwAttrib = 0;
267               LPPIDLDATA pData   = _dbg_ILGetDataPointer(pidltemp);
268               DWORD type = pData ? pData->type : 0;
269               LPWSTR szLongName   = _dbg_ILGetTextPointerW(pidltemp);
270               LPWSTR szShortName  = _dbg_ILGetSTextPointerW(pidltemp);
271               char szName[MAX_PATH];
272 
273               _dbg_ILSimpleGetText(pidltemp, szName, MAX_PATH);
274               if ( pData && (PT_FOLDER == type || PT_VALUE == type) )
275                 dwAttrib = pData->u.file.uFileAttribs;
276 
277               MESSAGE ("[%p] size=%04u type=%x attr=0x%08x name=%s (%s,%s)\n",
278                        pidltemp, pidltemp->mkid.cb, type, dwAttrib,
279                            debugstr_a(szName), debugstr_w(szLongName), debugstr_w(szShortName));
280           }
281           else
282           {
283               DWORD dwAttrib = 0;
284               LPPIDLDATA pData   = _dbg_ILGetDataPointer(pidltemp);
285               DWORD type = pData ? pData->type : 0;
286               LPSTR szLongName   = _dbg_ILGetTextPointer(pidltemp);
287               LPSTR szShortName  = _dbg_ILGetSTextPointer(pidltemp);
288               char szName[MAX_PATH];
289 
290               _dbg_ILSimpleGetText(pidltemp, szName, MAX_PATH);
291               if ( pData && (PT_FOLDER == type || PT_VALUE == type) )
292                 dwAttrib = pData->u.file.uFileAttribs;
293 
294               MESSAGE ("[%p] size=%04u type=%x attr=0x%08x name=%s (%s,%s)\n",
295                        pidltemp, pidltemp->mkid.cb, type, dwAttrib,
296                            debugstr_a(szName), debugstr_a(szLongName), debugstr_a(szShortName));
297           }
298 
299           pidltemp = _dbg_ILGetNext(pidltemp);
300 
301         } while (pidltemp && pidltemp->mkid.cb);
302       }
303       else
304       {
305         MESSAGE ("empty pidl (Desktop)\n");
306       }
307       pcheck(pidl);
308     }
309 }
310 
311 void pdump(LPCITEMIDLIST pidl)
312 {
313     if (!TRACE_ON(pidl)) return;
314 
315     return pdump_impl(pidl);
316 }
317 
318 
319 void pdump_always(LPCITEMIDLIST pidl)
320 {
321     pdump_impl(pidl);
322 }
323 
324 
325 static void dump_pidl_hex( LPCITEMIDLIST pidl )
326 {
327     const unsigned char *p = (const unsigned char *)pidl;
328     const int max_bytes = 0x80;
329 #define max_line 0x10
330     char szHex[max_line*3+1], szAscii[max_line+1];
331     int i, n;
332 
333     n = pidl->mkid.cb;
334     if( n>max_bytes )
335         n = max_bytes;
336     for( i=0; i<n; i++ )
337     {
338         sprintf( &szHex[ (i%max_line)*3 ], "%02X ", p[i] );
339         szAscii[ (i%max_line) ] = isprint( p[i] ) ? p[i] : '.';
340 
341         /* print out at the end of each line and when we're finished */
342         if( i!=(n-1) && (i%max_line) != (max_line-1) )
343             continue;
344         szAscii[ (i%max_line)+1 ] = 0;
345         ERR("%-*s   %s\n", max_line*3, szHex, szAscii );
346     }
347 }
348 
349 BOOL pcheck( LPCITEMIDLIST pidl )
350 {
351     DWORD type;
352     LPCITEMIDLIST pidltemp = pidl;
353 
354     while( pidltemp && pidltemp->mkid.cb )
355     {
356         LPPIDLDATA pidlData = _dbg_ILGetDataPointer(pidltemp);
357 
358         if (pidlData)
359         {
360             type = pidlData->type;
361             switch( type )
362             {
363                 case PT_CPLAPPLET:
364                 case PT_GUID:
365                 case PT_SHELLEXT:
366                 case PT_DRIVE:
367                 case PT_DRIVE1:
368                 case PT_DRIVE2:
369                 case PT_DRIVE3:
370                 case PT_FOLDER:
371                 case PT_VALUE:
372                 case PT_VALUEW:
373                 case PT_FOLDER1:
374                 case PT_WORKGRP:
375                 case PT_COMP:
376                 case PT_NETPROVIDER:
377                 case PT_NETWORK:
378                 case PT_IESPECIAL1:
379                 case PT_YAGUID:
380                 case PT_IESPECIAL2:
381                 case PT_SHARE:
382                 case 0x99:      /* Network Connection pidl type */
383                     break;
384                 default:
385                     ERR("unknown IDLIST %p [%p] size=%u type=%x\n",
386                         pidl, pidltemp, pidltemp->mkid.cb,type );
387                     dump_pidl_hex( pidltemp );
388                     return FALSE;
389             }
390             pidltemp = _dbg_ILGetNext(pidltemp);
391         }
392         else
393         {
394             return FALSE;
395         }
396     }
397     return TRUE;
398 }
399 
400 static const struct {
401     REFIID riid;
402     const char *name;
403 } InterfaceDesc[] = {
404     {IID_IUnknown,            "IID_IUnknown"},
405     {IID_IClassFactory,        "IID_IClassFactory"},
406     {IID_IShellView,        "IID_IShellView"},
407     {IID_IOleCommandTarget,    "IID_IOleCommandTarget"},
408     {IID_IDropTarget,        "IID_IDropTarget"},
409     {IID_IDropSource,        "IID_IDropSource"},
410     {IID_IViewObject,        "IID_IViewObject"},
411     {IID_IContextMenu,        "IID_IContextMenu"},
412     {IID_IShellExtInit,        "IID_IShellExtInit"},
413     {IID_IShellFolder,        "IID_IShellFolder"},
414     {IID_IShellFolder2,        "IID_IShellFolder2"},
415     {IID_IPersist,            "IID_IPersist"},
416     {IID_IPersistFolder,        "IID_IPersistFolder"},
417     {IID_IPersistFolder2,        "IID_IPersistFolder2"},
418     {IID_IPersistFolder3,        "IID_IPersistFolder3"},
419     {IID_IExtractIconA,        "IID_IExtractIconA"},
420     {IID_IExtractIconW,        "IID_IExtractIconW"},
421     {IID_IDataObject,        "IID_IDataObject"},
422     {IID_IAutoComplete,            "IID_IAutoComplete"},
423     {IID_IAutoComplete2,           "IID_IAutoComplete2"},
424         {IID_IShellLinkA,              "IID_IShellLinkA"},
425         {IID_IShellLinkW,              "IID_IShellLinkW"},
426     };
427 
428 const char * shdebugstr_guid( const struct _GUID *id )
429 {
430     unsigned int i;
431     const char* name = NULL;
432     char clsidbuf[100];
433 
434     if (!id) return "(null)";
435 
436         for (i=0; i < sizeof(InterfaceDesc) / sizeof(InterfaceDesc[0]); i++) {
437             if (IsEqualIID(InterfaceDesc[i].riid, *id)) name = InterfaceDesc[i].name;
438         }
439         if (!name) {
440         if (HCR_GetClassNameA(*id, clsidbuf, 100))
441             name = clsidbuf;
442         }
443 
444             return wine_dbg_sprintf( "\n\t{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x} (%s)",
445                  id->Data1, id->Data2, id->Data3,
446                  id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
447                  id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], name ? name : "unknown" );
448 }
449