2 * Shell Library Functions
21 #include "cursoricon.h"
22 #include "interfaces.h"
23 #include "sysmetrics.h"
28 static const char * const SHELL_People[] =
45 "Niels de Carpentier",
51 "Frans van Dorsselaer",
102 "Philippe De Muyter",
115 "Bernhard Rosenkraenzer",
116 "Johannes Ruscheinski",
118 "Constantine Sapuntzakis",
126 "Yngvi Sigurjonsson",
141 "Gregory Trubetskoy",
153 "Karl Guenter Wuensch",
156 "Nikita V. Youshchenko",
159 "Luiz Otavio L. Zorzella",
164 /* .ICO file ICONDIR definitions */
170 BYTE bWidth; /* Width, in pixels, of the image */
171 BYTE bHeight; /* Height, in pixels, of the image */
172 BYTE bColorCount; /* Number of colors in image (0 if >=8bpp) */
173 BYTE bReserved; /* Reserved ( must be 0) */
174 WORD wPlanes; /* Color Planes */
175 WORD wBitCount; /* Bits per pixel */
176 DWORD dwBytesInRes; /* How many bytes in this resource? */
177 DWORD dwImageOffset; /* Where in the file is this image? */
178 } icoICONDIRENTRY, *LPicoICONDIRENTRY;
182 WORD idReserved; /* Reserved (must be 0) */
183 WORD idType; /* Resource Type (1 for icons) */
184 WORD idCount; /* How many images? */
185 icoICONDIRENTRY idEntries[1]; /* An entry for each image (idCount of 'em) */
186 } icoICONDIR, *LPicoICONDIR;
190 static const char* lpstrMsgWndCreated = "OTHERWINDOWCREATED";
191 static const char* lpstrMsgWndDestroyed = "OTHERWINDOWDESTROYED";
192 static const char* lpstrMsgShellActivate = "ACTIVATESHELLWINDOW";
194 static HWND16 SHELL_hWnd = 0;
195 static HHOOK SHELL_hHook = 0;
196 static UINT16 uMsgWndCreated = 0;
197 static UINT16 uMsgWndDestroyed = 0;
198 static UINT16 uMsgShellActivate = 0;
200 /*************************************************************************
201 * DragAcceptFiles [SHELL.9]
203 void WINAPI DragAcceptFiles(HWND16 hWnd, BOOL16 b)
205 WND* wnd = WIN_FindWndPtr(hWnd);
208 wnd->dwExStyle = b? wnd->dwExStyle | WS_EX_ACCEPTFILES
209 : wnd->dwExStyle & ~WS_EX_ACCEPTFILES;
213 /*************************************************************************
214 * DragQueryFile [SHELL.11]
216 UINT16 WINAPI DragQueryFile(HDROP16 hDrop, WORD wFile, LPSTR lpszFile,
219 /* hDrop is a global memory block allocated with GMEM_SHARE
220 * with DROPFILESTRUCT as a header and filenames following
221 * it, zero length filename is in the end */
223 LPDROPFILESTRUCT lpDropFileStruct;
227 TRACE(reg,"(%04x, %i, %p, %u)\n",
228 hDrop,wFile,lpszFile,wLength);
230 lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop);
231 if(!lpDropFileStruct) return 0;
233 lpCurrent = (LPSTR) lpDropFileStruct + lpDropFileStruct->wSize;
238 while (*lpCurrent++); /* skip filename */
240 return (wFile == 0xFFFF) ? i : 0;
243 i = strlen(lpCurrent);
244 if (!lpszFile) return i+1; /* needed buffer size */
246 i = (wLength > i) ? i : wLength-1;
247 strncpy(lpszFile, lpCurrent, i);
250 GlobalUnlock16(hDrop);
255 /*************************************************************************
256 * DragFinish [SHELL.12]
258 void WINAPI DragFinish(HDROP16 h)
260 GlobalFree16((HGLOBAL16)h);
264 /*************************************************************************
265 * DragQueryPoint [SHELL.13]
267 BOOL16 WINAPI DragQueryPoint(HDROP16 hDrop, POINT16 *p)
269 LPDROPFILESTRUCT lpDropFileStruct;
272 lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop);
274 memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT16));
275 bRet = lpDropFileStruct->fInNonClientArea;
277 GlobalUnlock16(hDrop);
281 /*************************************************************************
282 * SHELL_FindExecutable
283 * Utility for code sharing between FindExecutable and ShellExecute
285 static HINSTANCE32 SHELL_FindExecutable( LPCSTR lpFile,
289 char *extension = NULL; /* pointer to file extension */
290 char tmpext[5]; /* local copy to mung as we please */
291 char filetype[256]; /* registry name for this filetype */
292 LONG filetypelen=256; /* length of above */
293 char command[256]; /* command from registry */
294 LONG commandlen=256; /* This is the most DOS can handle :) */
295 char buffer[256]; /* Used to GetProfileString */
296 HINSTANCE32 retval=31; /* default - 'No association was found' */
297 char *tok; /* token pointer */
298 int i; /* random counter */
299 char xlpFile[256]; /* result of SearchPath */
302 (lpFile != NULL?lpFile:"-") );
303 lpResult[0]='\0'; /* Start off with an empty return string */
305 /* trap NULL parameters on entry */
306 if (( lpFile == NULL ) || ( lpResult == NULL ) || ( lpOperation == NULL ))
308 /* FIXME - should throw a warning, perhaps! */
309 return 2; /* File not found. Close enough, I guess. */
312 if (SearchPath32A( NULL, lpFile,".exe",sizeof(xlpFile),xlpFile,NULL))
315 /* First thing we need is the file's extension */
316 extension = strrchr( xlpFile, '.' ); /* Assume last "." is the one; */
317 /* File->Run in progman uses */
319 if ((extension == NULL) || (extension == &xlpFile[strlen(xlpFile)]))
321 return 31; /* no association */
324 /* Make local copy & lowercase it for reg & 'programs=' lookup */
325 lstrcpyn32A( tmpext, extension, 5 );
326 CharLower32A( tmpext );
327 TRACE(exec, "%s file\n", tmpext);
329 /* Three places to check: */
330 /* 1. win.ini, [windows], programs (NB no leading '.') */
331 /* 2. Registry, HKEY_CLASS_ROOT\<filetype>\shell\open\command */
332 /* 3. win.ini, [extensions], extension (NB no leading '.' */
333 /* All I know of the order is that registry is checked before */
334 /* extensions; however, it'd make sense to check the programs */
335 /* section first, so that's what happens here. */
337 /* See if it's a program - if GetProfileString fails, we skip this
338 * section. Actually, if GetProfileString fails, we've probably
339 * got a lot more to worry about than running a program... */
340 if ( GetProfileString32A("windows", "programs", "exe pif bat com",
341 buffer, sizeof(buffer)) > 0 )
343 for (i=0;i<strlen(buffer); i++) buffer[i]=tolower(buffer[i]);
345 tok = strtok(buffer, " \t"); /* ? */
348 if (strcmp(tok, &tmpext[1])==0) /* have to skip the leading "." */
350 strcpy(lpResult, xlpFile);
351 /* Need to perhaps check that the file has a path
353 TRACE(exec, "found %s\n",
357 /* Greater than 32 to indicate success FIXME According to the
358 * docs, I should be returning a handle for the
359 * executable. Does this mean I'm supposed to open the
360 * executable file or something? More RTFM, I guess... */
362 tok=strtok(NULL, " \t");
367 if (RegQueryValue16( (HKEY)HKEY_CLASSES_ROOT, tmpext, filetype,
368 &filetypelen ) == SHELL_ERROR_SUCCESS )
370 filetype[filetypelen]='\0';
371 TRACE(exec, "File type: %s\n",
374 /* Looking for ...buffer\shell\lpOperation\command */
375 strcat( filetype, "\\shell\\" );
376 strcat( filetype, lpOperation );
377 strcat( filetype, "\\command" );
379 if (RegQueryValue16( (HKEY)HKEY_CLASSES_ROOT, filetype, command,
380 &commandlen ) == SHELL_ERROR_SUCCESS )
382 /* Is there a replace() function anywhere? */
383 command[commandlen]='\0';
384 strcpy( lpResult, command );
385 tok=strstr( lpResult, "%1" );
388 tok[0]='\0'; /* truncate string at the percent */
389 strcat( lpResult, xlpFile ); /* what if no dir in xlpFile? */
390 tok=strstr( command, "%1" );
391 if ((tok!=NULL) && (strlen(tok)>2))
393 strcat( lpResult, &tok[2] );
396 retval=33; /* FIXME see above */
399 else /* Check win.ini */
401 /* Toss the leading dot */
403 if ( GetProfileString32A( "extensions", extension, "", command,
404 sizeof(command)) > 0)
406 if (strlen(command)!=0)
408 strcpy( lpResult, command );
409 tok=strstr( lpResult, "^" ); /* should be ^.extension? */
413 strcat( lpResult, xlpFile ); /* what if no dir in xlpFile? */
414 tok=strstr( command, "^" ); /* see above */
415 if ((tok != NULL) && (strlen(tok)>5))
417 strcat( lpResult, &tok[5]);
420 retval=33; /* FIXME - see above */
425 TRACE(exec, "returning %s\n", lpResult);
429 /*************************************************************************
430 * ShellExecute16 [SHELL.20]
432 HINSTANCE16 WINAPI ShellExecute16( HWND16 hWnd, LPCSTR lpOperation,
433 LPCSTR lpFile, LPCSTR lpParameters,
434 LPCSTR lpDirectory, INT16 iShowCmd )
436 HINSTANCE16 retval=31;
440 TRACE(exec, "(%04x,'%s','%s','%s','%s',%x)\n",
441 hWnd, lpOperation ? lpOperation:"<null>", lpFile ? lpFile:"<null>",
442 lpParameters ? lpParameters : "<null>",
443 lpDirectory ? lpDirectory : "<null>", iShowCmd);
445 if (lpFile==NULL) return 0; /* should not happen */
446 if (lpOperation==NULL) /* default is open */
451 GetCurrentDirectory32A( sizeof(old_dir), old_dir );
452 SetCurrentDirectory32A( lpDirectory );
455 retval = SHELL_FindExecutable( lpFile, lpOperation, cmd );
457 if (retval > 32) /* Found */
462 strcat(cmd,lpParameters);
465 TRACE(exec,"starting %s\n",cmd);
466 retval = WinExec32( cmd, iShowCmd );
468 if (lpDirectory) SetCurrentDirectory32A( old_dir );
473 /*************************************************************************
474 * ShellExecute32A (SHELL32.245)
476 HINSTANCE32 WINAPI ShellExecute32A( HWND32 hWnd, LPCSTR lpOperation,
477 LPCSTR lpFile, LPCSTR lpParameters,
478 LPCSTR lpDirectory, INT32 iShowCmd )
480 return ShellExecute16( hWnd, lpOperation, lpFile, lpParameters,
481 lpDirectory, iShowCmd );
485 /*************************************************************************
486 * FindExecutable16 (SHELL.21)
488 HINSTANCE16 WINAPI FindExecutable16( LPCSTR lpFile, LPCSTR lpDirectory,
491 return (HINSTANCE16)FindExecutable32A( lpFile, lpDirectory, lpResult );
494 /*************************************************************************
495 * FindExecutable32A (SHELL32.184)
497 HINSTANCE32 WINAPI FindExecutable32A( LPCSTR lpFile, LPCSTR lpDirectory,
500 HINSTANCE32 retval=31; /* default - 'No association was found' */
503 TRACE(exec, "File %s, Dir %s\n",
504 (lpFile != NULL?lpFile:"-"),
505 (lpDirectory != NULL?lpDirectory:"-"));
507 lpResult[0]='\0'; /* Start off with an empty return string */
509 /* trap NULL parameters on entry */
510 if (( lpFile == NULL ) || ( lpResult == NULL ))
512 /* FIXME - should throw a warning, perhaps! */
513 return 2; /* File not found. Close enough, I guess. */
518 GetCurrentDirectory32A( sizeof(old_dir), old_dir );
519 SetCurrentDirectory32A( lpDirectory );
522 retval = SHELL_FindExecutable( lpFile, "open", lpResult );
524 TRACE(exec, "returning %s\n", lpResult);
525 if (lpDirectory) SetCurrentDirectory32A( old_dir );
536 #define IDC_STATIC_TEXT 100
537 #define IDC_LISTBOX 99
538 #define IDC_WINE_TEXT 98
540 #define DROP_FIELD_TOP (-15)
541 #define DROP_FIELD_HEIGHT 15
543 extern HICON32 hIconTitleFont;
545 static BOOL32 __get_dropline( HWND32 hWnd, LPRECT32 lprect )
547 HWND32 hWndCtl = GetDlgItem32(hWnd, IDC_WINE_TEXT);
550 GetWindowRect32( hWndCtl, lprect );
551 MapWindowPoints32( 0, hWnd, (LPPOINT32)lprect, 2 );
552 lprect->bottom = (lprect->top += DROP_FIELD_TOP);
558 /*************************************************************************
559 * AboutDlgProc32 (not an exported API function)
561 LRESULT WINAPI AboutDlgProc32( HWND32 hWnd, UINT32 msg, WPARAM32 wParam,
565 char Template[512], AppTitle[512];
571 ABOUT_INFO *info = (ABOUT_INFO *)lParam;
574 const char* const *pstr = SHELL_People;
575 SendDlgItemMessage32A(hWnd, stc1, STM_SETICON32,info->hIcon, 0);
576 GetWindowText32A( hWnd, Template, sizeof(Template) );
577 sprintf( AppTitle, Template, info->szApp );
578 SetWindowText32A( hWnd, AppTitle );
579 SetWindowText32A( GetDlgItem32(hWnd, IDC_STATIC_TEXT),
580 info->szOtherStuff );
581 hWndCtl = GetDlgItem32(hWnd, IDC_LISTBOX);
582 SendMessage32A( hWndCtl, WM_SETREDRAW, 0, 0 );
583 SendMessage32A( hWndCtl, WM_SETFONT, hIconTitleFont, 0 );
586 SendMessage32A( hWndCtl, LB_ADDSTRING32,
587 (WPARAM32)-1, (LPARAM)*pstr );
590 SendMessage32A( hWndCtl, WM_SETREDRAW, 1, 0 );
599 HDC32 hDC = BeginPaint32( hWnd, &ps );
601 if( __get_dropline( hWnd, &rect ) )
602 GRAPH_DrawLines( hDC, (LPPOINT32)&rect, 1, GetStockObject32( BLACK_PEN ) );
603 EndPaint32( hWnd, &ps );
607 case WM_LBTRACKPOINT:
609 hWndCtl = GetDlgItem32(hWnd, IDC_LISTBOX);
610 if( (INT16)GetKeyState16( VK_CONTROL ) < 0 )
612 if( DragDetect32( hWndCtl, *((LPPOINT32)&lParam) ) )
614 INT32 idx = SendMessage32A( hWndCtl, LB_GETCURSEL32, 0, 0 );
617 INT32 length = SendMessage32A( hWndCtl, LB_GETTEXTLEN32, (WPARAM32)idx, 0 );
618 HGLOBAL16 hMemObj = GlobalAlloc16( GMEM_MOVEABLE, length + 1 );
619 char* pstr = (char*)GlobalLock16( hMemObj );
623 HCURSOR16 hCursor = LoadCursor16( 0, MAKEINTRESOURCE16(OCR_DRAGOBJECT) );
624 SendMessage32A( hWndCtl, LB_GETTEXT32, (WPARAM32)idx, (LPARAM)pstr );
625 SendMessage32A( hWndCtl, LB_DELETESTRING32, (WPARAM32)idx, 0 );
626 UpdateWindow32( hWndCtl );
627 if( !DragObject16((HWND16)hWnd, (HWND16)hWnd, DRAGOBJ_DATA, 0, (WORD)hMemObj, hCursor) )
628 SendMessage32A( hWndCtl, LB_ADDSTRING32, (WPARAM32)-1, (LPARAM)pstr );
630 if( hMemObj ) GlobalFree16( hMemObj );
636 case WM_QUERYDROPOBJECT:
639 LPDRAGINFO lpDragInfo = (LPDRAGINFO)PTR_SEG_TO_LIN((SEGPTR)lParam);
640 if( lpDragInfo && lpDragInfo->wFlags == DRAGOBJ_DATA )
643 if( __get_dropline( hWnd, &rect ) )
645 POINT32 pt = { lpDragInfo->pt.x, lpDragInfo->pt.y };
646 rect.bottom += DROP_FIELD_HEIGHT;
647 if( PtInRect32( &rect, pt ) )
649 SetWindowLong32A( hWnd, DWL_MSGRESULT, 1 );
660 LPDRAGINFO lpDragInfo = (LPDRAGINFO)PTR_SEG_TO_LIN((SEGPTR)lParam);
661 if( lpDragInfo && lpDragInfo->wFlags == DRAGOBJ_DATA && lpDragInfo->hList )
663 char* pstr = (char*)GlobalLock16( (HGLOBAL16)(lpDragInfo->hList) );
666 static char __appendix_str[] = " with";
668 hWndCtl = GetDlgItem32( hWnd, IDC_WINE_TEXT );
669 SendMessage32A( hWndCtl, WM_GETTEXT, 512, (LPARAM)Template );
670 if( !lstrncmp32A( Template, "WINE", 4 ) )
671 SetWindowText32A( GetDlgItem32(hWnd, IDC_STATIC_TEXT), Template );
674 char* pch = Template + strlen(Template) - strlen(__appendix_str);
676 SendMessage32A( GetDlgItem32(hWnd, IDC_LISTBOX), LB_ADDSTRING32,
677 (WPARAM32)-1, (LPARAM)Template );
680 lstrcpy32A( Template, pstr );
681 lstrcat32A( Template, __appendix_str );
682 SetWindowText32A( hWndCtl, Template );
684 SetWindowLong32A( hWnd, DWL_MSGRESULT, 1 );
694 EndDialog32(hWnd, TRUE);
703 /*************************************************************************
704 * AboutDlgProc16 (SHELL.33)
706 LRESULT WINAPI AboutDlgProc16( HWND16 hWnd, UINT16 msg, WPARAM16 wParam,
709 return AboutDlgProc32( hWnd, msg, wParam, lParam );
713 /*************************************************************************
714 * ShellAbout16 (SHELL.22)
716 BOOL16 WINAPI ShellAbout16( HWND16 hWnd, LPCSTR szApp, LPCSTR szOtherStuff,
719 return ShellAbout32A( hWnd, szApp, szOtherStuff, hIcon );
722 /*************************************************************************
723 * ShellAbout32A (SHELL32.243)
725 BOOL32 WINAPI ShellAbout32A( HWND32 hWnd, LPCSTR szApp, LPCSTR szOtherStuff,
730 info.szOtherStuff = szOtherStuff;
732 if (!hIcon) info.hIcon = LoadIcon16( 0, MAKEINTRESOURCE16(OIC_WINEICON) );
733 return DialogBoxIndirectParam32A( WIN_GetWindowInstance( hWnd ),
734 SYSRES_GetResPtr( SYSRES_DIALOG_SHELL_ABOUT_MSGBOX ),
735 hWnd, AboutDlgProc32, (LPARAM)&info );
739 /*************************************************************************
740 * ShellAbout32W (SHELL32.244)
742 BOOL32 WINAPI ShellAbout32W( HWND32 hWnd, LPCWSTR szApp, LPCWSTR szOtherStuff,
748 info.szApp = HEAP_strdupWtoA( GetProcessHeap(), 0, szApp );
749 info.szOtherStuff = HEAP_strdupWtoA( GetProcessHeap(), 0, szOtherStuff );
751 if (!hIcon) info.hIcon = LoadIcon16( 0, MAKEINTRESOURCE16(OIC_WINEICON) );
752 ret = DialogBoxIndirectParam32A( WIN_GetWindowInstance( hWnd ),
753 SYSRES_GetResPtr( SYSRES_DIALOG_SHELL_ABOUT_MSGBOX ),
754 hWnd, AboutDlgProc32, (LPARAM)&info );
755 HeapFree( GetProcessHeap(), 0, (LPSTR)info.szApp );
756 HeapFree( GetProcessHeap(), 0, (LPSTR)info.szOtherStuff );
760 /*************************************************************************
761 * Shell_NotifyIcon [SHELL32.249]
763 * This function is supposed to deal with the systray.
764 * Any ideas on how this is to be implimented?
766 BOOL32 WINAPI Shell_NotifyIcon( DWORD dwMessage,
767 PNOTIFYICONDATA pnid )
772 /*************************************************************************
773 * Shell_NotifyIcon [SHELL32.240]
775 * This function is supposed to deal with the systray.
776 * Any ideas on how this is to be implimented?
778 BOOL32 WINAPI Shell_NotifyIconA(DWORD dwMessage,
779 PNOTIFYICONDATA pnid )
784 /*************************************************************************
785 * SHELL_GetResourceTable
787 static DWORD SHELL_GetResourceTable(HFILE32 hFile,LPBYTE *retptr)
789 IMAGE_DOS_HEADER mz_header;
794 _llseek32( hFile, 0, SEEK_SET );
795 if ( (_lread32(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
796 (mz_header.e_magic != IMAGE_DOS_SIGNATURE)
800 _llseek32( hFile, mz_header.e_lfanew, SEEK_SET );
801 if (_lread32( hFile, magic, sizeof(magic) ) != sizeof(magic))
803 _llseek32( hFile, mz_header.e_lfanew, SEEK_SET);
805 if (*(DWORD*)magic == IMAGE_NT_SIGNATURE)
806 return IMAGE_NT_SIGNATURE;
807 if (*(WORD*)magic == IMAGE_OS2_SIGNATURE) {
808 IMAGE_OS2_HEADER ne_header;
809 LPBYTE pTypeInfo = (LPBYTE)-1;
811 if (_lread32(hFile,&ne_header,sizeof(ne_header))!=sizeof(ne_header))
814 if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return 0;
815 size = ne_header.rname_tab_offset - ne_header.resource_tab_offset;
816 if( size > sizeof(NE_TYPEINFO) )
818 pTypeInfo = (BYTE*)HeapAlloc( GetProcessHeap(), 0, size);
820 _llseek32(hFile, mz_header.e_lfanew+ne_header.resource_tab_offset, SEEK_SET);
821 if( _lread32( hFile, (char*)pTypeInfo, size) != size ) {
822 HeapFree( GetProcessHeap(), 0, pTypeInfo);
829 *retptr = (LPBYTE)-1;
830 return IMAGE_OS2_SIGNATURE; /* handles .ICO too */
834 /*************************************************************************
837 static HGLOBAL16 SHELL_LoadResource(HINSTANCE16 hInst, HFILE32 hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
840 HGLOBAL16 handle = DirectResAlloc( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
842 if( (ptr = (BYTE*)GlobalLock16( handle )) )
844 _llseek32( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
845 _lread32( hFile, (char*)ptr, pNInfo->length << sizeShift);
851 /*************************************************************************
854 static HGLOBAL16 ICO_LoadIcon(HINSTANCE16 hInst, HFILE32 hFile, LPicoICONDIRENTRY lpiIDE)
857 HGLOBAL16 handle = DirectResAlloc( hInst, 0x10, lpiIDE->dwBytesInRes);
859 if( (ptr = (BYTE*)GlobalLock16( handle )) )
861 _llseek32( hFile, lpiIDE->dwImageOffset, SEEK_SET);
862 _lread32( hFile, (char*)ptr, lpiIDE->dwBytesInRes);
868 /*************************************************************************
869 * ICO_GetIconDirectory
871 * Read .ico file and build phony ICONDIR struct for GetIconID
873 static HGLOBAL16 ICO_GetIconDirectory(HINSTANCE16 hInst, HFILE32 hFile, LPicoICONDIR* lplpiID )
875 WORD id[3]; /* idReserved, idType, idCount */
879 _llseek32( hFile, 0, SEEK_SET );
880 if( _lread32(hFile,(char*)id,sizeof(id)) != sizeof(id) ) return 0;
884 * - see http://www.microsoft.com/win32dev/ui/icons.htm
887 if( id[0] || id[1] != 1 || !id[2] ) return 0;
889 i = id[2]*sizeof(icoICONDIRENTRY) + sizeof(id);
891 lpiID = (LPicoICONDIR)HeapAlloc( GetProcessHeap(), 0, i);
893 if( _lread32(hFile,(char*)lpiID->idEntries,i) == i )
895 HGLOBAL16 handle = DirectResAlloc( hInst, 0x10,
896 id[2]*sizeof(ICONDIRENTRY) + sizeof(id) );
899 CURSORICONDIR* lpID = (CURSORICONDIR*)GlobalLock16( handle );
900 lpID->idReserved = lpiID->idReserved = id[0];
901 lpID->idType = lpiID->idType = id[1];
902 lpID->idCount = lpiID->idCount = id[2];
903 for( i=0; i < lpiID->idCount; i++ )
905 memcpy((void*)(lpID->idEntries + i),
906 (void*)(lpiID->idEntries + i), sizeof(ICONDIRENTRY) - 2);
907 lpID->idEntries[i].icon.wResId = i;
915 HeapFree( GetProcessHeap(), 0, lpiID);
919 /*************************************************************************
920 * InternalExtractIcon [SHELL.39]
922 * This abortion is called directly by Progman
924 HGLOBAL16 WINAPI InternalExtractIcon(HINSTANCE16 hInstance,
925 LPCSTR lpszExeFileName, UINT16 nIconIndex,
929 HGLOBAL16* RetPtr = NULL;
933 HFILE32 hFile = OpenFile32( lpszExeFileName, &ofs, OF_READ );
934 UINT16 iconDirCount = 0,iconCount = 0;
936 TRACE(reg,"(%04x,file %s,start %d,extract %d\n",
937 hInstance, lpszExeFileName, nIconIndex, n);
939 if( hFile == HFILE_ERROR32 || !n ) return 0;
941 hRet = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, sizeof(HICON16)*n);
942 RetPtr = (HICON16*)GlobalLock16(hRet);
944 *RetPtr = (n == 0xFFFF)? 0: 1; /* error return values */
946 sig = SHELL_GetResourceTable(hFile,&pData);
948 if(sig == IMAGE_OS2_SIGNATURE)
951 NE_TYPEINFO* pTInfo = (NE_TYPEINFO*)(pData + 2);
952 NE_NAMEINFO* pIconStorage = NULL;
953 NE_NAMEINFO* pIconDir = NULL;
954 LPicoICONDIR lpiID = NULL;
956 if( pData == (BYTE*)-1 )
958 /* check for .ICO file */
960 hIcon = ICO_GetIconDirectory(hInstance, hFile, &lpiID);
961 if( hIcon ) { iconDirCount = 1; iconCount = lpiID->idCount; }
963 else while( pTInfo->type_id && !(pIconStorage && pIconDir) )
965 /* find icon directory and icon repository */
967 if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON )
969 iconDirCount = pTInfo->count;
970 pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
971 TRACE(reg,"\tfound directory - %i icon families\n", iconDirCount);
973 if( pTInfo->type_id == NE_RSCTYPE_ICON )
975 iconCount = pTInfo->count;
976 pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
977 TRACE(reg,"\ttotal icons - %i\n", iconCount);
979 pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
982 /* load resources and create icons */
984 if( (pIconStorage && pIconDir) || lpiID )
985 if( nIconIndex == (UINT16)-1 ) RetPtr[0] = iconDirCount;
986 else if( nIconIndex < iconDirCount )
990 if( n > iconDirCount - nIconIndex ) n = iconDirCount - nIconIndex;
992 for( i = nIconIndex; i < nIconIndex + n; i++ )
994 /* .ICO files have only one icon directory */
997 hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + i,
999 RetPtr[i-nIconIndex] = GetIconID( hIcon, 3 );
1000 GlobalFree16(hIcon);
1003 for( icon = nIconIndex; icon < nIconIndex + n; icon++ )
1007 hIcon = ICO_LoadIcon( hInstance, hFile,
1008 lpiID->idEntries + RetPtr[icon-nIconIndex]);
1010 for( i = 0; i < iconCount; i++ )
1011 if( pIconStorage[i].id == (RetPtr[icon-nIconIndex] | 0x8000) )
1012 hIcon = SHELL_LoadResource( hInstance, hFile, pIconStorage + i,
1016 RetPtr[icon-nIconIndex] = LoadIconHandler( hIcon, TRUE );
1017 FarSetOwner( RetPtr[icon-nIconIndex], GetExePtr(hInstance) );
1020 RetPtr[icon-nIconIndex] = 0;
1023 if( lpiID ) HeapFree( GetProcessHeap(), 0, lpiID);
1024 else HeapFree( GetProcessHeap(), 0, pData);
1026 if( sig == IMAGE_NT_SIGNATURE)
1028 LPBYTE peimage,idata,igdata;
1029 LPIMAGE_DOS_HEADER dheader;
1030 LPIMAGE_NT_HEADERS pe_header;
1031 LPIMAGE_SECTION_HEADER pe_sections;
1032 LPIMAGE_RESOURCE_DIRECTORY rootresdir,iconresdir,icongroupresdir;
1033 LPIMAGE_RESOURCE_DATA_ENTRY idataent,igdataent;
1036 LPIMAGE_RESOURCE_DIRECTORY_ENTRY xresent;
1037 CURSORICONDIR **cids;
1039 fmapping = CreateFileMapping32A(hFile,NULL,PAGE_READONLY|SEC_COMMIT,0,0,NULL);
1040 if (fmapping == 0) { /* FIXME, INVALID_HANDLE_VALUE? */
1041 WARN(reg,"failed to create filemap.\n");
1045 peimage = MapViewOfFile(fmapping,FILE_MAP_READ,0,0,0);
1047 WARN(reg,"failed to mmap filemap.\n");
1048 CloseHandle(fmapping);
1052 dheader = (LPIMAGE_DOS_HEADER)peimage;
1053 /* it is a pe header, SHELL_GetResourceTable checked that */
1054 pe_header = (LPIMAGE_NT_HEADERS)(peimage+dheader->e_lfanew);
1055 /* probably makes problems with short PE headers... but I haven't seen
1058 pe_sections = (LPIMAGE_SECTION_HEADER)(((char*)pe_header)+sizeof(*pe_header));
1060 for (i=0;i<pe_header->FileHeader.NumberOfSections;i++) {
1061 if (pe_sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
1063 /* FIXME: doesn't work when the resources are not in a seperate section */
1064 if (pe_sections[i].VirtualAddress == pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress) {
1065 rootresdir = (LPIMAGE_RESOURCE_DIRECTORY)((char*)peimage+pe_sections[i].PointerToRawData);
1071 WARN(reg,"haven't found section for resource directory.\n");
1072 UnmapViewOfFile(peimage);
1073 CloseHandle(fmapping);
1077 icongroupresdir = GetResDirEntryW(rootresdir,RT_GROUP_ICON32W,
1078 (DWORD)rootresdir,FALSE);
1079 if (!icongroupresdir) {
1080 WARN(reg,"No Icongroupresourcedirectory!\n");
1081 UnmapViewOfFile(peimage);
1082 CloseHandle(fmapping);
1087 iconDirCount = icongroupresdir->NumberOfNamedEntries+icongroupresdir->NumberOfIdEntries;
1088 if( nIconIndex == (UINT16)-1 ) {
1089 RetPtr[0] = iconDirCount;
1090 UnmapViewOfFile(peimage);
1091 CloseHandle(fmapping);
1096 if (nIconIndex >= iconDirCount) {
1097 WARN(reg,"nIconIndex %d is larger than iconDirCount %d\n",
1098 nIconIndex,iconDirCount);
1099 UnmapViewOfFile(peimage);
1100 CloseHandle(fmapping);
1105 cids = (CURSORICONDIR**)HeapAlloc(GetProcessHeap(),0,n*sizeof(CURSORICONDIR*));
1107 /* caller just wanted the number of entries */
1109 xresent = (LPIMAGE_RESOURCE_DIRECTORY_ENTRY)(icongroupresdir+1);
1110 /* assure we don't get too much ... */
1111 if( n > iconDirCount - nIconIndex ) n = iconDirCount - nIconIndex;
1113 /* starting from specified index ... */
1114 xresent = xresent+nIconIndex;
1116 for (i=0;i<n;i++,xresent++) {
1118 LPIMAGE_RESOURCE_DIRECTORY resdir;
1120 /* go down this resource entry, name */
1121 resdir = (LPIMAGE_RESOURCE_DIRECTORY)((DWORD)rootresdir+(xresent->u2.s.OffsetToDirectory));
1122 /* default language (0) */
1123 resdir = GetResDirEntryW(resdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
1124 igdataent = (LPIMAGE_RESOURCE_DATA_ENTRY)resdir;
1126 /* lookup address in mapped image for virtual address */
1128 for (j=0;j<pe_header->FileHeader.NumberOfSections;j++) {
1129 if (igdataent->OffsetToData < pe_sections[j].VirtualAddress)
1131 if (igdataent->OffsetToData+igdataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
1133 igdata = peimage+(igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
1136 WARN(reg,"no matching real address for icongroup!\n");
1137 UnmapViewOfFile(peimage);
1138 CloseHandle(fmapping);
1143 cid = (CURSORICONDIR*)igdata;
1145 RetPtr[i] = LookupIconIdFromDirectoryEx32(igdata,TRUE,SYSMETRICS_CXICON,SYSMETRICS_CYICON,0);
1147 iconresdir=GetResDirEntryW(rootresdir,RT_ICON32W,
1148 (DWORD)rootresdir,FALSE);
1150 WARN(reg,"No Iconresourcedirectory!\n");
1151 UnmapViewOfFile(peimage);
1152 CloseHandle(fmapping);
1157 LPIMAGE_RESOURCE_DIRECTORY xresdir;
1159 xresdir = GetResDirEntryW(iconresdir,(LPWSTR)RetPtr[i],(DWORD)rootresdir,FALSE);
1160 xresdir = GetResDirEntryW(xresdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
1162 idataent = (LPIMAGE_RESOURCE_DATA_ENTRY)xresdir;
1165 /* map virtual to address in image */
1166 for (j=0;j<pe_header->FileHeader.NumberOfSections;j++) {
1167 if (idataent->OffsetToData < pe_sections[j].VirtualAddress)
1169 if (idataent->OffsetToData+idataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
1171 idata = peimage+(idataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
1174 WARN(reg,"no matching real address found for icondata!\n");
1178 RetPtr[i] = CreateIconFromResourceEx32(idata,idataent->Size,TRUE,0x00030000,SYSMETRICS_CXICON,SYSMETRICS_CYICON,0);
1180 UnmapViewOfFile(peimage);
1181 CloseHandle(fmapping);
1186 /* return array with icon handles */
1191 /*************************************************************************
1192 * ExtractIcon16 (SHELL.34)
1194 HICON16 WINAPI ExtractIcon16( HINSTANCE16 hInstance, LPCSTR lpszExeFileName,
1197 return ExtractIcon32A( hInstance, lpszExeFileName, nIconIndex );
1201 /*************************************************************************
1202 * ExtractIcon32A (SHELL32.133)
1204 HICON32 WINAPI ExtractIcon32A( HINSTANCE32 hInstance, LPCSTR lpszExeFileName,
1207 HGLOBAL16 handle = InternalExtractIcon(hInstance,lpszExeFileName,nIconIndex, 1);
1211 HICON16* ptr = (HICON16*)GlobalLock16(handle);
1212 HICON16 hIcon = *ptr;
1214 GlobalFree16(handle);
1220 /*************************************************************************
1221 * ExtractIcon32W (SHELL32.180)
1223 HICON32 WINAPI ExtractIcon32W( HINSTANCE32 hInstance, LPCWSTR lpszExeFileName,
1226 LPSTR exefn = HEAP_strdupWtoA(GetProcessHeap(),0,lpszExeFileName);
1227 HICON32 ret = ExtractIcon32A(hInstance,exefn,nIconIndex);
1229 HeapFree(GetProcessHeap(),0,exefn);
1234 /*************************************************************************
1235 * ExtractAssociatedIcon [SHELL.36]
1237 * Return icon for given file (either from file itself or from associated
1238 * executable) and patch parameters if needed.
1240 HICON32 WINAPI ExtractAssociatedIcon32A(HINSTANCE32 hInst,LPSTR lpIconPath,
1243 return ExtractAssociatedIcon16(hInst,lpIconPath,lpiIcon);
1246 HICON16 WINAPI ExtractAssociatedIcon16(HINSTANCE16 hInst,LPSTR lpIconPath,
1249 HICON16 hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
1254 if( hIcon == 1 ) /* no icons found in given file */
1256 char tempPath[0x80];
1257 UINT16 uRet = FindExecutable16(lpIconPath,NULL,tempPath);
1259 if( uRet > 32 && tempPath[0] )
1261 strcpy(lpIconPath,tempPath);
1262 hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
1264 if( hIcon > 2 ) return hIcon;
1270 *lpiIcon = 2; /* MSDOS icon - we found .exe but no icons in it */
1272 *lpiIcon = 6; /* generic icon - found nothing */
1274 GetModuleFileName16(hInst, lpIconPath, 0x80);
1275 hIcon = LoadIcon16( hInst, MAKEINTRESOURCE16(*lpiIcon));
1281 /*************************************************************************
1282 * FindEnvironmentString [SHELL.38]
1284 * Returns a pointer into the DOS environment... Ugh.
1286 LPSTR SHELL_FindString(LPSTR lpEnv, LPCSTR entry)
1288 UINT16 l = strlen(entry);
1289 for( ; *lpEnv ; lpEnv+=strlen(lpEnv)+1 )
1291 if( lstrncmpi32A(lpEnv, entry, l) ) continue;
1294 return (lpEnv + l); /* empty entry */
1295 else if ( *(lpEnv+l)== '=' )
1296 return (lpEnv + l + 1);
1301 SEGPTR WINAPI FindEnvironmentString(LPSTR str)
1303 SEGPTR spEnv = GetDOSEnvironment();
1304 LPSTR lpEnv = (LPSTR)PTR_SEG_TO_LIN(spEnv);
1306 LPSTR lpString = (spEnv)?SHELL_FindString(lpEnv, str):NULL;
1308 if( lpString ) /* offset should be small enough */
1309 return spEnv + (lpString - lpEnv);
1311 return (SEGPTR)NULL;
1314 /*************************************************************************
1315 * DoEnvironmentSubst [SHELL.37]
1317 * Replace %KEYWORD% in the str with the value of variable KEYWORD
1318 * from "DOS" environment.
1320 DWORD WINAPI DoEnvironmentSubst(LPSTR str,WORD length)
1322 LPSTR lpEnv = (LPSTR)PTR_SEG_TO_LIN(GetDOSEnvironment());
1323 LPSTR lpBuffer = (LPSTR)HeapAlloc( GetProcessHeap(), 0, length);
1325 LPSTR lpbstr = lpBuffer;
1327 CharToOem32A(str,str);
1329 TRACE(reg,"accept %s\n", str);
1331 while( *lpstr && lpbstr - lpBuffer < length )
1333 LPSTR lpend = lpstr;
1337 do { lpend++; } while( *lpend && *lpend != '%' );
1338 if( *lpend == '%' && lpend - lpstr > 1 ) /* found key */
1342 lpKey = SHELL_FindString(lpEnv, lpstr+1);
1343 if( lpKey ) /* found key value */
1345 int l = strlen(lpKey);
1347 if( l > length - (lpbstr - lpBuffer) - 1 )
1349 WARN(reg,"Env subst aborted - string too short\n");
1353 strcpy(lpbstr, lpKey);
1360 else break; /* back off and whine */
1365 *lpbstr++ = *lpstr++;
1369 if( lpstr - str == strlen(str) )
1371 strncpy(str, lpBuffer, length);
1377 TRACE(reg," return %s\n", str);
1379 OemToChar32A(str,str);
1380 HeapFree( GetProcessHeap(), 0, lpBuffer);
1382 /* Return str length in the LOWORD
1383 * and 1 in HIWORD if subst was successful.
1385 return (DWORD)MAKELONG(strlen(str), length);
1388 /*************************************************************************
1389 * ShellHookProc [SHELL.103]
1390 * System-wide WH_SHELL hook.
1392 LRESULT WINAPI ShellHookProc(INT16 code, WPARAM16 wParam, LPARAM lParam)
1394 TRACE(reg,"%i, %04x, %08x\n", code, wParam,
1396 if( SHELL_hHook && SHELL_hWnd )
1401 case HSHELL_WINDOWCREATED: uMsg = uMsgWndCreated; break;
1402 case HSHELL_WINDOWDESTROYED: uMsg = uMsgWndDestroyed; break;
1403 case HSHELL_ACTIVATESHELLWINDOW: uMsg = uMsgShellActivate;
1405 PostMessage16( SHELL_hWnd, uMsg, wParam, 0 );
1407 return CallNextHookEx16( WH_SHELL, code, wParam, lParam );
1410 /*************************************************************************
1411 * RegisterShellHook [SHELL.102]
1413 BOOL32 WINAPI RegisterShellHook(HWND16 hWnd, UINT16 uAction)
1415 TRACE(reg,"%04x [%u]\n", hWnd, uAction );
1419 case 2: /* register hWnd as a shell window */
1423 HMODULE16 hShell = GetModuleHandle16( "SHELL" );
1425 SHELL_hHook = SetWindowsHookEx16( WH_SHELL, ShellHookProc,
1429 uMsgWndCreated = RegisterWindowMessage32A( lpstrMsgWndCreated );
1430 uMsgWndDestroyed = RegisterWindowMessage32A( lpstrMsgWndDestroyed );
1431 uMsgShellActivate = RegisterWindowMessage32A( lpstrMsgShellActivate );
1433 else WARN(reg, "unable to install ShellHookProc()!\n");
1436 if( SHELL_hHook ) return ((SHELL_hWnd = hWnd) != 0);
1441 WARN(reg, "unknown code %i\n", uAction );
1451 /*************************************************************************
1452 * SHGetFileInfoA [SHELL32.218]
1454 DWORD WINAPI SHGetFileInfo32A(LPCSTR path,DWORD dwFileAttributes,
1455 SHFILEINFO32A *psfi, UINT32 sizeofpsfi,
1458 FIXME(shell,"(%s,0x%08lx,%p,%d,0x%08x): stub\n",
1459 path,dwFileAttributes,psfi,sizeofpsfi,flags);
1463 /*************************************************************************
1464 * SHAppBarMessage32 [SHELL32.207]
1466 UINT32 WINAPI SHAppBarMessage32(DWORD msg, PAPPBARDATA data)
1468 FIXME(shell,"(0x%08lx,%p): stub\n", msg, data);
1472 case ABM_GETAUTOHIDEBAR:
1474 case ABM_GETTASKBARPOS:
1478 case ABM_SETAUTOHIDEBAR:
1480 case ABM_WINDOWPOSCHANGED:
1487 /*************************************************************************
1488 * CommandLineToArgvW [SHELL32.7]
1490 LPWSTR* WINAPI CommandLineToArgvW(LPWSTR cmdline,LPDWORD numargs)
1495 /* to get writeable copy */
1496 cmdline = HEAP_strdupW( GetProcessHeap(), 0, cmdline);
1503 while (*s && *s==0x0020)
1509 argv=(LPWSTR*)HeapAlloc( GetProcessHeap(), 0, sizeof(LPWSTR)*(i+1) );
1515 argv[i++]=HEAP_strdupW( GetProcessHeap(), 0, t );
1517 while (*s && *s==0x0020)
1528 argv[i++]=(LPWSTR)HEAP_strdupW( GetProcessHeap(), 0, t );
1529 HeapFree( GetProcessHeap(), 0, cmdline );
1535 /*************************************************************************
1536 * Control_RunDLL [SHELL32.12]
1538 * Wild speculation in the following!
1540 * http://premium.microsoft.com/msdn/library/techart/msdn193.htm
1543 void WINAPI Control_RunDLL (HWND32 hwnd, LPCVOID code, LPCSTR cmd, DWORD arg4)
1545 TRACE(exec, "(%08x, %p, \"%s\", %08lx)\n",
1546 hwnd, code ? code : "(null)", cmd ? cmd : "(null)", arg4);
1549 /*************************************************************************
1552 void WINAPI FreeIconList( DWORD dw )
1554 FIXME(reg, "empty stub\n" );
1557 /*************************************************************************
1558 * SHELL32_DllGetClassObject [SHELL32.14]
1560 * http://premium.microsoft.com/msdn/library/sdkdoc/api2_48fo.htm
1562 DWORD WINAPI SHELL32_DllGetClassObject(REFCLSID rclsid,REFIID iid,LPVOID *ppv)
1564 char xclsid[50],xiid[50];
1565 HRESULT hres = E_OUTOFMEMORY;
1568 WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1569 WINE_StringFromCLSID((LPCLSID)iid,xiid);
1570 TRACE(shell,"(%s,%s,%p)\n",xclsid,xiid,ppv);
1573 /* SDK example code looks like this:
1575 HRESULT hres = E_OUTOFMEMORY;
1578 CClassFactory *pClassFactory = new CClassFactory(rclsid);
1580 if (pClassFactory) {
1581 hRes = pClassFactory->QueryInterface(riid,ppv);
1582 pClassFactory->Release();
1586 * The magic of the whole stuff is still unclear to me, so just hack together
1590 if (!memcmp(rclsid,&CLSID_ShellDesktop,sizeof(CLSID_ShellDesktop))) {
1591 TRACE(shell," requested CLSID_ShellDesktop, creating it.\n");
1592 *ppv = IShellFolder_Constructor();
1593 FIXME(shell,"Initialize this folder to be the shell desktop folder\n");
1597 FIXME(shell, " -> clsid not found. returning E_OUTOFMEMORY.\n");
1601 /*************************************************************************
1602 * SHGetDesktopFolder [SHELL32.216]
1603 * returns the interface to the shell desktop folder.
1605 * [SDK header win95/shlobj.h: This is equivalent to call CoCreateInstance with
1606 * CLSID_ShellDesktop.
1608 * CoCreateInstance(CLSID_Desktop, NULL,
1609 * CLSCTX_INPROC, IID_IShellFolder, &pshf);
1611 * So what we are doing is currently wrong....
1613 DWORD WINAPI SHGetDesktopFolder(LPSHELLFOLDER *shellfolder) {
1614 *shellfolder = IShellFolder_Constructor();
1618 /*************************************************************************
1619 * SHGetMalloc [SHELL32.220]
1620 * returns the interface to shell malloc.
1622 * [SDK header win95/shlobj.h:
1623 * equivalent to: #define SHGetMalloc(ppmem) CoGetMalloc(MEMCTX_TASK, ppmem)
1625 * What we are currently doing is not very wrong, since we always use the same
1626 * heap (ProcessHeap).
1628 DWORD WINAPI SHGetMalloc(LPMALLOC32 *lpmal) {
1629 TRACE(shell,"(%p)\n", lpmal);
1630 return CoGetMalloc32(0,lpmal);
1633 /*************************************************************************
1634 * SHGetSpecialFolderLocation [SHELL32.223]
1635 * returns the PIDL of a special folder
1637 * nFolder is a CSIDL_xxxxx.
1639 HRESULT WINAPI SHGetSpecialFolderLocation(HWND32 hwndOwner, INT32 nFolder, LPITEMIDLIST * ppidl) {
1640 FIXME(shell,"(%04x,%d,%p),stub!\n", hwndOwner,nFolder,ppidl);
1641 *ppidl = (LPITEMIDLIST)HeapAlloc(GetProcessHeap(),0,2*sizeof(ITEMIDLIST));
1642 FIXME(shell, "we return only the empty ITEMIDLIST currently.\n");
1643 (*ppidl)->mkid.cb = 0;
1647 /*************************************************************************
1648 * SHGetPathFromIDList [SHELL32.221]
1649 * returns the path from a passed PIDL.
1651 BOOL32 WINAPI SHGetPathFromIDList(LPCITEMIDLIST pidl,LPSTR pszPath) {
1652 FIXME(shell,"(%p,%p),stub!\n",pidl,pszPath);
1653 lstrcpy32A(pszPath,"E:\\"); /* FIXME */