{"id":7083,"date":"2012-07-20T07:00:00","date_gmt":"2012-07-20T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2012\/07\/20\/the-format-of-icon-resources\/"},"modified":"2012-07-20T07:00:00","modified_gmt":"2012-07-20T07:00:00","slug":"the-format-of-icon-resources","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20120720-00\/?p=7083","title":{"rendered":"The format of icon resources"},"content":{"rendered":"<p>\nIt&#8217;s been a long time since my last entry in the continuing\nsporadic series on resources formats.\nToday we&#8217;ll look at icons.\n<\/p>\n<p>\nRecall that an icon file\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/10\/18\/10077133.aspx\">\nconsists of two parts<\/a>,\nan <i>icon directory<\/i>\n(consisting of an icon directory header followed by a number of\nicon directory entries),\nand then the icon images themselves.\n<\/p>\n<p>\nWhen an icon is stored in resources, each of those parts gets its own\nresource entry.\n<\/p>\n<p>\nThe icon directory (the header plus the directory entries)\nis stored as a resource of type\n<code>RT_GROUP_ICON<\/code>.\nThe format of the icon directory in resources is slightly different\nfrom the format on disk:\n<\/p>\n<pre>\ntypedef struct GRPICONDIR\n{\n    WORD idReserved;\n    WORD idType;\n    WORD idCount;\n    GRPICONDIRENTRY idEntries[];\n} GRPICONDIR;\ntypedef struct GRPICONDIRENTRY\n{\n    BYTE  bWidth;\n    BYTE  bHeight;\n    BYTE  bColorCount;\n    BYTE  bReserved;\n    WORD  wPlanes;\n    WORD  wBitCount;\n    DWORD dwBytesInRes;\n    WORD  nId;\n} GRPICONDIRENTRY;\n<\/pre>\n<p>\nAll the members mean the same thing as in the corresponding\n<code>ICONDIR<\/code> and <code>IconDirectoryEntry<\/code>\nstructures, except for that mysterious <code>nId<\/code>\n(which replaces the <code>dwImageOffset<\/code> from the\n<code>IconDirectoryEntry<\/code>).\nTo unravel that mystery, we need to look at where\nthe rest of the icon file went.\n<\/p>\n<p>\nIn the icon file format,\nthe <code>dwImageOffset<\/code> represented the location\nof the icon bitmap within the file.\nWhen the icon file is converted to a resource,\neach icon bitmap is split off into its own resource\nof type <code>RT_ICON<\/code>.\nThe resource compiler auto-assigns the resource IDs,\nand it is those resource IDs that are stored in the\n<code>nId<\/code> member.\n<\/p>\n<p>\nFor example, suppose you have an icon file with four\nimages.\nIn your resource file you say\n<\/p>\n<pre>\n42 ICON myicon.ico\n<\/pre>\n<p>\nThe resource compiler breaks the file into five resources:\n<\/p>\n<table BORDER=\"1\" CELLPADDING=\"3\" STYLE=\"border-collapse: collapse\">\n<tr>\n<th>Resource type<\/th>\n<th>Resource Id<\/th>\n<th>Contents<\/th>\n<\/tr>\n<tr>\n<td><code>RT_GROUP_ICON<\/code><\/td>\n<td ALIGN=\"right\">42<\/td>\n<td><code>GRPICONDIR.idCount = 4<\/code><br \/>\n        <code>GRPICONDIRENTRY[0].nId = 124<\/code><br \/>\n        <code>GRPICONDIRENTRY[1].nId = 125<\/code><br \/>\n        <code>GRPICONDIRENTRY[2].nId = 126<\/code><br \/>\n        <code>GRPICONDIRENTRY[3].nId = 127<\/code>\n    <\/td>\n<\/tr>\n<tr>\n<td><code>RT_ICON<\/code><\/td>\n<td ALIGN=\"right\">124<\/td>\n<td>Pixels for image 0<\/td>\n<\/tr>\n<tr>\n<td><code>RT_ICON<\/code><\/td>\n<td ALIGN=\"right\">125<\/td>\n<td>Pixels for image 1<\/td>\n<\/tr>\n<tr>\n<td><code>RT_ICON<\/code><\/td>\n<td ALIGN=\"right\">126<\/td>\n<td>Pixels for image 2<\/td>\n<\/tr>\n<tr>\n<td><code>RT_ICON<\/code><\/td>\n<td ALIGN=\"right\">127<\/td>\n<td>Pixels for image 3<\/td>\n<\/tr>\n<\/table>\n<p>\nWhy does Windows break the resources into five pieces instead of just\ndumping them all inside one giant resource?\n<\/p>\n<p>\nRecall\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/02\/02\/66159.aspx\">\nhow 16-bit Windows managed resources<\/a>.\nBack in 16-bit Windows, a resource was a handle into a table,\nand obtaining the bits of the resource involved allocating memory and\nloading it from the disk.\nRecall also that 16-bit Windows operated under tight memory constraints,\nso you didn&#8217;t want to load anything into memory unless you really\nneeded it.\n<\/p>\n<p>\nTherefore, looking up an icon in 16-bit Windows went like this:\n<\/p>\n<ul>\n<li>Find the icon group resource, load it, and lock it.\n<li>Study it to decide which icon image is best.\n<li>Unlock and free the icon group resource since we don&#8217;t need\n    it any more.<\/p>\n<li>Find and load the icon image resource for the one you chose.\n<li>Return that handle as the icon handle.\n<\/ul>\n<p>\nObserve that once we decide which icon image we want,\nthe only memory consumed is the memory for that specific image.\nWe never load the images we don&#8217;t need.\n<\/p>\n<p>\nDrawing an icon went like this:<\/p>\n<ul>\n<li>Lock the icon handle to get access to the pixels.\n<li>Draw the icon.\n<li>Unlock the icon handle.\n<\/ul>\n<p>\nSince icons were usually marked discardable,\nthey could get evicted from memory if necessary,\nand they would get reloaded the next time you tried to draw them.\n<\/p>\n<p>\nAlthough Win32 does not follow the same memory management model\nfor resources as 16-bit Windows,\nit preserved the programming model\n(find, load, lock)\nto make it easier to port programs from 16-bit Windows to 32-bit Windows.\nAnd in order not to break code which loaded icons from resources directly\n(say, because they wanted to replace the icon selection algorithm),\nthe breakdown of an icon file into a directory + images was also preserved.\n<\/p>\n<p>\nYou now know enough to solve this customer&#8217;s problem:\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\nI have an icon in a resource DLL, and I need to pass its raw data\nto another component.\nHowever, the number of bytes reported by\n<code>Size&shy;Of&shy;Resource<\/code> is only 48 instead of 5KB\nwhich is the amount actually stored in the resource DLL.\nI triple-checked the resource DLL and I&#8217;m sure I&#8217;m looking at the\nright icon resource.\n<\/p>\n<p>\nHere is my code:\n<\/p>\n<pre>\nHRSRC hrsrcIcon = FindResource(hResources,\n                     MAKEINTRESOURCE(IDI_MY_ICON), RT_GROUP_ICON);\nDWORD cbIcon = SizeofResource(hResources, hrsrcIcon);\nHGLOBAL hIcon = LoadResource(hResources, hrsrcIcon);\nvoid *lpIcon = LockResource(hIcon);\n<\/pre>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s been a long time since my last entry in the continuing sporadic series on resources formats. Today we&#8217;ll look at icons. Recall that an icon file consists of two parts, an icon directory (consisting of an icon directory header followed by a number of icon directory entries), and then the icon images themselves. When [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-7083","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>It&#8217;s been a long time since my last entry in the continuing sporadic series on resources formats. Today we&#8217;ll look at icons. Recall that an icon file consists of two parts, an icon directory (consisting of an icon directory header followed by a number of icon directory entries), and then the icon images themselves. When [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/7083","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=7083"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/7083\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=7083"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=7083"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=7083"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}