source: trunk/src/shell32/shell32_odin.cpp

Last change on this file was 21963, checked in by dmik, 14 years ago

Print version number in About Odin dialog.

File size: 40.2 KB
Line 
1/* $Id: shell32_odin.cpp,v 1.5 2002-06-09 12:41:22 sandervl Exp $ */
2
3/*
4 * Win32 SHELL32 for OS/2
5 *
6 * Copyright 1999 Patrick Haller (haller@zebra.fh-weingarten.de)
7 * Project Odin Software License can be found in LICENSE.TXT
8 *
9 * Shell basics
10 *
11 * 1998 Marcus Meissner
12 * 1998 Juergen Schmied (jsch) * <juergen.schmied@metronet.de>
13 *
14 */
15
16/*****************************************************************************
17 * Includes *
18 *****************************************************************************/
19
20#include <odin.h>
21#include <odinwrap.h>
22#include <os2sel.h>
23
24#include <stdlib.h>
25#include <string.h>
26
27#define CINTERFACE
28
29#include "winerror.h"
30#include "heap.h"
31#include "resource.h"
32#include "dlgs.h"
33#include "sysmetrics.h"
34#include "debugtools.h"
35#include "winreg.h"
36#include "authors.h"
37#include "winversion.h"
38
39#include "shellapi.h"
40#include "pidl.h"
41
42#include "shlobj.h"
43#include "shell32_main.h"
44#include "shlguid.h"
45#include "undocshell.h"
46#include "shpolicy.h"
47#include "shlwapi.h"
48
49#include <heapstring.h>
50#include <misc.h>
51#include <peexe.h>
52#include <neexe.h>
53#include <cursoricon.h>
54#include <ctype.h>
55#include <module.h>
56
57#include "os2_integration.h"
58#include "odinbuild.h"
59
60
61/*****************************************************************************
62 * Local Variables *
63 *****************************************************************************/
64
65ODINDEBUGCHANNEL(SHELL32-MAIN)
66
67typedef struct
68{ LPCSTR szApp;
69 LPCSTR szOtherStuff;
70 HICON hIcon;
71} ABOUT_INFO;
72
73#define IDC_STATIC_TEXT 100
74#define IDC_LISTBOX 99
75#define IDC_WINE_TEXT 98
76#define IDC_ODIN_TEXT 98
77
78#define DROP_FIELD_TOP (-15)
79#define DROP_FIELD_HEIGHT 15
80
81extern HICON hIconTitleFont;
82
83static BOOL __get_dropline( HWND hWnd, LPRECT lprect )
84{ HWND hWndCtl = GetDlgItem(hWnd, IDC_WINE_TEXT);
85 if( hWndCtl )
86 { GetWindowRect( hWndCtl, lprect );
87 MapWindowPoints( 0, hWnd, (LPPOINT)lprect, 2 );
88 lprect->bottom = (lprect->top += DROP_FIELD_TOP);
89 return TRUE;
90 }
91 return FALSE;
92}
93
94
95/*************************************************************************
96 * AboutDlgProc32 (internal)
97 */
98#define IDC_ODINLOGO 2001
99#define IDC_ODINBUILDNR 98
100#define IDB_ODINLOGO 5555
101
102BOOL WINAPI AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam,
103 LPARAM lParam )
104{
105 HWND hWndCtl;
106 char Template[512], AppTitle[512];
107
108 switch(msg)
109 {
110 case WM_INITDIALOG:
111 {
112 ABOUT_INFO *info = (ABOUT_INFO *)lParam;
113 if(info)
114 {
115 const char* const *pstr = SHELL_People;
116
117 SendDlgItemMessageA(hWnd, stc1, STM_SETICON,info->hIcon, 0);
118 GetWindowTextA( hWnd, Template, sizeof(Template) );
119 sprintf( AppTitle, Template, info->szApp );
120 SetWindowTextA( hWnd, AppTitle );
121 SetWindowTextA( GetDlgItem(hWnd, IDC_STATIC_TEXT), info->szOtherStuff );
122
123 GetWindowTextA( GetDlgItem(hWnd, IDC_ODINBUILDNR), Template, sizeof(Template) );
124 sprintf( AppTitle, Template, ODIN32_VERSION_MAJOR,
125 ODIN32_VERSION_MINOR, ODIN32_BUILD_NR, __DATE__);
126 SetWindowTextA( GetDlgItem(hWnd, IDC_ODINBUILDNR), AppTitle);
127 HWND hwndOdinLogo = GetDlgItem(hWnd, IDC_ODINLOGO);
128 if(hwndOdinLogo) {
129 HBITMAP hBitmap = LoadBitmapA(shell32_hInstance, MAKEINTRESOURCEA(IDB_ODINLOGO));
130 SendMessageA(hwndOdinLogo, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap);
131 }
132
133 hWndCtl = GetDlgItem(hWnd, IDC_LISTBOX);
134 SendMessageA( hWndCtl, WM_SETREDRAW, 0, 0 );
135#if 0 //CB: not used (hIconTitleFont not valid!!!), default font is ok
136 SendMessageA( hWndCtl, WM_SETFONT, hIconTitleFont, 0 );
137#endif
138 while (*pstr)
139 {
140 SendMessageA( hWndCtl, LB_ADDSTRING, (WPARAM)-1, (LPARAM)*pstr );
141 pstr++;
142 }
143 SendMessageA( hWndCtl, WM_SETREDRAW, 1, 0 );
144 }
145 return 1;
146 }
147
148 case WM_PAINT:
149 {
150 RECT rect;
151 PAINTSTRUCT ps;
152 HDC hDC = BeginPaint( hWnd, &ps );
153
154 if( __get_dropline( hWnd, &rect ) ) {
155 SelectObject( hDC, GetStockObject( BLACK_PEN ) );
156 MoveToEx( hDC, rect.left, rect.top, NULL );
157 LineTo( hDC, rect.right, rect.bottom );
158 }
159 EndPaint( hWnd, &ps );
160 break;
161 }
162
163 case WM_LBTRACKPOINT:
164 hWndCtl = GetDlgItem(hWnd, IDC_LISTBOX);
165 if( (INT)GetKeyState( VK_CONTROL ) < 0 )
166 { if( DragDetect( hWndCtl, *((LPPOINT)&lParam) ) )
167 { INT idx = SendMessageA( hWndCtl, LB_GETCURSEL, 0, 0 );
168 if( idx != -1 )
169 { INT length = SendMessageA( hWndCtl, LB_GETTEXTLEN, (WPARAM)idx, 0 );
170 HGLOBAL hMemObj = GlobalAlloc( GMEM_MOVEABLE, length + 1 );
171 char* pstr = (char*)GlobalLock( hMemObj );
172
173 if( pstr )
174 { HCURSOR hCursor = LoadCursorA( 0, (LPCSTR)OCR_DRAGOBJECT );
175 SendMessageA( hWndCtl, LB_GETTEXT, (WPARAM)idx, (LPARAM)pstr );
176 SendMessageA( hWndCtl, LB_DELETESTRING, (WPARAM)idx, 0 );
177 UpdateWindow( hWndCtl );
178
179 if( !DragObject(hWnd, hWnd, DRAGOBJ_DATA, hMemObj, hCursor) )
180 SendMessageA( hWndCtl, LB_ADDSTRING, (WPARAM)-1, (LPARAM)pstr );
181 }
182 if( hMemObj )
183 GlobalFree( hMemObj );
184 }
185 }
186 }
187 break;
188
189 case WM_QUERYDROPOBJECT:
190 if( wParam == 0 )
191 { LPDRAGINFO lpDragInfo = (LPDRAGINFO)lParam;
192 if( lpDragInfo && lpDragInfo->wFlags == DRAGOBJ_DATA )
193 { RECT rect;
194 if( __get_dropline( hWnd, &rect ) )
195 { POINT pt;
196 pt.x=lpDragInfo->pt.x;
197 pt.x=lpDragInfo->pt.y;
198 rect.bottom += DROP_FIELD_HEIGHT;
199 if( PtInRect( &rect, pt ) )
200 { SetWindowLongA( hWnd, DWL_MSGRESULT, 1 );
201 return TRUE;
202 }
203 }
204 }
205 }
206 break;
207
208 case WM_DROPOBJECT:
209 if( wParam == hWnd )
210 { LPDRAGINFO lpDragInfo = (LPDRAGINFO)lParam;
211 if( lpDragInfo && lpDragInfo->wFlags == DRAGOBJ_DATA && lpDragInfo->hList )
212 { char* pstr = (char*)GlobalLock( (HGLOBAL)(lpDragInfo->hList) );
213 if( pstr )
214 { static char __appendix_str[] = " with";
215
216 hWndCtl = GetDlgItem( hWnd, IDC_ODIN_TEXT );
217 SendMessageA( hWndCtl, WM_GETTEXT, 512, (LPARAM)Template );
218 if( !strncmp( Template, "ODIN", 4 ) )
219 SetWindowTextA( GetDlgItem(hWnd, IDC_STATIC_TEXT), Template );
220 else
221 { char* pch = Template + strlen(Template) - strlen(__appendix_str);
222 *pch = '\0';
223 SendMessageA( GetDlgItem(hWnd, IDC_LISTBOX), LB_ADDSTRING,
224 (WPARAM)-1, (LPARAM)Template );
225 }
226
227 strcpy( Template, pstr );
228 strcat( Template, __appendix_str );
229 SetWindowTextA( hWndCtl, Template );
230 SetWindowLongA( hWnd, DWL_MSGRESULT, 1 );
231 return TRUE;
232 }
233 }
234 }
235 break;
236
237 case WM_COMMAND:
238 if (wParam == IDOK)
239 {
240 EndDialog(hWnd, TRUE);
241 return TRUE;
242 }
243 break;
244
245 case WM_CLOSE:
246 EndDialog(hWnd, TRUE);
247 break;
248 }
249 return 0;
250}
251
252
253/*************************************************************************
254 * ShellAboutA [SHELL32.243]
255 */
256
257BOOL WIN32API ShellAboutA(HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff,
258 HICON hIcon )
259{ ABOUT_INFO info;
260 HRSRC hRes;
261 LPVOID dlgTemplate;
262
263 if(!(hRes = FindResourceA(shell32_hInstance, "SHELL_ABOUT_MSGBOX", RT_DIALOGA)))
264 return FALSE;
265 if(!(dlgTemplate = (LPVOID)LoadResource(shell32_hInstance, hRes)))
266 return FALSE;
267
268 info.szApp = szApp;
269 info.szOtherStuff = szOtherStuff;
270 info.hIcon = hIcon;
271 if (!hIcon) info.hIcon = LoadIconA( 0, MAKEINTRESOURCEA(OIC_ODINICON) );
272 return DialogBoxIndirectParamA( GetWindowLongA( hWnd, GWL_HINSTANCE ),
273 (DLGTEMPLATE*)dlgTemplate , hWnd, AboutDlgProc, (LPARAM)&info );
274}
275
276
277/*************************************************************************
278 * ShellAboutW [SHELL32.244]
279 */
280BOOL WIN32API ShellAboutW(HWND hWnd, LPCWSTR szApp, LPCWSTR szOtherStuff,
281 HICON hIcon )
282{ INT ret;
283 ABOUT_INFO info;
284 HRSRC hRes;
285 LPVOID dlgTemplate;
286
287 if(!(hRes = FindResourceA(shell32_hInstance, "SHELL_ABOUT_MSGBOX", RT_DIALOGA)))
288 return FALSE;
289 if(!(dlgTemplate = (LPVOID)LoadResource(shell32_hInstance, hRes)))
290 return FALSE;
291
292 info.szApp = HEAP_strdupWtoA( GetProcessHeap(), 0, szApp );
293 info.szOtherStuff = HEAP_strdupWtoA( GetProcessHeap(), 0, szOtherStuff );
294 info.hIcon = hIcon;
295 if (!hIcon) info.hIcon = LoadIconA( 0, MAKEINTRESOURCEA(OIC_ODINICON) );
296 ret = DialogBoxIndirectParamA( GetWindowLongA( hWnd, GWL_HINSTANCE ),
297 (DLGTEMPLATE*)dlgTemplate, hWnd, AboutDlgProc, (LPARAM)&info );
298 HeapFree( GetProcessHeap(), 0, (LPSTR)info.szApp );
299 HeapFree( GetProcessHeap(), 0, (LPSTR)info.szOtherStuff );
300 return ret;
301}
302
303/*************************************************************************
304 * ExtractAssociatedIcon [SHELL.36]
305 *
306 * Return icon for given file (either from file itself or from associated
307 * executable) and patch parameters if needed.
308 */
309HICON WIN32API ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath,
310 LPWORD lpiIcon)
311{
312 HICON hIcon;
313
314 hIcon = ExtractIconA(hInst, lpIconPath, *lpiIcon);
315
316 if( hIcon < 2 )
317 { if( hIcon == 1 ) /* no icons found in given file */
318 { char tempPath[0x104];
319 UINT uRet = FindExecutableA(lpIconPath,NULL,tempPath);
320
321 if( uRet > 32 && tempPath[0] )
322 { strcpy(lpIconPath,tempPath);
323 hIcon = ExtractIconA(hInst, lpIconPath, *lpiIcon);
324 if( hIcon > 2 )
325 return hIcon;
326 }
327 else hIcon = 0;
328 }
329
330 if( hIcon == 1 )
331 *lpiIcon = 2; /* MSDOS icon - we found .exe but no icons in it */
332 else
333 *lpiIcon = 6; /* generic icon - found nothing */
334
335 GetModuleFileNameA(hInst, lpIconPath, 0x80);
336 hIcon = LoadIconA( hInst, (LPCSTR)*lpiIcon);
337 }
338 return hIcon;
339}
340
341#if 0 //CB: DirectResAlloc16 not yet ported
342/*************************************************************************
343 * SHELL_LoadResource
344 */
345static HGLOBAL SHELL_LoadResource(HINSTANCE hInst, HFILE hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
346{ BYTE* ptr;
347 HGLOBAL handle = DirectResAlloc( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
348
349 TRACE("\n");
350
351 if( (ptr = (BYTE*)GlobalLock( handle )) )
352 { _llseek( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
353 _lread( hFile, (char*)ptr, pNInfo->length << sizeShift);
354 return handle;
355 }
356 return 0;
357}
358
359/*************************************************************************
360 * ICO_LoadIcon
361 */
362static HGLOBAL ICO_LoadIcon(HINSTANCE hInst, HFILE hFile, LPicoICONDIRENTRY lpiIDE)
363{ BYTE* ptr;
364 HGLOBAL handle = DirectResAlloc( hInst, 0x10, lpiIDE->dwBytesInRes);
365 TRACE("\n");
366 if( (ptr = (BYTE*)GlobalLock( handle )) )
367 { _llseek( hFile, lpiIDE->dwImageOffset, SEEK_SET);
368 _lread( hFile, (char*)ptr, lpiIDE->dwBytesInRes);
369 return handle;
370 }
371 return 0;
372}
373
374/*************************************************************************
375 * ICO_GetIconDirectory
376 *
377 * Read .ico file and build phony ICONDIR struct for GetIconID
378 */
379static HGLOBAL ICO_GetIconDirectory(HINSTANCE hInst, HFILE hFile, LPicoICONDIR* lplpiID )
380{ WORD id[3]; /* idReserved, idType, idCount */
381 LPicoICONDIR lpiID;
382 int i;
383
384 TRACE("\n");
385 _llseek( hFile, 0, SEEK_SET );
386 if( _lread(hFile,(char*)id,sizeof(id)) != sizeof(id) ) return 0;
387
388 /* check .ICO header
389 *
390 * - see http://www.microsoft.com/win32dev/ui/icons.htm
391 */
392
393 if( id[0] || id[1] != 1 || !id[2] ) return 0;
394
395 i = id[2]*sizeof(icoICONDIRENTRY) ;
396
397 lpiID = (LPicoICONDIR)HeapAlloc( GetProcessHeap(), 0, i + sizeof(id));
398
399 if( _lread(hFile,(char*)lpiID->idEntries,i) == i )
400 { HGLOBAL handle = DirectResAlloc( hInst, 0x10,
401 id[2]*sizeof(CURSORICONDIRENTRY) + sizeof(id) );
402 if( handle )
403 { CURSORICONDIR* lpID = (CURSORICONDIR*)GlobalLock( handle );
404 lpID->idReserved = lpiID->idReserved = id[0];
405 lpID->idType = lpiID->idType = id[1];
406 lpID->idCount = lpiID->idCount = id[2];
407 for( i=0; i < lpiID->idCount; i++ )
408 { memcpy((void*)(lpID->idEntries + i),
409 (void*)(lpiID->idEntries + i), sizeof(CURSORICONDIRENTRY) - 2);
410 lpID->idEntries[i].wResId = i;
411 }
412 *lplpiID = lpiID;
413 return handle;
414 }
415 }
416 /* fail */
417
418 HeapFree( GetProcessHeap(), 0, lpiID);
419 return 0;
420}
421#endif
422
423//iconcache.c
424DWORD SHELL_GetResourceTable(HFILE hFile, LPBYTE *retptr);
425
426//CB: from loader/pe_resource.c
427
428/**********************************************************************
429 * GetResDirEntryW
430 *
431 * Helper function - goes down one level of PE resource tree
432 *
433 */
434PIMAGE_RESOURCE_DIRECTORY GetResDirEntryW(PIMAGE_RESOURCE_DIRECTORY resdirptr,
435 LPCWSTR name,DWORD root,
436 BOOL allowdefault)
437{
438 int entrynum;
439 PIMAGE_RESOURCE_DIRECTORY_ENTRY entryTable;
440 int namelen;
441
442 if (HIWORD(name)) {
443 if (name[0]=='#') {
444 char buf[10];
445
446 lstrcpynWtoA(buf,name+1,10);
447 return GetResDirEntryW(resdirptr,(LPCWSTR)atoi(buf),root,allowdefault);
448 }
449 entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (
450 (BYTE *) resdirptr +
451 sizeof(IMAGE_RESOURCE_DIRECTORY));
452 namelen = lstrlenW(name);
453 for (entrynum = 0; entrynum < resdirptr->NumberOfNamedEntries; entrynum++)
454 {
455 PIMAGE_RESOURCE_DIR_STRING_U str =
456 (PIMAGE_RESOURCE_DIR_STRING_U) (root +
457 entryTable[entrynum].u1.s.NameOffset);
458 if(namelen != str->Length)
459 continue;
460 if(lstrncmpiW(name,str->NameString,str->Length)==0)
461 return (PIMAGE_RESOURCE_DIRECTORY) (
462 root +
463 entryTable[entrynum].u2.s.OffsetToDirectory);
464 }
465 return NULL;
466 } else {
467 entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (
468 (BYTE *) resdirptr +
469 sizeof(IMAGE_RESOURCE_DIRECTORY) +
470 resdirptr->NumberOfNamedEntries * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
471 for (entrynum = 0; entrynum < resdirptr->NumberOfIdEntries; entrynum++)
472 if ((DWORD)entryTable[entrynum].u1.Name == (DWORD)name)
473 return (PIMAGE_RESOURCE_DIRECTORY) (
474 root +
475 entryTable[entrynum].u2.s.OffsetToDirectory);
476 /* just use first entry if no default can be found */
477 if (allowdefault && !name && resdirptr->NumberOfIdEntries)
478 return (PIMAGE_RESOURCE_DIRECTORY) (
479 root +
480 entryTable[0].u2.s.OffsetToDirectory);
481 return NULL;
482 }
483}
484
485/*************************************************************************
486 * InternalExtractIcon [SHELL.39]
487 *
488 * This abortion is called directly by Progman
489 */
490HGLOBAL WINAPI InternalExtractIcon(HINSTANCE hInstance,
491 LPCSTR lpszExeFileName, UINT nIconIndex, WORD n )
492{ HGLOBAL hRet = 0;
493 HGLOBAL* RetPtr = NULL;
494 LPBYTE pData;
495 OFSTRUCT ofs;
496 DWORD sig;
497 HFILE hFile = OpenFile( lpszExeFileName, &ofs, OF_READ );
498 UINT iconDirCount = 0,iconCount = 0;
499 LPBYTE peimage;
500 HANDLE fmapping;
501
502 TRACE("(%04x,file %s,start %d,extract %d\n",
503 hInstance, lpszExeFileName, nIconIndex, n);
504
505 if( hFile == HFILE_ERROR || !n )
506 return 0;
507
508 hRet = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(HICON16)*n);
509 RetPtr = (HGLOBAL*)GlobalLock(hRet);
510
511 *RetPtr = (n == 0xFFFF)? 0: 1; /* error return values */
512
513 sig = SHELL_GetResourceTable(hFile,&pData);
514#if 0 //CB: some functions not (yet) supported
515 if( sig==IMAGE_OS2_SIGNATURE || sig==1 ) /* .ICO file */
516 { HICON hIcon = 0;
517 NE_TYPEINFO* pTInfo = (NE_TYPEINFO*)(pData + 2);
518 NE_NAMEINFO* pIconStorage = NULL;
519 NE_NAMEINFO* pIconDir = NULL;
520 LPicoICONDIR lpiID = NULL;
521
522 if( pData == (BYTE*)-1 )
523 { hIcon = ICO_GetIconDirectory(hInstance, hFile, &lpiID); /* check for .ICO file */
524 if( hIcon )
525 { iconDirCount = 1; iconCount = lpiID->idCount;
526 }
527 }
528 else while( pTInfo->type_id && !(pIconStorage && pIconDir) )
529 { if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON ) /* find icon directory and icon repository */
530 { iconDirCount = pTInfo->count;
531 pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
532 TRACE("\tfound directory - %i icon families\n", iconDirCount);
533 }
534 if( pTInfo->type_id == NE_RSCTYPE_ICON )
535 { iconCount = pTInfo->count;
536 pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
537 TRACE("\ttotal icons - %i\n", iconCount);
538 }
539 pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
540 }
541
542 /* load resources and create icons */
543
544 if( (pIconStorage && pIconDir) || lpiID )
545 { if( nIconIndex == (UINT16)-1 )
546 { RetPtr[0] = iconDirCount;
547 }
548 else if( nIconIndex < iconDirCount )
549 { UINT i, icon;
550 if( n > iconDirCount - nIconIndex )
551 n = iconDirCount - nIconIndex;
552
553 for( i = nIconIndex; i < nIconIndex + n; i++ )
554 { /* .ICO files have only one icon directory */
555
556 if( lpiID == NULL )
557 hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + i, *(WORD*)pData );
558 RetPtr[i-nIconIndex] = GetIconID( hIcon, 3 );
559 GlobalFree(hIcon);
560 }
561
562 for( icon = nIconIndex; icon < nIconIndex + n; icon++ )
563 { hIcon = 0;
564 if( lpiID )
565 { hIcon = ICO_LoadIcon( hInstance, hFile, lpiID->idEntries + RetPtr[icon-nIconIndex]);
566 }
567 else
568 { for( i = 0; i < iconCount; i++ )
569 { if( pIconStorage[i].id == (RetPtr[icon-nIconIndex] | 0x8000) )
570 { hIcon = SHELL_LoadResource( hInstance, hFile, pIconStorage + i,*(WORD*)pData );
571 }
572 }
573 }
574 if( hIcon )
575 { RetPtr[icon-nIconIndex] = LoadIconHandler16( hIcon, TRUE );
576 FarSetOwner16( RetPtr[icon-nIconIndex], GetExePtr(hInstance) );
577 }
578 else
579 { RetPtr[icon-nIconIndex] = 0;
580 }
581 }
582 }
583 }
584 if( lpiID )
585 HeapFree( GetProcessHeap(), 0, lpiID);
586 else
587 HeapFree( GetProcessHeap(), 0, pData);
588 }
589#endif
590 if( sig == IMAGE_NT_SIGNATURE)
591 { LPBYTE idata,igdata;
592 PIMAGE_DOS_HEADER dheader;
593 PIMAGE_NT_HEADERS pe_header;
594 PIMAGE_SECTION_HEADER pe_sections;
595 PIMAGE_RESOURCE_DIRECTORY rootresdir,iconresdir,icongroupresdir;
596 PIMAGE_RESOURCE_DATA_ENTRY idataent,igdataent;
597 int i,j;
598 PIMAGE_RESOURCE_DIRECTORY_ENTRY xresent;
599 CURSORICONDIR **cids;
600
601 fmapping = CreateFileMappingA(hFile,NULL,PAGE_READONLY|SEC_COMMIT,0,0,NULL);
602 if (fmapping == 0)
603 { /* FIXME, INVALID_HANDLE_VALUE? */
604 WARN("failed to create filemap.\n");
605 hRet = 0;
606 goto end_2; /* failure */
607 }
608 peimage = (BYTE*)MapViewOfFile(fmapping,FILE_MAP_READ,0,0,0);
609 if (!peimage)
610 { WARN("failed to mmap filemap.\n");
611 hRet = 0;
612 goto end_2; /* failure */
613 }
614 dheader = (PIMAGE_DOS_HEADER)peimage;
615
616 /* it is a pe header, SHELL_GetResourceTable checked that */
617 pe_header = (PIMAGE_NT_HEADERS)(peimage+dheader->e_lfanew);
618
619 /* probably makes problems with short PE headers... but I haven't seen
620 * one yet...
621 */
622 pe_sections = (PIMAGE_SECTION_HEADER)(((char*)pe_header)+sizeof(*pe_header));
623 rootresdir = NULL;
624
625 for (i=0;i<pe_header->FileHeader.NumberOfSections;i++)
626 { if (pe_sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
627 continue;
628 /* FIXME: doesn't work when the resources are not in a seperate section */
629 if (pe_sections[i].VirtualAddress == pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress)
630 { rootresdir = (PIMAGE_RESOURCE_DIRECTORY)((char*)peimage+pe_sections[i].PointerToRawData);
631 break;
632 }
633 }
634
635 if (!rootresdir)
636 { WARN("haven't found section for resource directory.\n");
637 goto end_4; /* failure */
638 }
639
640 icongroupresdir = GetResDirEntryW(rootresdir,RT_GROUP_ICONW, (DWORD)rootresdir,FALSE);
641
642 if (!icongroupresdir)
643 { WARN("No Icongroupresourcedirectory!\n");
644 goto end_4; /* failure */
645 }
646
647 iconDirCount = icongroupresdir->NumberOfNamedEntries+icongroupresdir->NumberOfIdEntries;
648
649 if( nIconIndex == (UINT)-1 )
650 { RetPtr[0] = iconDirCount;
651 goto end_3; /* success */
652 }
653
654 if (nIconIndex >= iconDirCount)
655 { WARN("nIconIndex %d is larger than iconDirCount %d\n",nIconIndex,iconDirCount);
656 GlobalFree(hRet);
657 goto end_4; /* failure */
658 }
659
660 cids = (CURSORICONDIR**)HeapAlloc(GetProcessHeap(),0,n*sizeof(CURSORICONDIR*));
661
662 /* caller just wanted the number of entries */
663 xresent = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(icongroupresdir+1);
664
665 /* assure we don't get too much ... */
666 if( n > iconDirCount - nIconIndex )
667 { n = iconDirCount - nIconIndex;
668 }
669
670 /* starting from specified index ... */
671 xresent = xresent+nIconIndex;
672
673 for (i=0;i<n;i++,xresent++)
674 { CURSORICONDIR *cid;
675 PIMAGE_RESOURCE_DIRECTORY resdir;
676
677 /* go down this resource entry, name */
678 resdir = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)rootresdir+(xresent->u2.s.OffsetToDirectory));
679
680 /* default language (0) */
681 resdir = GetResDirEntryW(resdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
682 igdataent = (PIMAGE_RESOURCE_DATA_ENTRY)resdir;
683
684 /* lookup address in mapped image for virtual address */
685 igdata = NULL;
686
687 for (j=0;j<pe_header->FileHeader.NumberOfSections;j++)
688 { if (igdataent->OffsetToData < pe_sections[j].VirtualAddress)
689 continue;
690 if (igdataent->OffsetToData+igdataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
691 continue;
692 igdata = peimage+(igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
693 }
694
695 if (!igdata)
696 { WARN("no matching real address for icongroup!\n");
697 goto end_4; /* failure */
698 }
699 /* found */
700 cid = (CURSORICONDIR*)igdata;
701 cids[i] = cid;
702 RetPtr[i] = LookupIconIdFromDirectoryEx(igdata,TRUE,GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CYICON),0);
703 }
704
705 iconresdir=GetResDirEntryW(rootresdir,RT_ICONW,(DWORD)rootresdir,FALSE);
706
707 if (!iconresdir)
708 { WARN("No Iconresourcedirectory!\n");
709 goto end_4; /* failure */
710 }
711
712 for (i=0;i<n;i++)
713 { PIMAGE_RESOURCE_DIRECTORY xresdir;
714 xresdir = GetResDirEntryW(iconresdir,(LPWSTR)(DWORD)RetPtr[i],(DWORD)rootresdir,FALSE);
715 xresdir = GetResDirEntryW(xresdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
716 idataent = (PIMAGE_RESOURCE_DATA_ENTRY)xresdir;
717 idata = NULL;
718
719 /* map virtual to address in image */
720 for (j=0;j<pe_header->FileHeader.NumberOfSections;j++)
721 { if (idataent->OffsetToData < pe_sections[j].VirtualAddress)
722 continue;
723 if (idataent->OffsetToData+idataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
724 continue;
725 idata = peimage+(idataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
726 }
727 if (!idata)
728 { WARN("no matching real address found for icondata!\n");
729 RetPtr[i]=0;
730 continue;
731 }
732 RetPtr[i] = CreateIconFromResourceEx(idata,idataent->Size,TRUE,0x00030000,GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CYICON),0);
733 }
734 goto end_3; /* sucess */
735 }
736 goto end_1; /* return array with icon handles */
737
738/* cleaning up (try & catch would be nicer) */
739end_4: hRet = 0; /* failure */
740end_3: UnmapViewOfFile(peimage); /* success */
741end_2: CloseHandle(fmapping);
742end_1: _lclose( hFile);
743 return hRet;
744}
745
746/*************************************************************************
747 * SHELL_GetResourceTable
748 */
749DWORD SHELL_GetResourceTable(HFILE hFile,LPBYTE *retptr)
750{ IMAGE_DOS_HEADER mz_header;
751 char magic[4];
752 int size;
753
754 TRACE("\n");
755
756 *retptr = NULL;
757 _llseek( hFile, 0, SEEK_SET );
758 if ((_lread(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) || (mz_header.e_magic != IMAGE_DOS_SIGNATURE))
759 { /* .ICO file ? */
760 if (mz_header.e_cblp == 1)
761 { /* ICONHEADER.idType, must be 1 */
762 *retptr = (LPBYTE)-1;
763 return 1;
764 }
765 else
766 return 0; /* failed */
767 }
768 _llseek( hFile, mz_header.e_lfanew, SEEK_SET );
769
770 if (_lread( hFile, magic, sizeof(magic) ) != sizeof(magic))
771 return 0;
772
773 _llseek( hFile, mz_header.e_lfanew, SEEK_SET);
774
775 if (*(DWORD*)magic == IMAGE_NT_SIGNATURE)
776 return IMAGE_NT_SIGNATURE;
777
778 if (*(WORD*)magic == IMAGE_OS2_SIGNATURE)
779 { IMAGE_OS2_HEADER ne_header;
780 LPBYTE pTypeInfo = (LPBYTE)-1;
781
782 if (_lread(hFile,&ne_header,sizeof(ne_header))!=sizeof(ne_header))
783 return 0;
784
785 if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE)
786 return 0;
787
788 size = ne_header.ne_restab - ne_header.ne_rsrctab;
789
790 if( size > sizeof(NE_TYPEINFO) )
791 { pTypeInfo = (BYTE*)HeapAlloc( GetProcessHeap(), 0, size);
792 if( pTypeInfo )
793 { _llseek(hFile, mz_header.e_lfanew+ne_header.ne_rsrctab, SEEK_SET);
794 if( _lread( hFile, (char*)pTypeInfo, size) != size )
795 { HeapFree( GetProcessHeap(), 0, pTypeInfo);
796 pTypeInfo = NULL;
797 }
798 }
799 }
800 *retptr = pTypeInfo;
801 return IMAGE_OS2_SIGNATURE;
802 }
803 return 0; /* failed */
804}
805
806/*************************************************************************
807 * SHELL_FindExecutable [Internal]
808 *
809 * Utility for code sharing between FindExecutable and ShellExecute
810 */
811HINSTANCE SHELL_FindExecutable( LPCSTR lpFile,
812 LPCSTR lpOperation,
813 LPSTR lpResult)
814{ char *extension = NULL; /* pointer to file extension */
815 char tmpext[5]; /* local copy to mung as we please */
816 char filetype[256]; /* registry name for this filetype */
817 LONG filetypelen=256; /* length of above */
818 char command[256]; /* command from registry */
819 LONG commandlen=256; /* This is the most DOS can handle :) */
820 char buffer[256]; /* Used to GetProfileString */
821 HINSTANCE retval=31; /* default - 'No association was found' */
822 char *tok; /* token pointer */
823 int i; /* random counter */
824 char xlpFile[256]; /* result of SearchPath */
825
826 dprintf(("SHELL32:SHELL:SHELL_FindExecutable(%s,%s,%08xh)\n",
827 lpFile,
828 lpOperation,
829 lpResult));
830
831 lpResult[0]='\0'; /* Start off with an empty return string */
832
833 /* trap NULL parameters on entry */
834 if (( lpFile == NULL ) || ( lpResult == NULL ) || ( lpOperation == NULL ))
835 { dprintf(("SHELL32:SHELL:SHELL_FindExecutable(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n",
836 lpFile, lpOperation, lpResult));
837 return 2; /* File not found. Close enough, I guess. */
838 }
839
840 if (SearchPathA( NULL, lpFile,".exe",sizeof(xlpFile),xlpFile,NULL))
841 { dprintf(("SHELL32:SHELL:SHELL_FindExecutable(SearchPath32A returned non-zero\n"));
842 lpFile = xlpFile;
843 }
844
845 /* First thing we need is the file's extension */
846 extension = strrchr( xlpFile, '.' ); /* Assume last "." is the one; */
847 /* File->Run in progman uses */
848 /* .\FILE.EXE :( */
849 dprintf(("SHELL32:SHELL:SHELL_FindExecutable(xlpFile=%s,extension=%s)\n",
850 xlpFile, extension));
851
852 if ((extension == NULL) || (extension == &xlpFile[strlen(xlpFile)]))
853 { dprintf(("SHELL32:SHELL:SHELL_FindExecutable Returning 31 - No association\n"));
854 return 31; /* no association */
855 }
856
857 /* Make local copy & lowercase it for reg & 'programs=' lookup */
858 lstrcpynA( tmpext, extension, 5 );
859 CharLowerA( tmpext );
860
861
862 dprintf(("SHELL32:SHELL:SHELL_FindExecutable(%s file)\n", tmpext));
863
864 /* Three places to check: */
865 /* 1. win.ini, [windows], programs (NB no leading '.') */
866 /* 2. Registry, HKEY_CLASS_ROOT\<filetype>\shell\open\command */
867 /* 3. win.ini, [extensions], extension (NB no leading '.' */
868 /* All I know of the order is that registry is checked before */
869 /* extensions; however, it'd make sense to check the programs */
870 /* section first, so that's what happens here. */
871
872 /* See if it's a program - if GetProfileString fails, we skip this
873 * section. Actually, if GetProfileString fails, we've probably
874 * got a lot more to worry about than running a program... */
875 if ( GetProfileStringA("windows", "programs", "exe pif bat com",
876 buffer, sizeof(buffer)) > 0 )
877 { for (i=0;i<strlen(buffer); i++) buffer[i]=tolower(buffer[i]);
878
879 tok = strtok(buffer, " \t"); /* ? */
880 while( tok!= NULL)
881 {
882 if (strcmp(tok, &tmpext[1])==0) /* have to skip the leading "." */
883 {
884 strcpy(lpResult, xlpFile);
885 /* Need to perhaps check that the file has a path
886 * attached */
887 dprintf(("SHELL32:SHELL:SHELL_FindExecutable found %s\n",
888 lpResult));
889 return 33;
890
891 /* Greater than 32 to indicate success FIXME According to the
892 * docs, I should be returning a handle for the
893 * executable. Does this mean I'm supposed to open the
894 * executable file or something? More RTFM, I guess... */
895 }
896 tok=strtok(NULL, " \t");
897 }
898 }
899
900 /* Check registry */
901 if (RegQueryValueA( HKEY_CLASSES_ROOT, tmpext, filetype,
902 &filetypelen ) == ERROR_SUCCESS )
903 {
904 filetype[filetypelen]='\0';
905 dprintf(("SHELL32:SHELL:SHELL_FindExecutable(File type: %s)\n",
906 filetype));
907
908 /* Looking for ...buffer\shell\lpOperation\command */
909 strcat( filetype, "\\shell\\" );
910 strcat( filetype, lpOperation );
911 strcat( filetype, "\\command" );
912
913 if (RegQueryValueA( HKEY_CLASSES_ROOT, filetype, command,
914 &commandlen ) == ERROR_SUCCESS )
915 {
916 LPSTR tmp;
917 char param[256];
918 LONG paramlen = 256;
919
920 /* Get the parameters needed by the application
921 from the associated ddeexec key */
922 tmp = strstr(filetype,"command");
923 tmp[0] = '\0';
924 strcat(filetype,"ddeexec");
925
926 if(RegQueryValueA( HKEY_CLASSES_ROOT, filetype, param,&paramlen ) == ERROR_SUCCESS)
927 {
928 strcat(command," ");
929 strcat(command,param);
930 commandlen += paramlen;
931 }
932
933 /* Is there a replace() function anywhere? */
934 command[commandlen]='\0';
935 strcpy( lpResult, command );
936 tok=strstr( lpResult, "%1" );
937 if (tok != NULL)
938 {
939 tok[0]='\0'; /* truncate string at the percent */
940 strcat( lpResult, xlpFile ); /* what if no dir in xlpFile? */
941 tok=strstr( command, "%1" );
942 if ((tok!=NULL) && (strlen(tok)>2))
943 {
944 strcat( lpResult, &tok[2] );
945 }
946 }
947 retval=33; /* FIXME see above */
948 }
949 }
950 else /* Check win.ini */
951 {
952 /* Toss the leading dot */
953 extension++;
954 if ( GetProfileStringA( "extensions", extension, "", command,
955 sizeof(command)) > 0)
956 {
957 if (strlen(command)!=0)
958 {
959 strcpy( lpResult, command );
960 tok=strstr( lpResult, "^" ); /* should be ^.extension? */
961 if (tok != NULL)
962 {
963 tok[0]='\0';
964 strcat( lpResult, xlpFile ); /* what if no dir in xlpFile? */
965 tok=strstr( command, "^" ); /* see above */
966 if ((tok != NULL) && (strlen(tok)>5))
967 {
968 strcat( lpResult, &tok[5]);
969 }
970 }
971 retval=33; /* FIXME - see above */
972 }
973 }
974 }
975
976 dprintf(("SHELL32:SHELL:SHELL_FindExecutable (returning %s)\n", lpResult));
977 return retval;
978}
979
980/*************************************************************************
981 * ShellExecuteA [SHELL32.245]
982 */
983
984HINSTANCE WIN32API ShellExecuteA(HWND hWnd, LPCSTR lpOperation,
985 LPCSTR lpFile,
986 LPCSTR lpParameters,
987 LPCSTR lpDirectory,
988 INT iShowCmd )
989{
990 HINSTANCE retval=31;
991 char old_dir[1024];
992 char cmd[256];
993 LONG cmdlen = sizeof( cmd );
994 LPSTR tok;
995
996 if (lpFile==NULL)
997 return 0; /* should not happen */
998
999 if (lpOperation==NULL) /* default is open */
1000 lpOperation="open";
1001
1002 if (lpDirectory)
1003 {
1004 // @@@PH 2002-02-26 might throw whole process off track
1005 // in case of concurrency
1006 GetCurrentDirectoryA( sizeof(old_dir), old_dir );
1007 SetCurrentDirectoryA( lpDirectory );
1008 }
1009
1010 cmd[0] = '\0';
1011 retval = SHELL_FindExecutable( lpFile, lpOperation, cmd );
1012
1013 if (retval > 32) /* Found */
1014 {
1015 if (lpParameters)
1016 {
1017 strcat(cmd," ");
1018 strcat(cmd,lpParameters);
1019 }
1020
1021 dprintf(("starting %s\n",cmd));
1022 retval = WinExec( cmd, iShowCmd );
1023 }
1024 else
1025 {
1026 // - path might be an URL
1027 // - argument might be associated with some class / app
1028
1029 // 2002-02-26 PH
1030 // File Extension Association is missing. We'd have to lookup
1031 // i. e. ".doc" and create the command.
1032 // @@@PH
1033
1034 // build lookup key
1035 char lpstrShellSubkey[256] = "\\shell\\";
1036 /* Looking for ...protocol\shell\lpOperation\command */
1037 strcat( lpstrShellSubkey, lpOperation );
1038 strcat( lpstrShellSubkey, "\\command" );
1039
1040 // First, check for URL association
1041 if(PathIsURLA((LPSTR)lpFile)) /* File not found, check for URL */
1042 {
1043 LPSTR lpstrRes;
1044 INT iSize;
1045
1046 lpstrRes = strchr(lpFile,':');
1047 if (NULL != lpstrRes)
1048 {
1049 char szProtocol[256];
1050
1051 iSize = lpstrRes - lpFile;
1052
1053 strncpy(szProtocol,
1054 lpFile,
1055 min( sizeof( szProtocol ), iSize) );
1056
1057 /* Remove File Protocol from lpFile */
1058 /* In the case file://path/file */
1059 if(!strnicmp(lpFile,"file",iSize))
1060 {
1061 lpFile += iSize;
1062 while(*lpFile == ':') lpFile++;
1063 }
1064
1065 /* Get the application for the protocol and execute it */
1066 if (RegQueryValueA(HKEY_CLASSES_ROOT,
1067 szProtocol,
1068 cmd,
1069 &cmdlen ) == ERROR_SUCCESS )
1070 {
1071 LPSTR tmp;
1072 char param[256] = "";
1073 LONG paramlen = 256;
1074
1075 /* Get the parameters needed by the application
1076 from the associated ddeexec key */
1077 tmp = strstr(szProtocol,"command");
1078 tmp[0] = '\0';
1079 strcat(szProtocol,"ddeexec");
1080
1081 if(RegQueryValueA(HKEY_CLASSES_ROOT,
1082 szProtocol,
1083 param,
1084 &paramlen ) == ERROR_SUCCESS)
1085 {
1086 strcat(cmd," ");
1087 strcat(cmd,param);
1088 cmdlen += paramlen;
1089 }
1090 }
1091 }
1092 }
1093
1094
1095 // Second, check for filename extension association
1096 if (0 == cmd[0])
1097 {
1098 LPSTR lpstrRDot = strrchr(lpFile, '.');
1099 if (NULL != lpstrRDot)
1100 {
1101 char szAssociation[256];
1102 LONG lAssociationLen = sizeof( szAssociation );
1103
1104 // lookup associated application (or COM object) for
1105 // this extension
1106 if (RegQueryValueA(HKEY_CLASSES_ROOT,
1107 lpstrRDot,
1108 szAssociation,
1109 &lAssociationLen) == ERROR_SUCCESS)
1110 {
1111 // append the shell subkey
1112 strcat(szAssociation, lpstrShellSubkey);
1113 lAssociationLen = sizeof( szAssociation );
1114
1115 // lookup application for retrieved association
1116 if (RegQueryValueA(HKEY_CLASSES_ROOT,
1117 szAssociation,
1118 cmd,
1119 &cmdlen) == ERROR_SUCCESS)
1120 {
1121 // received cmd now
1122 }
1123 }
1124 }
1125 }
1126
1127
1128#ifdef __WIN32OS2__
1129 if (0 == cmd[0])
1130 {
1131 // OS/2 specific addon:
1132 // if no windows association is found, pass on to the workplace shell
1133 // eventually.
1134 retval = ShellExecuteOS2(hWnd,
1135 lpOperation,
1136 lpFile,
1137 lpParameters,
1138 lpDirectory,
1139 iShowCmd);
1140 }
1141#endif
1142
1143 if (0 != cmd[0])
1144 {
1145 // resolve the parameters
1146 // @@@PH 2002-02-26 there might be more than one parameter only
1147 /* Is there a replace() function anywhere? */
1148 tok=strstr( cmd, "%1" );
1149 if (tok != NULL)
1150 {
1151 tok[0]='\0'; /* truncate string at the percent */
1152 strcat( cmd, lpFile ); /* what if no dir in xlpFile? */
1153 tok=strstr( cmd, "%1" );
1154 if ((tok!=NULL) && (strlen(tok)>2))
1155 {
1156 strcat( cmd, &tok[2] );
1157 }
1158 }
1159 }
1160
1161 /* Nothing was done yet, try to execute the cmdline directly,
1162 maybe it's an OS/2 program */
1163 if (0 == cmd[0])
1164 {
1165 strcpy(cmd,lpFile);
1166 strcat(cmd,lpParameters ? lpParameters : "");
1167 }
1168
1169 // now launch ... something :)
1170 retval = WinExec( cmd, iShowCmd );
1171 }
1172
1173 if (lpDirectory)
1174 SetCurrentDirectoryA( old_dir );
1175
1176 return retval;
1177}
1178
1179
1180/*****************************************************************************
1181 * Name : UINT DragQueryFileAorW
1182 * Purpose :
1183 * Parameters: HDROP hDrop - drop structure handle
1184 * UINT iFile - index of file to query
1185 * LPTSTR lpszFile - target buffer
1186 * UINT cch - target buffer size
1187 * Variables :
1188 * Result :
1189 * Remark :
1190 * Status : UNTESTED STUB
1191 *
1192 * Author : Patrick Haller [Tue, 1999/06/09 20:00]
1193 *****************************************************************************/
1194
1195UINT WIN32API DragQueryFileAorW(HDROP hDrop, UINT iFile, LPTSTR lpszFile,
1196 UINT cch)
1197{
1198 // @@@PH maybe they want automatic determination here
1199 if (SHELL_OsIsUnicode())
1200 return DragQueryFileW(hDrop, iFile, (LPWSTR)lpszFile, cch);
1201 else
1202 return DragQueryFileA(hDrop, iFile, lpszFile, cch);
1203}
1204
1205
1206LPCSTR debugstr_guid1( void *id1 )
1207{
1208 static char str[40];
1209 GUID *id = (GUID *)id1;
1210
1211 if (!id) return "(null)";
1212 if (!HIWORD(id))
1213 {
1214 sprintf( str, "<guid-0x%04x>", LOWORD(id) );
1215 }
1216 else
1217 {
1218 sprintf( str, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
1219 id->Data1, id->Data2, id->Data3,
1220 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
1221 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
1222 }
1223 return str;
1224}
1225
Note: See TracBrowser for help on using the repository browser.