source: trunk/src/shell32/shell.cpp@ 3243

Last change on this file since 3243 was 3243, checked in by cbratschi, 25 years ago

merged with Corel WINE 20000324

File size: 29.9 KB
Line 
1/* $Id: shell.cpp,v 1.5 2000-03-26 16:34:43 cbratschi 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 Library Functions
10 *
11 * 1998 Marcus Meissner
12 *
13 * Corel WINE 20000324 level
14 */
15
16
17/*****************************************************************************
18 * Includes *
19 *****************************************************************************/
20
21#include <odin.h>
22#include <odinwrap.h>
23#include <os2sel.h>
24
25#include <assert.h>
26#include <stdlib.h>
27#include <string.h>
28//#include <unistd.h>
29#include <ctype.h>
30
31#define ICOM_CINTERFACE 1
32#define CINTERFACE 1
33
34#include <winbase.h>
35#include <winuser.h>
36//#include "wine/shell16.h"
37#include "winerror.h"
38//#include "file.h"
39#include "heap.h"
40#include "ldt.h"
41#include "module.h"
42#include "neexe.h"
43#include "dlgs.h"
44#include "cursoricon.h"
45#include "shellapi.h"
46#include "shlobj.h"
47#include "debugtools.h"
48#include "winreg.h"
49//#include "syslevel.h"
50#include "imagelist.h"
51#include "shell32_main.h"
52#include "winversion.h"
53
54#include <heapstring.h>
55#include <misc.h>
56
57
58/*****************************************************************************
59 * Implementation *
60 *****************************************************************************/
61
62ODINDEBUGCHANNEL(SHELL32-SHELL)
63
64
65/* .ICO file ICONDIR definitions */
66
67#include "pshpack1.h"
68
69typedef struct
70{
71 BYTE bWidth; /* Width, in pixels, of the image */
72 BYTE bHeight; /* Height, in pixels, of the image */
73 BYTE bColorCount; /* Number of colors in image (0 if >=8bpp) */
74 BYTE bReserved; /* Reserved ( must be 0) */
75 WORD wPlanes; /* Color Planes */
76 WORD wBitCount; /* Bits per pixel */
77 DWORD dwBytesInRes; /* How many bytes in this resource? */
78 DWORD dwImageOffset; /* Where in the file is this image? */
79} icoICONDIRENTRY, *LPicoICONDIRENTRY;
80
81typedef struct
82{
83 WORD idReserved; /* Reserved (must be 0) */
84 WORD idType; /* Resource Type (1 for icons) */
85 WORD idCount; /* How many images? */
86 icoICONDIRENTRY idEntries[1]; /* An entry for each image (idCount of 'em) */
87} icoICONDIR, *LPicoICONDIR;
88
89#include "poppack.h"
90
91static const char* lpstrMsgWndCreated = "OTHERWINDOWCREATED";
92static const char* lpstrMsgWndDestroyed = "OTHERWINDOWDESTROYED";
93static const char* lpstrMsgShellActivate = "ACTIVATESHELLWINDOW";
94
95static HWND SHELL_hWnd = 0;
96static HHOOK SHELL_hHook = 0;
97static UINT uMsgWndCreated = 0;
98static UINT uMsgWndDestroyed = 0;
99static UINT uMsgShellActivate = 0;
100HINSTANCE SHELL_hInstance32;
101static int SHELL_Attach = 0;
102
103
104/*************************************************************************
105 * DragAcceptFiles32 [SHELL32.54]
106 */
107
108//SvL: DON'T USE ODINFUNCTION MACRO'S HERE; SetWindowLong (style) sends messages
109// to the win32 app!!!! (FS messed up)
110void WINAPI DragAcceptFiles(HWND hWnd, BOOL b)
111{
112 LONG exstyle;
113
114 dprintf(("DragAcceptFiles %x %d", hWnd, b));
115 if( !IsWindow(hWnd) )
116 return;
117 exstyle = GetWindowLongA(hWnd,GWL_EXSTYLE);
118 if (b)exstyle |= WS_EX_ACCEPTFILES;
119 else exstyle &= ~WS_EX_ACCEPTFILES;
120 SetWindowLongA(hWnd,GWL_EXSTYLE,exstyle);
121}
122
123/*************************************************************************
124 * SHELL_DragQueryFile [internal]
125 *
126 */
127static UINT SHELL_DragQueryFile(LPSTR lpDrop, LPWSTR lpwDrop, UINT lFile,
128 LPSTR lpszFile, LPWSTR lpszwFile, UINT lLength)
129{
130 UINT i;
131
132 i = 0;
133 if (lpDrop) {
134 while (i++ < lFile) {
135 while (*lpDrop++); /* skip filename */
136 if (!*lpDrop)
137 return (lFile == 0xFFFFFFFF) ? i : 0;
138 }
139 }
140 if (lpwDrop) {
141 while (i++ < lFile) {
142 while (*lpwDrop++); /* skip filename */
143 if (!*lpwDrop)
144 return (lFile == 0xFFFFFFFF) ? i : 0;
145 }
146 }
147
148 if (lpDrop) i = lstrlenA(lpDrop);
149 if (lpwDrop) i = lstrlenW(lpwDrop);
150 i++;
151 if (!lpszFile && !lpszwFile) {
152 return i; /* needed buffer size */
153 }
154 i = (lLength > i) ? i : lLength;
155 if (lpszFile) {
156 if (lpDrop) lstrcpynA (lpszFile, lpDrop, i);
157 else lstrcpynWtoA(lpszFile, lpwDrop, i);
158 } else {
159 if (lpDrop) lstrcpynAtoW(lpszwFile, lpDrop, i);
160 else lstrcpynW (lpszwFile, lpwDrop, i);
161 }
162 return i;
163}
164
165/*************************************************************************
166 * DragQueryFile32A [SHELL32.81] [shell32.82]
167 */
168
169ODINFUNCTION4(UINT, DragQueryFileA, HDROP, hDrop,
170 UINT, lFile,
171 LPSTR, lpszFile,
172 UINT, lLength)
173{ /* hDrop is a global memory block allocated with GMEM_SHARE
174 * with DROPFILESTRUCT as a header and filenames following
175 * it, zero length filename is in the end */
176
177 LPDROPFILESTRUCT lpDropFileStruct;
178 LPSTR lpCurrent;
179 UINT i;
180
181 lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop);
182 if(!lpDropFileStruct)
183 return 0;
184
185 lpCurrent = (LPSTR) lpDropFileStruct + lpDropFileStruct->lSize;
186 i = SHELL_DragQueryFile(lpCurrent, NULL, lFile, lpszFile, NULL, lLength);
187 GlobalUnlock(hDrop);
188 return i;
189}
190
191/*************************************************************************
192 * DragQueryFile32W [shell32.133]
193 */
194ODINFUNCTION4(UINT, DragQueryFileW, HDROP, hDrop,
195 UINT, lFile,
196 LPWSTR, lpszwFile,
197 UINT, lLength)
198{
199 LPDROPFILESTRUCT lpDropFileStruct;
200 LPWSTR lpwCurrent;
201 UINT i;
202
203 lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop);
204 if(!lpDropFileStruct)
205 return 0;
206
207 lpwCurrent = (LPWSTR) lpDropFileStruct + lpDropFileStruct->lSize;
208 i = SHELL_DragQueryFile(NULL, lpwCurrent, lFile, NULL, lpszwFile,lLength);
209 GlobalUnlock(hDrop);
210 return i;
211}
212
213
214/*****************************************************************************
215 * Name : UINT DragQueryFileAorW
216 * Purpose :
217 * Parameters: HDROP hDrop - drop structure handle
218 * UINT iFile - index of file to query
219 * LPTSTR lpszFile - target buffer
220 * UINT cch - target buffer size
221 * Variables :
222 * Result :
223 * Remark :
224 * Status : UNTESTED STUB
225 *
226 * Author : Patrick Haller [Tue, 1999/06/09 20:00]
227 *****************************************************************************/
228
229ODINFUNCTION4(UINT, DragQueryFileAorW,
230 HDROP, hDrop,
231 UINT, iFile,
232 LPTSTR, lpszFile,
233 UINT, cch)
234{
235 // @@@PH maybe they want automatic determination here
236 if (VERSION_OsIsUnicode())
237 return DragQueryFileW(hDrop, iFile, (LPWSTR)lpszFile, cch);
238 else
239 return DragQueryFileA(hDrop, iFile, lpszFile, cch);
240}
241
242
243/*************************************************************************
244 * DragFinish32 [SHELL32.80]
245 */
246ODINPROCEDURE1(DragFinish, HDROP, h)
247{
248 GlobalFree((HGLOBAL)h);
249}
250
251
252/*************************************************************************
253 * DragQueryPoint32 [SHELL32.135]
254 */
255ODINFUNCTION2(BOOL, DragQueryPoint,
256 HDROP, hDrop,
257 POINT*, p)
258{
259 LPDROPFILESTRUCT lpDropFileStruct;
260 BOOL bRet;
261
262 lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop);
263
264 memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT));
265 bRet = lpDropFileStruct->fInNonClientArea;
266
267 GlobalUnlock(hDrop);
268 return bRet;
269}
270
271/*************************************************************************
272 * SHELL_FindExecutable [Internal]
273 *
274 * Utility for code sharing between FindExecutable and ShellExecute
275 */
276HINSTANCE SHELL_FindExecutable( LPCSTR lpFile,
277 LPCSTR lpOperation,
278 LPSTR lpResult)
279{ char *extension = NULL; /* pointer to file extension */
280 char tmpext[5]; /* local copy to mung as we please */
281 char filetype[256]; /* registry name for this filetype */
282 LONG filetypelen=256; /* length of above */
283 char command[256]; /* command from registry */
284 LONG commandlen=256; /* This is the most DOS can handle :) */
285 char buffer[256]; /* Used to GetProfileString */
286 HINSTANCE retval=31; /* default - 'No association was found' */
287 char *tok; /* token pointer */
288 int i; /* random counter */
289 char xlpFile[256]; /* result of SearchPath */
290
291 dprintf(("SHELL32:SHELL:SHELL_FindExecutable(%s,%s,%08xh)\n",
292 lpFile,
293 lpOperation,
294 lpResult));
295
296 lpResult[0]='\0'; /* Start off with an empty return string */
297
298 /* trap NULL parameters on entry */
299 if (( lpFile == NULL ) || ( lpResult == NULL ) || ( lpOperation == NULL ))
300 { dprintf(("SHELL32:SHELL:SHELL_FindExecutable(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n",
301 lpFile, lpOperation, lpResult));
302 return 2; /* File not found. Close enough, I guess. */
303 }
304
305 if (SearchPathA( NULL, lpFile,".exe",sizeof(xlpFile),xlpFile,NULL))
306 { dprintf(("SHELL32:SHELL:SHELL_FindExecutable(SearchPath32A returned non-zero\n"));
307 lpFile = xlpFile;
308 }
309
310 /* First thing we need is the file's extension */
311 extension = strrchr( xlpFile, '.' ); /* Assume last "." is the one; */
312 /* File->Run in progman uses */
313 /* .\FILE.EXE :( */
314 dprintf(("SHELL32:SHELL:SHELL_FindExecutable(xlpFile=%s,extension=%s)\n",
315 xlpFile, extension));
316
317 if ((extension == NULL) || (extension == &xlpFile[strlen(xlpFile)]))
318 { dprintf(("SHELL32:SHELL:SHELL_FindExecutable Returning 31 - No association\n"));
319 return 31; /* no association */
320 }
321
322 /* Make local copy & lowercase it for reg & 'programs=' lookup */
323 lstrcpynA( tmpext, extension, 5 );
324 CharLowerA( tmpext );
325
326
327 dprintf(("SHELL32:SHELL:SHELL_FindExecutable(%s file)\n", tmpext));
328
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. */
336
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 ( GetProfileStringA("windows", "programs", "exe pif bat com",
341 buffer, sizeof(buffer)) > 0 )
342 { for (i=0;i<strlen(buffer); i++) buffer[i]=tolower(buffer[i]);
343
344 tok = strtok(buffer, " \t"); /* ? */
345 while( tok!= NULL)
346 {
347 if (strcmp(tok, &tmpext[1])==0) /* have to skip the leading "." */
348 {
349 strcpy(lpResult, xlpFile);
350 /* Need to perhaps check that the file has a path
351 * attached */
352 dprintf(("SHELL32:SHELL:SHELL_FindExecutable found %s\n",
353 lpResult));
354 return 33;
355
356 /* Greater than 32 to indicate success FIXME According to the
357 * docs, I should be returning a handle for the
358 * executable. Does this mean I'm supposed to open the
359 * executable file or something? More RTFM, I guess... */
360 }
361 tok=strtok(NULL, " \t");
362 }
363 }
364
365 /* Check registry */
366 if (RegQueryValueA( HKEY_CLASSES_ROOT, tmpext, filetype,
367 &filetypelen ) == ERROR_SUCCESS )
368 {
369 filetype[filetypelen]='\0';
370 dprintf(("SHELL32:SHELL:SHELL_FindExecutable(File type: %s)\n",
371 filetype));
372
373 /* Looking for ...buffer\shell\lpOperation\command */
374 strcat( filetype, "\\shell\\" );
375 strcat( filetype, lpOperation );
376 strcat( filetype, "\\command" );
377
378 if (RegQueryValueA( HKEY_CLASSES_ROOT, filetype, command,
379 &commandlen ) == ERROR_SUCCESS )
380 {
381 LPSTR tmp;
382 char param[256];
383 LONG paramlen = 256;
384
385 /* Get the parameters needed by the application
386 from the associated ddeexec key */
387 tmp = strstr(filetype,"command");
388 tmp[0] = '\0';
389 strcat(filetype,"ddeexec");
390
391 if(RegQueryValueA( HKEY_CLASSES_ROOT, filetype, param,&paramlen ) == ERROR_SUCCESS)
392 {
393 strcat(command," ");
394 strcat(command,param);
395 commandlen += paramlen;
396 }
397
398 /* Is there a replace() function anywhere? */
399 command[commandlen]='\0';
400 strcpy( lpResult, command );
401 tok=strstr( lpResult, "%1" );
402 if (tok != NULL)
403 {
404 tok[0]='\0'; /* truncate string at the percent */
405 strcat( lpResult, xlpFile ); /* what if no dir in xlpFile? */
406 tok=strstr( command, "%1" );
407 if ((tok!=NULL) && (strlen(tok)>2))
408 {
409 strcat( lpResult, &tok[2] );
410 }
411 }
412 retval=33; /* FIXME see above */
413 }
414 }
415 else /* Check win.ini */
416 {
417 /* Toss the leading dot */
418 extension++;
419 if ( GetProfileStringA( "extensions", extension, "", command,
420 sizeof(command)) > 0)
421 {
422 if (strlen(command)!=0)
423 {
424 strcpy( lpResult, command );
425 tok=strstr( lpResult, "^" ); /* should be ^.extension? */
426 if (tok != NULL)
427 {
428 tok[0]='\0';
429 strcat( lpResult, xlpFile ); /* what if no dir in xlpFile? */
430 tok=strstr( command, "^" ); /* see above */
431 if ((tok != NULL) && (strlen(tok)>5))
432 {
433 strcat( lpResult, &tok[5]);
434 }
435 }
436 retval=33; /* FIXME - see above */
437 }
438 }
439 }
440
441 dprintf(("SHELL32:SHELL:SHELL_FindExecutable (returning %s)\n", lpResult));
442 return retval;
443}
444
445
446/*************************************************************************
447 * SHELL_GetResourceTable
448 */
449static DWORD SHELL_GetResourceTable(HFILE hFile,LPBYTE *retptr)
450{ IMAGE_DOS_HEADER mz_header;
451 char magic[4];
452 int size;
453
454 dprintf(("SHELL32:Shell:SHELL_GetResourceTable(%08xh,%08xh)\n",
455 hFile,
456 retptr));
457
458 *retptr = NULL;
459 _llseek( hFile, 0, SEEK_SET );
460 if ((_lread(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) || (mz_header.e_magic != IMAGE_DOS_SIGNATURE))
461 { /* .ICO file ? */
462 if (mz_header.e_cblp == 1)
463 { /* ICONHEADER.idType, must be 1 */
464 *retptr = (LPBYTE)-1;
465 return 1;
466 }
467 else
468 return 0; /* failed */
469 }
470 _llseek( hFile, mz_header.e_lfanew, SEEK_SET );
471
472 if (_lread( hFile, magic, sizeof(magic) ) != sizeof(magic))
473 return 0;
474
475 _llseek( hFile, mz_header.e_lfanew, SEEK_SET);
476
477 if (*(DWORD*)magic == IMAGE_NT_SIGNATURE)
478 return IMAGE_NT_SIGNATURE;
479
480 if (*(WORD*)magic == IMAGE_OS2_SIGNATURE)
481 { IMAGE_OS2_HEADER ne_header;
482 LPBYTE pTypeInfo = (LPBYTE)-1;
483
484 if (_lread(hFile,&ne_header,sizeof(ne_header))!=sizeof(ne_header))
485 return 0;
486
487 if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE)
488 return 0;
489
490 size = ne_header.rname_tab_offset - ne_header.resource_tab_offset;
491
492//@@@PH no NE support
493#if 1
494 if( size > sizeof(NE_TYPEINFO) )
495 { pTypeInfo = (BYTE*)HeapAlloc( GetProcessHeap(), 0, size);
496 if( pTypeInfo )
497 { _llseek(hFile, mz_header.e_lfanew+ne_header.resource_tab_offset, SEEK_SET);
498 if( _lread( hFile, (char*)pTypeInfo, size) != size )
499 { HeapFree( GetProcessHeap(), 0, pTypeInfo);
500 pTypeInfo = NULL;
501 }
502 }
503 }
504#endif
505
506 *retptr = pTypeInfo;
507 return IMAGE_OS2_SIGNATURE;
508 }
509 return 0; /* failed */
510}
511#if 0 //CB: DirectResAlloc16 not yet ported
512/*************************************************************************
513 * SHELL_LoadResource
514 */
515static HGLOBAL SHELL_LoadResource(HINSTANCE hInst, HFILE hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
516{ BYTE* ptr;
517 HGLOBAL handle = DirectResAlloc( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
518
519 TRACE("\n");
520
521 if( (ptr = (BYTE*)GlobalLock( handle )) )
522 { _llseek( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
523 _lread( hFile, (char*)ptr, pNInfo->length << sizeShift);
524 return handle;
525 }
526 return 0;
527}
528
529/*************************************************************************
530 * ICO_LoadIcon
531 */
532static HGLOBAL ICO_LoadIcon(HINSTANCE hInst, HFILE hFile, LPicoICONDIRENTRY lpiIDE)
533{ BYTE* ptr;
534 HGLOBAL handle = DirectResAlloc( hInst, 0x10, lpiIDE->dwBytesInRes);
535 TRACE("\n");
536 if( (ptr = (BYTE*)GlobalLock( handle )) )
537 { _llseek( hFile, lpiIDE->dwImageOffset, SEEK_SET);
538 _lread( hFile, (char*)ptr, lpiIDE->dwBytesInRes);
539 return handle;
540 }
541 return 0;
542}
543
544/*************************************************************************
545 * ICO_GetIconDirectory
546 *
547 * Read .ico file and build phony ICONDIR struct for GetIconID
548 */
549static HGLOBAL ICO_GetIconDirectory(HINSTANCE hInst, HFILE hFile, LPicoICONDIR* lplpiID )
550{ WORD id[3]; /* idReserved, idType, idCount */
551 LPicoICONDIR lpiID;
552 int i;
553
554 TRACE("\n");
555 _llseek( hFile, 0, SEEK_SET );
556 if( _lread(hFile,(char*)id,sizeof(id)) != sizeof(id) ) return 0;
557
558 /* check .ICO header
559 *
560 * - see http://www.microsoft.com/win32dev/ui/icons.htm
561 */
562
563 if( id[0] || id[1] != 1 || !id[2] ) return 0;
564
565 i = id[2]*sizeof(icoICONDIRENTRY) ;
566
567 lpiID = (LPicoICONDIR)HeapAlloc( GetProcessHeap(), 0, i + sizeof(id));
568
569 if( _lread(hFile,(char*)lpiID->idEntries,i) == i )
570 { HGLOBAL handle = DirectResAlloc( hInst, 0x10,
571 id[2]*sizeof(CURSORICONDIRENTRY) + sizeof(id) );
572 if( handle )
573 { CURSORICONDIR* lpID = (CURSORICONDIR*)GlobalLock( handle );
574 lpID->idReserved = lpiID->idReserved = id[0];
575 lpID->idType = lpiID->idType = id[1];
576 lpID->idCount = lpiID->idCount = id[2];
577 for( i=0; i < lpiID->idCount; i++ )
578 { memcpy((void*)(lpID->idEntries + i),
579 (void*)(lpiID->idEntries + i), sizeof(CURSORICONDIRENTRY) - 2);
580 lpID->idEntries[i].wResId = i;
581 }
582 *lplpiID = lpiID;
583 return handle;
584 }
585 }
586 /* fail */
587
588 HeapFree( GetProcessHeap(), 0, lpiID);
589 return 0;
590}
591#endif
592/*************************************************************************
593 * InternalExtractIcon [SHELL.39]
594 *
595 * This abortion is called directly by Progman
596 */
597HGLOBAL WINAPI InternalExtractIcon(HINSTANCE hInstance,
598 LPCSTR lpszExeFileName, UINT nIconIndex, WORD n )
599{ HGLOBAL hRet = 0;
600 HGLOBAL* RetPtr = NULL;
601 LPBYTE pData;
602 OFSTRUCT ofs;
603 DWORD sig;
604 HFILE hFile = OpenFile( lpszExeFileName, &ofs, OF_READ );
605 UINT iconDirCount = 0,iconCount = 0;
606 LPBYTE peimage;
607 HANDLE fmapping;
608
609 TRACE("(%04x,file %s,start %d,extract %d\n",
610 hInstance, lpszExeFileName, nIconIndex, n);
611
612 if( hFile == HFILE_ERROR || !n )
613 return 0;
614
615 hRet = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(HICON16)*n);
616 RetPtr = (HGLOBAL*)GlobalLock(hRet);
617
618 *RetPtr = (n == 0xFFFF)? 0: 1; /* error return values */
619
620 sig = SHELL_GetResourceTable(hFile,&pData);
621#if 0 //CB: some functions not (yet) supported
622 if( sig==IMAGE_OS2_SIGNATURE || sig==1 ) /* .ICO file */
623 { HICON hIcon = 0;
624 NE_TYPEINFO* pTInfo = (NE_TYPEINFO*)(pData + 2);
625 NE_NAMEINFO* pIconStorage = NULL;
626 NE_NAMEINFO* pIconDir = NULL;
627 LPicoICONDIR lpiID = NULL;
628
629 if( pData == (BYTE*)-1 )
630 { hIcon = ICO_GetIconDirectory(hInstance, hFile, &lpiID); /* check for .ICO file */
631 if( hIcon )
632 { iconDirCount = 1; iconCount = lpiID->idCount;
633 }
634 }
635 else while( pTInfo->type_id && !(pIconStorage && pIconDir) )
636 { if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON ) /* find icon directory and icon repository */
637 { iconDirCount = pTInfo->count;
638 pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
639 TRACE("\tfound directory - %i icon families\n", iconDirCount);
640 }
641 if( pTInfo->type_id == NE_RSCTYPE_ICON )
642 { iconCount = pTInfo->count;
643 pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
644 TRACE("\ttotal icons - %i\n", iconCount);
645 }
646 pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
647 }
648
649 /* load resources and create icons */
650
651 if( (pIconStorage && pIconDir) || lpiID )
652 { if( nIconIndex == (UINT16)-1 )
653 { RetPtr[0] = iconDirCount;
654 }
655 else if( nIconIndex < iconDirCount )
656 { UINT i, icon;
657 if( n > iconDirCount - nIconIndex )
658 n = iconDirCount - nIconIndex;
659
660 for( i = nIconIndex; i < nIconIndex + n; i++ )
661 { /* .ICO files have only one icon directory */
662
663 if( lpiID == NULL )
664 hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + i, *(WORD*)pData );
665 RetPtr[i-nIconIndex] = GetIconID( hIcon, 3 );
666 GlobalFree(hIcon);
667 }
668
669 for( icon = nIconIndex; icon < nIconIndex + n; icon++ )
670 { hIcon = 0;
671 if( lpiID )
672 { hIcon = ICO_LoadIcon( hInstance, hFile, lpiID->idEntries + RetPtr[icon-nIconIndex]);
673 }
674 else
675 { for( i = 0; i < iconCount; i++ )
676 { if( pIconStorage[i].id == (RetPtr[icon-nIconIndex] | 0x8000) )
677 { hIcon = SHELL_LoadResource( hInstance, hFile, pIconStorage + i,*(WORD*)pData );
678 }
679 }
680 }
681 if( hIcon )
682 { RetPtr[icon-nIconIndex] = LoadIconHandler16( hIcon, TRUE );
683 FarSetOwner16( RetPtr[icon-nIconIndex], GetExePtr(hInstance) );
684 }
685 else
686 { RetPtr[icon-nIconIndex] = 0;
687 }
688 }
689 }
690 }
691 if( lpiID )
692 HeapFree( GetProcessHeap(), 0, lpiID);
693 else
694 HeapFree( GetProcessHeap(), 0, pData);
695 }
696#endif
697 if( sig == IMAGE_NT_SIGNATURE)
698 { LPBYTE idata,igdata;
699 PIMAGE_DOS_HEADER dheader;
700 PIMAGE_NT_HEADERS pe_header;
701 PIMAGE_SECTION_HEADER pe_sections;
702 PIMAGE_RESOURCE_DIRECTORY rootresdir,iconresdir,icongroupresdir;
703 PIMAGE_RESOURCE_DATA_ENTRY idataent,igdataent;
704 int i,j;
705 PIMAGE_RESOURCE_DIRECTORY_ENTRY xresent;
706 CURSORICONDIR **cids;
707
708 fmapping = CreateFileMappingA(hFile,NULL,PAGE_READONLY|SEC_COMMIT,0,0,NULL);
709 if (fmapping == 0)
710 { /* FIXME, INVALID_HANDLE_VALUE? */
711 WARN("failed to create filemap.\n");
712 hRet = 0;
713 goto end_2; /* failure */
714 }
715 peimage = (BYTE*)MapViewOfFile(fmapping,FILE_MAP_READ,0,0,0);
716 if (!peimage)
717 { WARN("failed to mmap filemap.\n");
718 hRet = 0;
719 goto end_2; /* failure */
720 }
721 dheader = (PIMAGE_DOS_HEADER)peimage;
722
723 /* it is a pe header, SHELL_GetResourceTable checked that */
724 pe_header = (PIMAGE_NT_HEADERS)(peimage+dheader->e_lfanew);
725
726 /* probably makes problems with short PE headers... but I haven't seen
727 * one yet...
728 */
729 pe_sections = (PIMAGE_SECTION_HEADER)(((char*)pe_header)+sizeof(*pe_header));
730 rootresdir = NULL;
731
732 for (i=0;i<pe_header->FileHeader.NumberOfSections;i++)
733 { if (pe_sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
734 continue;
735 /* FIXME: doesn't work when the resources are not in a seperate section */
736 if (pe_sections[i].VirtualAddress == pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress)
737 { rootresdir = (PIMAGE_RESOURCE_DIRECTORY)((char*)peimage+pe_sections[i].PointerToRawData);
738 break;
739 }
740 }
741
742 if (!rootresdir)
743 { WARN("haven't found section for resource directory.\n");
744 goto end_4; /* failure */
745 }
746
747 icongroupresdir = GetResDirEntryW(rootresdir,RT_GROUP_ICONW, (DWORD)rootresdir,FALSE);
748
749 if (!icongroupresdir)
750 { WARN("No Icongroupresourcedirectory!\n");
751 goto end_4; /* failure */
752 }
753
754 iconDirCount = icongroupresdir->NumberOfNamedEntries+icongroupresdir->NumberOfIdEntries;
755
756 if( nIconIndex == (UINT)-1 )
757 { RetPtr[0] = iconDirCount;
758 goto end_3; /* success */
759 }
760
761 if (nIconIndex >= iconDirCount)
762 { WARN("nIconIndex %d is larger than iconDirCount %d\n",nIconIndex,iconDirCount);
763 GlobalFree(hRet);
764 goto end_4; /* failure */
765 }
766
767 cids = (CURSORICONDIR**)HeapAlloc(GetProcessHeap(),0,n*sizeof(CURSORICONDIR*));
768
769 /* caller just wanted the number of entries */
770 xresent = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(icongroupresdir+1);
771
772 /* assure we don't get too much ... */
773 if( n > iconDirCount - nIconIndex )
774 { n = iconDirCount - nIconIndex;
775 }
776
777 /* starting from specified index ... */
778 xresent = xresent+nIconIndex;
779
780 for (i=0;i<n;i++,xresent++)
781 { CURSORICONDIR *cid;
782 PIMAGE_RESOURCE_DIRECTORY resdir;
783
784 /* go down this resource entry, name */
785 resdir = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)rootresdir+(xresent->u2.s.OffsetToDirectory));
786
787 /* default language (0) */
788 resdir = GetResDirEntryW(resdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
789 igdataent = (PIMAGE_RESOURCE_DATA_ENTRY)resdir;
790
791 /* lookup address in mapped image for virtual address */
792 igdata = NULL;
793
794 for (j=0;j<pe_header->FileHeader.NumberOfSections;j++)
795 { if (igdataent->OffsetToData < pe_sections[j].VirtualAddress)
796 continue;
797 if (igdataent->OffsetToData+igdataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
798 continue;
799 igdata = peimage+(igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
800 }
801
802 if (!igdata)
803 { WARN("no matching real address for icongroup!\n");
804 goto end_4; /* failure */
805 }
806 /* found */
807 cid = (CURSORICONDIR*)igdata;
808 cids[i] = cid;
809 RetPtr[i] = LookupIconIdFromDirectoryEx(igdata,TRUE,GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CYICON),0);
810 }
811
812 iconresdir=GetResDirEntryW(rootresdir,RT_ICONW,(DWORD)rootresdir,FALSE);
813
814 if (!iconresdir)
815 { WARN("No Iconresourcedirectory!\n");
816 goto end_4; /* failure */
817 }
818
819 for (i=0;i<n;i++)
820 { PIMAGE_RESOURCE_DIRECTORY xresdir;
821 xresdir = GetResDirEntryW(iconresdir,(LPWSTR)(DWORD)RetPtr[i],(DWORD)rootresdir,FALSE);
822 xresdir = GetResDirEntryW(xresdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
823 idataent = (PIMAGE_RESOURCE_DATA_ENTRY)xresdir;
824 idata = NULL;
825
826 /* map virtual to address in image */
827 for (j=0;j<pe_header->FileHeader.NumberOfSections;j++)
828 { if (idataent->OffsetToData < pe_sections[j].VirtualAddress)
829 continue;
830 if (idataent->OffsetToData+idataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
831 continue;
832 idata = peimage+(idataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
833 }
834 if (!idata)
835 { WARN("no matching real address found for icondata!\n");
836 RetPtr[i]=0;
837 continue;
838 }
839 RetPtr[i] = CreateIconFromResourceEx(idata,idataent->Size,TRUE,0x00030000,GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CYICON),0);
840 }
841 goto end_3; /* sucess */
842 }
843 goto end_1; /* return array with icon handles */
844
845/* cleaning up (try & catch would be nicer) */
846end_4: hRet = 0; /* failure */
847end_3: UnmapViewOfFile(peimage); /* success */
848end_2: CloseHandle(fmapping);
849end_1: _lclose( hFile);
850 return hRet;
851}
852
853/*************************************************************************
854 * ExtractAssociatedIcon [SHELL.36]
855 *
856 * Return icon for given file (either from file itself or from associated
857 * executable) and patch parameters if needed.
858 */
859ODINFUNCTION3(HICON, ExtractAssociatedIconA,
860 HINSTANCE, hInst,
861 LPSTR, lpIconPath,
862 LPWORD, lpiIcon)
863{
864 HICON hIcon;
865
866 hIcon = ExtractIconA(hInst, lpIconPath, *lpiIcon);
867
868 if( hIcon < 2 )
869 { if( hIcon == 1 ) /* no icons found in given file */
870 { char tempPath[0x104];
871 UINT uRet = FindExecutableA(lpIconPath,NULL,tempPath);
872
873 if( uRet > 32 && tempPath[0] )
874 { strcpy(lpIconPath,tempPath);
875 hIcon = ExtractIconA(hInst, lpIconPath, *lpiIcon);
876 if( hIcon > 2 )
877 return hIcon;
878 }
879 else hIcon = 0;
880 }
881
882 if( hIcon == 1 )
883 *lpiIcon = 2; /* MSDOS icon - we found .exe but no icons in it */
884 else
885 *lpiIcon = 6; /* generic icon - found nothing */
886
887 GetModuleFileNameA(hInst, lpIconPath, 0x80);
888 hIcon = LoadIconA( hInst, (LPCSTR)*lpiIcon);
889 }
890 return hIcon;
891}
892
Note: See TracBrowser for help on using the repository browser.