test: extract.c Source File

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 }