Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

extract.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * 00003 * Module Name: extract.c 00004 * 00005 * Copyright (c) 1985 - 1999, Microsoft Corporation 00006 * 00007 * Icon Extraction Routines 00008 * 00009 * History: 00010 \***************************************************************************/ 00011 00012 #include "precomp.h" 00013 #pragma hdrstop 00014 #include "newexe.h" 00015 00016 /**************************************************************************** 00017 ****************************************************************************/ 00018 00019 #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) 00020 00021 #define ICON_MAGIC 0 00022 #define ICO_MAGIC1 1 00023 #define CUR_MAGIC1 2 00024 #define BMP_MAGIC ((WORD)'B'+((WORD)'M'<<8)) 00025 #define ANI_MAGIC ((WORD)'R'+((WORD)'I'<<8)) 00026 #define ANI_MAGIC1 ((WORD)'F'+((WORD)'F'<<8)) 00027 #define ANI_MAGIC4 ((WORD)'A'+((WORD)'C'<<8)) 00028 #define ANI_MAGIC5 ((WORD)'O'+((WORD)'N'<<8)) 00029 #define MZMAGIC ((WORD)'M'+((WORD)'Z'<<8)) 00030 #define PEMAGIC ((WORD)'P'+((WORD)'E'<<8)) 00031 #define LEMAGIC ((WORD)'L'+((WORD)'E'<<8)) 00032 00033 typedef struct new_exe NEWEXE, *LPNEWEXE; 00034 typedef struct exe_hdr EXEHDR, *LPEXEHDR; 00035 typedef struct rsrc_nameinfo RESNAMEINFO, *LPRESNAMEINFO; 00036 typedef struct rsrc_typeinfo RESTYPEINFO, *LPRESTYPEINFO; 00037 typedef struct rsrc_typeinfo UNALIGNED *ULPRESTYPEINFO; 00038 typedef struct new_rsrc RESTABLE, *LPRESTABLE; 00039 00040 #define RESOURCE_VA(x) ((x)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress) 00041 #define RESOURCE_SIZE(x) ((x)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size) 00042 #define NUMBER_OF_SECTIONS(x) ((x)->FileHeader.NumberOfSections) 00043 00044 #define FCC(c0,c1,c2,c3) ((DWORD)(c0)|((DWORD)(c1)<<8)|((DWORD)(c2)<<16)|((DWORD)(c3)<<24)) 00045 00046 #define COM_FILE FCC('.', 'c', 'o', 'm') 00047 #define BAT_FILE FCC('.', 'b', 'a', 't') 00048 #define CMD_FILE FCC('.', 'c', 'm', 'd') 00049 #define PIF_FILE FCC('.', 'p', 'i', 'f') 00050 #define LNK_FILE FCC('.', 'l', 'n', 'k') 00051 #define ICO_FILE FCC('.', 'i', 'c', 'o') 00052 #define EXE_FILE FCC('.', 'e', 'x', 'e') 00053 00054 00055 #define WIN32VER30 0x00030000 // for CreateIconFromResource() 00056 00057 #define GET_COUNT 424242 00058 00059 00060 /***************************************************************************\ 00061 * PathIsUNC 00062 * 00063 * Inline function to check for a double-backslash at the 00064 * beginning of a string 00065 * 00066 \***************************************************************************/ 00067 00068 __inline BOOL PathIsUNC( 00069 LPWSTR psz) 00070 { 00071 return (psz[0] == L'\\' && psz[1] == L'\\'); 00072 } 00073 00074 /***************************************************************************\ 00075 * ReadAByte 00076 * 00077 * This is used to touch memory to assure that if we page-fault, it is 00078 * outside win16lock. Most icons aren't more than two pages. 00079 * 00080 \***************************************************************************/ 00081 00082 BOOL ReadAByte( 00083 LPCVOID pMem) 00084 { 00085 return ((*(PBYTE)pMem) == 0); 00086 } 00087 00088 /***************************************************************************\ 00089 * RVAtoP 00090 * 00091 * 00092 \***************************************************************************/ 00093 00094 LPVOID RVAtoP( 00095 LPVOID pBase, 00096 DWORD rva) 00097 { 00098 LPEXEHDR pmz; 00099 IMAGE_NT_HEADERS *ppe; 00100 IMAGE_SECTION_HEADER *pSection; // section table 00101 int i; 00102 DWORD size; 00103 00104 pmz = (LPEXEHDR)pBase; 00105 ppe = (IMAGE_NT_HEADERS*)((BYTE*)pBase + pmz->e_lfanew); 00106 00107 /* 00108 * Scan the section table looking for the RVA 00109 */ 00110 pSection = IMAGE_FIRST_SECTION(ppe); 00111 00112 for (i = 0; i < NUMBER_OF_SECTIONS(ppe); i++) { 00113 00114 size = pSection[i].Misc.VirtualSize ? 00115 pSection[i].Misc.VirtualSize : pSection[i].SizeOfRawData; 00116 00117 if (rva >= pSection[i].VirtualAddress && 00118 rva < pSection[i].VirtualAddress + size) { 00119 00120 return (LPBYTE)pBase + pSection[i].PointerToRawData + (rva - pSection[i].VirtualAddress); 00121 } 00122 } 00123 00124 return NULL; 00125 } 00126 00127 /***************************************************************************\ 00128 * GetResourceTablePE 00129 * 00130 * 00131 \***************************************************************************/ 00132 00133 LPVOID GetResourceTablePE( 00134 LPVOID pBase) 00135 { 00136 LPEXEHDR pmz; 00137 IMAGE_NT_HEADERS *ppe; 00138 00139 pmz = (LPEXEHDR)pBase; 00140 ppe = (IMAGE_NT_HEADERS*)((BYTE*)pBase + pmz->e_lfanew); 00141 00142 if (pmz->e_magic != MZMAGIC) 00143 return 0; 00144 00145 if (ppe->Signature != IMAGE_NT_SIGNATURE) 00146 return 0; 00147 00148 if (ppe->FileHeader.SizeOfOptionalHeader < IMAGE_SIZEOF_NT_OPTIONAL_HEADER) 00149 return 0; 00150 00151 return RVAtoP(pBase, RESOURCE_VA(ppe)); 00152 } 00153 00154 /**************************************************************************** 00155 * FindResourcePE 00156 * 00157 * given a PE resource directory will find a resource in it. 00158 * 00159 * if iResIndex < 0 we will search for the specific index 00160 * if iResIndex >= 0 we will return the Nth index 00161 * if iResIndex == GET_COUNT the count of resources will be returned 00162 * 00163 \*****************************************************************************/ 00164 00165 LPVOID FindResourcePE( 00166 LPVOID pBase, 00167 LPVOID prt, 00168 int iResIndex, 00169 int ResType, 00170 DWORD *pcb) 00171 { 00172 int i; 00173 int cnt; 00174 IMAGE_RESOURCE_DIRECTORY *pdir; 00175 IMAGE_RESOURCE_DIRECTORY_ENTRY *pres; 00176 IMAGE_RESOURCE_DATA_ENTRY *pent; 00177 00178 pdir = (IMAGE_RESOURCE_DIRECTORY *)prt; 00179 00180 /* 00181 * First find the type always a ID so ignore strings totaly 00182 */ 00183 cnt = pdir->NumberOfIdEntries + pdir->NumberOfNamedEntries; 00184 pres = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pdir+1); 00185 00186 for (i = 0; i < cnt; i++) { 00187 00188 if (pres[i].Name == (DWORD)ResType) 00189 break; 00190 } 00191 00192 if (i==cnt) // did not find the type 00193 return 0; 00194 00195 /* 00196 * Now go find the actual resource either by id (iResIndex < 0) or 00197 * by ordinal (iResIndex >= 0) 00198 */ 00199 pdir = (IMAGE_RESOURCE_DIRECTORY*)((LPBYTE)prt + 00200 (pres[i].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY)); 00201 00202 cnt = pdir->NumberOfIdEntries + pdir->NumberOfNamedEntries; 00203 pres = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pdir+1); 00204 00205 /* 00206 * If we just want size, do it. 00207 */ 00208 if (iResIndex == GET_COUNT) 00209 return (LPVOID)UIntToPtr( cnt ); 00210 00211 /* 00212 * if we are to search for a specific id do it. 00213 */ 00214 if (iResIndex < 0) { 00215 00216 for (i = 0; i < cnt; i++) 00217 if (pres[i].Name == (DWORD)(-iResIndex)) 00218 break; 00219 } else { 00220 i = iResIndex; 00221 } 00222 00223 /* 00224 * is the index in range? 00225 */ 00226 if (i >= cnt) 00227 return 0; 00228 00229 /* 00230 * if we get this far the resource has a language part, ick! 00231 * !!!for now just punt and return the first one. 00232 * !!!BUGBUG we dont handle multi-language icons 00233 */ 00234 if (pres[i].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY) { 00235 00236 pdir = (IMAGE_RESOURCE_DIRECTORY*)((LPBYTE)prt + 00237 (pres[i].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY)); 00238 pres = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pdir+1); 00239 i = 0; // choose first one 00240 } 00241 00242 /* 00243 * Nested way to deep for me! 00244 */ 00245 if (pres[i].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY) 00246 return 0; 00247 00248 pent = (IMAGE_RESOURCE_DATA_ENTRY*)((LPBYTE)prt + pres[i].OffsetToData); 00249 00250 /* 00251 * all OffsetToData fields except the final one are relative to 00252 * the start of the section. the final one is a virtual address 00253 * we need to go back to the header and get the virtual address 00254 * of the resource section to do this right. 00255 */ 00256 *pcb = pent->Size; 00257 return RVAtoP(pBase, pent->OffsetToData); 00258 } 00259 00260 /***************************************************************************\ 00261 * GetResourceTableNE 00262 * 00263 * 00264 \***************************************************************************/ 00265 00266 LPVOID GetResourceTableNE( 00267 LPVOID pBase) 00268 { 00269 LPNEWEXE pne; 00270 LPEXEHDR pmz; 00271 00272 pmz = (LPEXEHDR)pBase; 00273 pne = (LPNEWEXE)((LPBYTE)pBase + pmz->e_lfanew); 00274 00275 if (pmz->e_magic != MZMAGIC) 00276 return 0; 00277 00278 if (pne->ne_magic != NEMAGIC) // must be a NEWEXE 00279 return 0; 00280 00281 if (pne->ne_exetyp != NE_WINDOWS && // must be a Win DLL/EXE/386 00282 pne->ne_exetyp != NE_DEV386) 00283 return 0; 00284 00285 if (pne->ne_expver < 0x0300) // must be 3.0 or greater 00286 return 0; 00287 00288 if (pne->ne_rsrctab == pne->ne_restab) // no resources 00289 return 0; 00290 00291 return (LPBYTE)pne + pne->ne_rsrctab; // return resource table pointer 00292 } 00293 00294 /***************************************************************************\ 00295 * FindResourceNE 00296 * 00297 * This returns a pointer to the rsrc_nameinfo of the resource with the 00298 * given index and type, if it is found, otherwise it returns NULL. 00299 * 00300 * if iResIndex is < 0, then it is assumed to be a ID and the res table 00301 * will be searched for a matching id. 00302 * 00303 * if iResIndex is >= 0, then it is assumed to be a index and the Nth 00304 * resorce of the specifed type will be returned. 00305 * 00306 * if iResIndex == GET_COUNT the count of resources will be returned 00307 * 00308 \***************************************************************************/ 00309 00310 LPVOID FindResourceNE( 00311 LPVOID lpBase, 00312 LPVOID prt, 00313 int iResIndex, 00314 int iResType, 00315 DWORD *pcb) 00316 { 00317 LPRESTABLE lpResTable; 00318 ULPRESTYPEINFO ulpResTypeInfo; 00319 LPRESNAMEINFO lpResNameInfo; // 16 bit alignment ok - had ushorts only 00320 int i; 00321 00322 lpResTable = (LPRESTABLE)prt; 00323 //ulpResTypeInfo = (ULPRESTYPEINFO)(LPWBYTE)&lpResTable->rs_typeinfo; 00324 ulpResTypeInfo = (ULPRESTYPEINFO)((LPBYTE)lpResTable + 2); 00325 00326 while (ulpResTypeInfo->rt_id) { 00327 00328 if (ulpResTypeInfo->rt_id == (iResType | RSORDID)) { 00329 00330 lpResNameInfo = (LPRESNAMEINFO)(ulpResTypeInfo + 1); 00331 00332 if (iResIndex == GET_COUNT) 00333 return (LPVOID)ulpResTypeInfo->rt_nres; 00334 00335 if (iResIndex < 0) { 00336 00337 for (i=0; i < (int)ulpResTypeInfo->rt_nres; i++) { 00338 00339 if (lpResNameInfo[i].rn_id == ((-iResIndex) | RSORDID)) 00340 break; 00341 } 00342 00343 iResIndex = i; 00344 } 00345 00346 if (iResIndex >= (int)ulpResTypeInfo->rt_nres) 00347 return NULL; 00348 00349 *pcb = ((DWORD)lpResNameInfo[iResIndex].rn_length) << lpResTable->rs_align; 00350 return (LPBYTE)lpBase + ((long)lpResNameInfo[iResIndex].rn_offset << lpResTable->rs_align); 00351 } 00352 00353 ulpResTypeInfo = 00354 (ULPRESTYPEINFO)((LPRESNAMEINFO)(ulpResTypeInfo + 1) + 00355 ulpResTypeInfo->rt_nres); 00356 } 00357 00358 *pcb = 0; 00359 return NULL; 00360 } 00361 00362 /***************************************************************************\ 00363 * ExtractIconFromICO 00364 * 00365 * 00366 \***************************************************************************/ 00367 00368 UINT ExtractIconFromICO( 00369 LPTSTR szFile, 00370 int nIconIndex, 00371 int cxIcon, 00372 int cyIcon, 00373 HICON *phicon, 00374 UINT flags) 00375 { 00376 HICON hicon; 00377 00378 if (nIconIndex >= 1) 00379 return 0; 00380 00381 flags |= LR_LOADFROMFILE; 00382 00383 again: 00384 00385 hicon = LoadImage(NULL, 00386 szFile, 00387 IMAGE_ICON, 00388 LOWORD(cxIcon), 00389 LOWORD(cyIcon), 00390 flags); 00391 00392 if (hicon == NULL) 00393 return 0; 00394 00395 /* 00396 * Do we just want a count? 00397 */ 00398 if (phicon == NULL) 00399 DestroyCursor((HCURSOR)hicon); 00400 else 00401 *phicon = hicon; 00402 00403 /* 00404 * Check for large/small icon extract 00405 */ 00406 if (HIWORD(cxIcon)) { 00407 00408 cxIcon = HIWORD(cxIcon); 00409 cyIcon = HIWORD(cyIcon); 00410 phicon++; 00411 00412 goto again; 00413 } 00414 00415 return 1; 00416 } 00417 00418 /***************************************************************************\ 00419 * ExtractIconFromBMP 00420 * 00421 * 00422 \***************************************************************************/ 00423 00424 #define ROP_DSna 0x00220326 00425 00426 UINT ExtractIconFromBMP( 00427 LPTSTR szFile, 00428 int nIconIndex, 00429 int cxIcon, 00430 int cyIcon, 00431 HICON *phicon, 00432 UINT flags) 00433 { 00434 HICON hicon; 00435 HBITMAP hbm; 00436 HBITMAP hbmMask; 00437 HDC hdc; 00438 HDC hdcMask; 00439 ICONINFO ii; 00440 00441 if (nIconIndex >= 1) 00442 return 0; 00443 00444 /* 00445 * BUGUS: don't use LR_CREATEDIBSECTION. USER can't make an icon out 00446 * of a DibSection. 00447 */ 00448 flags |= LR_LOADFROMFILE; 00449 00450 again: 00451 00452 hbm = (HBITMAP)LoadImage(NULL, 00453 szFile, 00454 IMAGE_BITMAP, 00455 LOWORD(cxIcon), 00456 LOWORD(cyIcon), 00457 flags); 00458 00459 if (hbm == NULL) 00460 return 0; 00461 00462 /* 00463 * do we just want a count? 00464 */ 00465 if (phicon == NULL) { 00466 DeleteObject(hbm); 00467 return 1; 00468 } 00469 00470 hbmMask = CreateBitmap(LOWORD(cxIcon), LOWORD(cyIcon), 1, 1, NULL); 00471 00472 hdc = CreateCompatibleDC(NULL); 00473 SelectObject(hdc, hbm); 00474 00475 hdcMask = CreateCompatibleDC(NULL); 00476 SelectObject(hdcMask, hbmMask); 00477 00478 SetBkColor(hdc, GetPixel(hdc, 0, 0)); 00479 00480 BitBlt(hdcMask, 0, 0, LOWORD(cxIcon), LOWORD(cyIcon), hdc, 0, 0, SRCCOPY); 00481 BitBlt(hdc, 0, 0, LOWORD(cxIcon), LOWORD(cyIcon), hdcMask, 0, 0, ROP_DSna); 00482 00483 ii.fIcon = TRUE; 00484 ii.xHotspot = 0; 00485 ii.yHotspot = 0; 00486 ii.hbmColor = hbm; 00487 ii.hbmMask = hbmMask; 00488 hicon = CreateIconIndirect(&ii); 00489 00490 DeleteObject(hdc); 00491 DeleteObject(hbm); 00492 DeleteObject(hdcMask); 00493 DeleteObject(hbmMask); 00494 00495 *phicon = hicon; 00496 00497 /* 00498 * Check for large/small icon extract 00499 */ 00500 if (HIWORD(cxIcon)) { 00501 cxIcon = HIWORD(cxIcon); 00502 cyIcon = HIWORD(cyIcon); 00503 phicon++; 00504 00505 goto again; 00506 } 00507 00508 return 1; 00509 } 00510 00511 /***************************************************************************\ 00512 * ExtractIconFromEXE 00513 * 00514 * 00515 \***************************************************************************/ 00516 00517 UINT ExtractIconFromEXE( 00518 HANDLE hFile, 00519 int nIconIndex, 00520 int cxIconSize, 00521 int cyIconSize, 00522 HICON *phicon, 00523 UINT *piconid, 00524 UINT nIcons, 00525 UINT flags) 00526 { 00527 HANDLE hFileMap = INVALID_HANDLE_VALUE; 00528 LPVOID lpFile = NULL; 00529 EXEHDR *pmz; 00530 NEWEXE UNALIGNED *pne; 00531 LPVOID pBase; 00532 LPVOID pres = NULL; 00533 UINT result = 0; 00534 LONG FileLength; 00535 DWORD cbSize; 00536 int cxIcon; 00537 int cyIcon; 00538 00539 LPVOID (*FindResourceX)(LPVOID pBase, 00540 LPVOID prt, 00541 int iResIndex, 00542 int iResType, 00543 DWORD *pcb); 00544 00545 FileLength = (LONG)GetFileSize(hFile, NULL); 00546 00547 hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); 00548 if (hFileMap == NULL) 00549 goto exit; 00550 00551 lpFile = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0); 00552 if (lpFile == NULL) 00553 goto exit; 00554 00555 pBase = (LPVOID)lpFile; 00556 pmz = (struct exe_hdr *)pBase; 00557 00558 _try { 00559 00560 if (pmz->e_magic != MZMAGIC) 00561 goto exit; 00562 00563 if (pmz->e_lfanew <= 0) // not a new exe 00564 goto exit; 00565 00566 if (pmz->e_lfanew >= FileLength) // not a new exe 00567 goto exit; 00568 00569 pne = (NEWEXE UNALIGNED *)((BYTE*)pmz + pmz->e_lfanew); 00570 00571 switch (pne->ne_magic) { 00572 case NEMAGIC: 00573 pres = GetResourceTableNE(pBase); 00574 FindResourceX = FindResourceNE; 00575 break; 00576 00577 case PEMAGIC: 00578 pres = GetResourceTablePE(pBase); 00579 FindResourceX = FindResourcePE; 00580 break; 00581 } 00582 00583 /* 00584 * cant find the resource table, fail 00585 */ 00586 if (pres == NULL) 00587 goto exit; 00588 00589 /* 00590 * do we just want a count? 00591 */ 00592 if (phicon == NULL) { 00593 result = PtrToUlong(FindResourceX(pBase, 00594 pres, 00595 GET_COUNT, 00596 (LONG_PTR)RT_GROUP_ICON, 00597 &cbSize)); 00598 goto exit; 00599 } 00600 00601 while (result < nIcons) { 00602 00603 LPVOID lpIconDir; 00604 LPVOID lpIcon; 00605 int idIcon; 00606 00607 cxIcon = cxIconSize; 00608 cyIcon = cyIconSize; 00609 00610 /* 00611 * find the icon dir for this icon. 00612 */ 00613 lpIconDir = FindResourceX(pBase, 00614 pres, 00615 nIconIndex, 00616 (LONG_PTR)RT_GROUP_ICON, 00617 &cbSize); 00618 00619 if (lpIconDir == NULL) 00620 goto exit; 00621 00622 if ((((LPNEWHEADER)lpIconDir)->Reserved != 0) || 00623 (((LPNEWHEADER)lpIconDir)->ResType != FT_ICON)) { 00624 00625 goto exit; 00626 } 00627 again: 00628 idIcon = LookupIconIdFromDirectoryEx((LPBYTE)lpIconDir, 00629 TRUE, 00630 LOWORD(cxIcon), 00631 LOWORD(cyIcon), 00632 flags); 00633 lpIcon = FindResourceX(pBase, 00634 pres, 00635 -idIcon, 00636 (LONG_PTR)RT_ICON, 00637 &cbSize); 00638 00639 if (lpIcon == NULL) 00640 goto exit; 00641 00642 if ((((UPBITMAPINFOHEADER)lpIcon)->biSize != sizeof(BITMAPINFOHEADER)) && 00643 (((UPBITMAPINFOHEADER)lpIcon)->biSize != sizeof(BITMAPCOREHEADER))) { 00644 00645 goto exit; 00646 } 00647 00648 #ifndef WINNT 00649 /* touch this memory before calling USER 00650 * so if we page fault we will do it outside of the Win16Lock 00651 * most icons aren't more than 2 pages 00652 */ 00653 ReadAByte(((BYTE *)lpIcon) + cbSize - 1); 00654 #endif 00655 00656 if (piconid) 00657 piconid[result] = idIcon; 00658 00659 phicon[result++] = CreateIconFromResourceEx((LPBYTE)lpIcon, 00660 cbSize, 00661 TRUE, 00662 WIN32VER30, 00663 LOWORD(cxIcon), 00664 LOWORD(cyIcon), 00665 flags); 00666 00667 /* 00668 * check for large/small icon extract 00669 */ 00670 if (HIWORD(cxIcon)) { 00671 00672 cxIcon = HIWORD(cxIcon); 00673 cyIcon = HIWORD(cyIcon); 00674 00675 goto again; 00676 } 00677 00678 nIconIndex++; // next icon index 00679 } 00680 00681 } _except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00682 result = 0; 00683 } 00684 00685 exit: 00686 00687 if (lpFile) 00688 UnmapViewOfFile(lpFile); 00689 00690 if (hFileMap != INVALID_HANDLE_VALUE) 00691 CloseHandle(hFileMap); 00692 00693 return result; 00694 } 00695 00696 /***************************************************************************\ 00697 * PathFindExtension 00698 * 00699 * 00700 \***************************************************************************/ 00701 00702 LPWSTR PathFindExtension( 00703 LPWSTR pszPath) 00704 { 00705 LPWSTR pszDot; 00706 00707 for (pszDot = NULL; *pszPath; pszPath = CharNext(pszPath)) { 00708 00709 switch (*pszPath) { 00710 case L'.': 00711 pszDot = pszPath; // remember the last dot 00712 break; 00713 00714 case L'\\': 00715 case L' ': // extensions can't have spaces 00716 pszDot = NULL; // forget last dot, it was in a directory 00717 break; 00718 } 00719 } 00720 00721 /* 00722 * if we found the extension, return ptr to the dot, else 00723 * ptr to end of the string (NULL extension) (cast->non const) 00724 */ 00725 return pszDot ? (LPWSTR)pszDot : (LPWSTR)pszPath; 00726 } 00727 00728 /***************************************************************************\ 00729 * PrivateExtractIconExA 00730 * 00731 * Ansi version of PrivateExtractIconExW 00732 * 00733 \***************************************************************************/ 00734 00735 WINUSERAPI UINT PrivateExtractIconExA( 00736 LPCSTR szFileName, 00737 int nIconIndex, 00738 HICON *phiconLarge, 00739 HICON *phiconSmall, 00740 UINT nIcons) 00741 { 00742 LPWSTR szFileNameW; 00743 UINT uRet; 00744 00745 if (!MBToWCS(szFileName, -1, &szFileNameW, -1, TRUE)) 00746 return 0; 00747 00748 uRet = PrivateExtractIconExW(szFileNameW, 00749 nIconIndex, 00750 phiconLarge, 00751 phiconSmall, 00752 nIcons); 00753 00754 UserLocalFree(szFileNameW); 00755 00756 return uRet; 00757 } 00758 00759 /***************************************************************************\ 00760 * HasExtension 00761 * 00762 * 00763 \***************************************************************************/ 00764 00765 DWORD HasExtension( 00766 LPWSTR pszPath) 00767 { 00768 LPWSTR p = PathFindExtension(pszPath); 00769 00770 /* 00771 * BUGBUG - BobDay - Shouldn't this limit the length to 4 characters? 00772 * "Fister.Bather" would return .BAT 00773 * 00774 * BUGBUG - BobDay - We could make this EXTKEY based like the extension 00775 * matching stuff elsewhere. EXTKEY is a QWORD value so UNICODE would 00776 * fit. 00777 */ 00778 if (*p == L'.') { 00779 00780 WCHAR szExt[5]; 00781 00782 lstrcpynW(szExt, p, 5); 00783 00784 if (lstrcmpiW(szExt,TEXT(".com")) == 0) return COM_FILE; 00785 if (lstrcmpiW(szExt,TEXT(".bat")) == 0) return BAT_FILE; 00786 if (lstrcmpiW(szExt,TEXT(".cmd")) == 0) return CMD_FILE; 00787 if (lstrcmpiW(szExt,TEXT(".pif")) == 0) return PIF_FILE; 00788 if (lstrcmpiW(szExt,TEXT(".lnk")) == 0) return LNK_FILE; 00789 if (lstrcmpiW(szExt,TEXT(".ico")) == 0) return ICO_FILE; 00790 if (lstrcmpiW(szExt,TEXT(".exe")) == 0) return EXE_FILE; 00791 } 00792 00793 return 0; 00794 } 00795 00796 /***************************************************************************\ 00797 * PrivateExtractIconsW 00798 * 00799 * Extracts 1 or more icons from a file. 00800 * 00801 * input: 00802 * szFileName - EXE/DLL/ICO/CUR/ANI file to extract from 00803 * nIconIndex - what icon to extract 00804 * 0 = first icon, 1=second icon, etc. 00805 * -N = icon with id==N 00806 * cxIcon - icon size wanted (if HIWORD != 0 two sizes...) 00807 * cyIcon - icon size wanted (if HIWORD != 0 two sizes...) 00808 * 0,0 means extract at natural size. 00809 * phicon - place to return extracted icon(s) 00810 * nIcons - number of icons to extract. 00811 * flags - LoadImage LR_* flags 00812 * 00813 * returns: 00814 * if picon is NULL, number of icons in the file is returned. 00815 * 00816 * notes: 00817 * handles extraction from PE (Win32), NE (Win16), ICO (Icon), 00818 * CUR (Cursor), ANI (Animated Cursor), and BMP (Bitmap) files. 00819 * only Win16 3.x files are supported (not 2.x) 00820 * 00821 * cx/cyIcon are the size of the icon to extract, two sizes 00822 * can be extracted by putting size 1 in the loword and size 2 in the 00823 * hiword, ie MAKELONG(24, 48) would extract 24 and 48 size icons. 00824 * yea this is a stupid hack it is done so IExtractIcon::Extract 00825 * can be called by outside people with custom large/small icon 00826 * sizes that are not what the shell uses internaly. 00827 * 00828 \***************************************************************************/ 00829 00830 WINUSERAPI UINT WINAPI PrivateExtractIconsW( 00831 LPCWSTR szFileName, 00832 int nIconIndex, 00833 int cxIcon, 00834 int cyIcon, 00835 HICON *phicon, 00836 UINT *piconid, 00837 UINT nIcons, 00838 UINT flags) 00839 { 00840 HANDLE hFile = (HANDLE)INVALID_HANDLE_VALUE; 00841 UINT result = 0; 00842 WORD magic[6]; 00843 WCHAR achFileName[MAX_PATH]; 00844 FILETIME ftAccess; 00845 WCHAR szExpFileName[MAX_PATH]; 00846 DWORD dwBytesRead; 00847 00848 /* 00849 * Set failure defaults. 00850 */ 00851 if (phicon) 00852 *phicon = NULL; 00853 00854 /* 00855 * Check for special extensions, and fail quick 00856 */ 00857 switch (HasExtension((LPWSTR)szFileName)) { 00858 case COM_FILE: 00859 case BAT_FILE: 00860 case CMD_FILE: 00861 case PIF_FILE: 00862 case LNK_FILE: 00863 goto exit; 00864 00865 default: 00866 break; 00867 } 00868 00869 /* 00870 * Try expanding environment variables in the file name we're passed. 00871 */ 00872 ExpandEnvironmentStrings(szFileName, szExpFileName, MAX_PATH); 00873 szExpFileName[ MAX_PATH-1 ] = (WCHAR)0; 00874 00875 /* 00876 * Open the file - First check to see if it is a UNC path. If it 00877 * is make sure that we have access to the path... 00878 */ 00879 if (PathIsUNC(szExpFileName)) { 00880 00881 lstrcpynW(achFileName, szExpFileName, ARRAYSIZE(achFileName)); // BUGBUG sizeof 00882 00883 } else { 00884 00885 if (SearchPath(NULL, 00886 szExpFileName, 00887 NULL, 00888 ARRAYSIZE(achFileName), 00889 achFileName, NULL) == 0) { 00890 00891 goto error_file; 00892 } 00893 } 00894 00895 hFile = CreateFile(achFileName, 00896 GENERIC_READ|FILE_WRITE_ATTRIBUTES, 00897 FILE_SHARE_WRITE | FILE_SHARE_READ, 00898 NULL, 00899 OPEN_EXISTING, 00900 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, 00901 0); 00902 00903 if (hFile == INVALID_HANDLE_VALUE) { 00904 00905 hFile = CreateFile(achFileName, GENERIC_READ, 00906 FILE_SHARE_READ, 00907 NULL, 00908 OPEN_EXISTING, 00909 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, 00910 0); 00911 00912 if (hFile == INVALID_HANDLE_VALUE) 00913 goto error_file; 00914 00915 } else { 00916 00917 /* 00918 * Restore the Access Date 00919 */ 00920 if (GetFileTime(hFile, NULL, &ftAccess, NULL)) 00921 SetFileTime(hFile, NULL, &ftAccess, NULL); 00922 } 00923 00924 00925 ReadFile(hFile, &magic, sizeof(magic), &dwBytesRead, NULL); 00926 if (dwBytesRead != sizeof(magic)) 00927 goto exit; 00928 00929 if (piconid) 00930 *piconid = (UINT)-1; // Fill in "don't know" value 00931 00932 switch (magic[0]) { 00933 case MZMAGIC: 00934 result = ExtractIconFromEXE(hFile, 00935 nIconIndex, 00936 cxIcon, 00937 cyIcon, 00938 phicon, 00939 piconid, 00940 nIcons, 00941 flags); 00942 break; 00943 00944 case ANI_MAGIC: // possible .ani cursor 00945 00946 /* 00947 * Ani cursors are easy they are RIFF files of type 'ACON' 00948 */ 00949 if (magic[1] == ANI_MAGIC1 && magic[4] == ANI_MAGIC4 && 00950 magic[5] == ANI_MAGIC5) { 00951 00952 result = ExtractIconFromICO(achFileName, 00953 nIconIndex, 00954 cxIcon, 00955 cyIcon, 00956 phicon, 00957 flags); 00958 } 00959 break; 00960 00961 case BMP_MAGIC: // possible bitmap 00962 result = ExtractIconFromBMP(achFileName, 00963 nIconIndex, 00964 cxIcon, 00965 cyIcon, 00966 phicon, 00967 flags); 00968 break; 00969 00970 case ICON_MAGIC: // possible .ico or .cur 00971 00972 /* 00973 * Icons and cursors look like this 00974 * 00975 * iReserved - always zero 00976 * iResourceType - 1 for icons 2 cor cursor. 00977 * cresIcons - number of resolutions in this file 00978 * 00979 * We only allow 1 <= cresIcons <= 10 00980 */ 00981 if ((magic[1] == ICO_MAGIC1 || magic[1] == CUR_MAGIC1) && 00982 magic[2] >= 1 && magic[2] <= 10) { 00983 00984 result = ExtractIconFromICO(achFileName, 00985 nIconIndex, 00986 cxIcon, 00987 cyIcon, 00988 phicon, 00989 flags); 00990 } 00991 break; 00992 } 00993 00994 exit: 00995 00996 if (hFile!=INVALID_HANDLE_VALUE) 00997 CloseHandle(hFile); 00998 00999 return result; 01000 01001 /* 01002 * if we cant open the file, return a code saying we cant open the file 01003 * if phicon==NULL return the count of icons in the file 0 01004 */ 01005 01006 error_file: 01007 01008 result = (phicon ? (UINT)-1 : 0); 01009 01010 goto exit; 01011 } 01012 01013 /***************************************************************************\ 01014 * PrivateExtractIconsA 01015 * 01016 * 01017 \***************************************************************************/ 01018 01019 WINUSERAPI UINT WINAPI PrivateExtractIconsA( 01020 LPCSTR szFileName, 01021 int nIconIndex, 01022 int cxIcon, 01023 int cyIcon, 01024 HICON *phicon, 01025 UINT *piconid, 01026 UINT nIcons, 01027 UINT flags) 01028 { 01029 LPWSTR szFileNameW; 01030 UINT uRet; 01031 01032 if (!MBToWCS(szFileName, -1, &szFileNameW, -1, TRUE)) 01033 return 0; 01034 01035 uRet = PrivateExtractIconsW(szFileNameW, 01036 nIconIndex, 01037 cxIcon, 01038 cyIcon, 01039 phicon, 01040 piconid, 01041 nIcons, 01042 flags); 01043 01044 UserLocalFree(szFileNameW); 01045 01046 return uRet; 01047 } 01048 01049 /***************************************************************************\ 01050 * PrivateExtractIconExW 01051 * 01052 * extracts 1 or more icons from a file. 01053 * 01054 * input: 01055 * szFileName - EXE/DLL/ICO file to extract from 01056 * nIconIndex - what icon to extract 01057 * 0 = first icon, 1=second icon, etc. 01058 * -N = icon with id==N 01059 * phiconLarge - place to return extracted icon(s) 01060 * phiconSmall - place to return extracted icon(s) (small size) 01061 * nIcons - number of icons to extract. 01062 * 01063 * returns: 01064 * number of icons extracted, or the count of icons if phiconLarge==NULL 01065 * 01066 * notes: 01067 * handles extraction from PE (Win32), NE (Win16), and ICO (Icon) files. 01068 * only Win16 3.x files are supported (not 2.x) 01069 * 01070 \***************************************************************************/ 01071 01072 WINUSERAPI UINT PrivateExtractIconExW( 01073 LPCWSTR szFileName, 01074 int nIconIndex, 01075 HICON *phiconLarge, 01076 HICON *phiconSmall, 01077 UINT nIcons) 01078 { 01079 UINT result = 0; 01080 01081 if ((nIconIndex == -1) || ((phiconLarge == NULL) && (phiconSmall == NULL))) 01082 return PrivateExtractIconsW(szFileName, 0, 0, 0, NULL, NULL, 0, 0); 01083 01084 if (phiconLarge && phiconSmall && (nIcons == 1)) { 01085 01086 HICON ahicon[2]; 01087 01088 ahicon[0] = NULL; 01089 ahicon[1] = NULL; 01090 01091 result = PrivateExtractIconsW(szFileName, 01092 nIconIndex, 01093 MAKELONG(GetSystemMetrics(SM_CXICON), 01094 GetSystemMetrics(SM_CXSMICON)), 01095 MAKELONG(GetSystemMetrics(SM_CYICON), 01096 GetSystemMetrics(SM_CYSMICON)), 01097 ahicon, 01098 NULL, 01099 2, 01100 0); 01101 01102 *phiconLarge = ahicon[0]; 01103 *phiconSmall = ahicon[1]; 01104 01105 } else { 01106 01107 if (phiconLarge) 01108 result = PrivateExtractIconsW(szFileName, 01109 nIconIndex, 01110 GetSystemMetrics(SM_CXICON), 01111 GetSystemMetrics(SM_CYICON), 01112 phiconLarge, 01113 NULL, 01114 nIcons, 01115 0); 01116 01117 if (phiconSmall) 01118 result = PrivateExtractIconsW(szFileName, 01119 nIconIndex, 01120 GetSystemMetrics(SM_CXSMICON), 01121 GetSystemMetrics(SM_CYSMICON), 01122 phiconSmall, 01123 NULL, 01124 nIcons, 01125 0); 01126 } 01127 01128 return result; 01129 }

Generated on Sat May 15 19:39:58 2004 for test by doxygen 1.3.7