{"id":2403,"date":"2006-02-27T11:56:00","date_gmt":"2006-02-27T11:56:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/heaths\/2006\/02\/27\/identifying-windows-installer-file-types\/"},"modified":"2006-02-27T11:56:00","modified_gmt":"2006-02-27T11:56:00","slug":"identifying-windows-installer-file-types","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/setup\/identifying-windows-installer-file-types\/","title":{"rendered":"Identifying Windows Installer File Types"},"content":{"rendered":"<p>I&#8217;ve been writing a number of helpful tools at work such as a tool to <a href=\"\/heaths\/archive\/2006\/02\/14\/532200.aspx\">extract transforms and cabinets from a patch<\/a> and wasn&#8217;t satisfied relying on the file extension to identify a patch, or other Windows Installer file types for that matter. File extensions are only one way to help the shell to invoke actions on files, filter file types in common dialogs, and more.<\/p>\n<p>If you try to open an <i>.msp<\/i> file with the <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/msi\/setup\/msiopendatabase.asp\"><code>MsiOpenDatabase<\/code> function<\/a> you must pass the <code>MSIDBOPEN_PATCHFILE<\/code> flag to the <code>szPersist<\/code> parameter or the function fails. Passing this flag for other Windows Installer file types also results in an error, and this function cannot be used to open <i>.msi<\/i> files. Changing the file extension makes no difference. Obviously something more helps Windows Installer functions validate that files are of a certain type.<\/p>\n<p>Recall from <a href=\"\/heaths\/archive\/2005\/09\/01\/459561.aspx\">What&#8217;s in a Patch<\/a> that Windows Installer relies on OLE structure storage. Embedded transforms are stored as sub-storage while embedded cabinets and binary data fields are streams. Sub-storages are identified by class identifiers (<code>CLSID<\/code>s) you can get using structured storages functions. You can open any of the supported Windows Installer types with the <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/stg\/stg\/stgopenstorage.asp\"><code>StgOpenStorage<\/code><\/a> and the <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/stg\/stg\/stgopenstorageex.asp\"><code>StgOpenStorageEx<\/code><\/a> functions. This provides a pointer to the <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/stg\/stg\/istorage.asp\"><code>IStorage<\/code> interface<\/a>, and with the pointer we can call the <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/stg\/stg\/istorage_stat.asp\"><code>IStorage::Stat<\/code> method<\/a>. That provides a <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/stg\/stg\/statstg.asp\"><code>STATSTG<\/code> structure<\/a> that contains the <code>CLSID<\/code> for the storage. If you compare the <code>CLSID<\/code> values for the various Windows Installer file types, you&#8217;ll find a few differences as seen in the table below.<\/p>\n<table cellspacing=\"2\" cellpadding=\"0\" border=\"0\">\n<thead>\n<tr>\n<td>\n<p><b>Description<\/b><\/p>\n<\/td>\n<td>\n<p><b>Extension<\/b><\/p>\n<\/td>\n<td>\n<p><b>CLSID<\/b><\/p>\n<\/td>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n<p>Installer Package<\/p>\n<\/td>\n<td>\n<p>msi<\/p>\n<\/td>\n<td>\n<p><code>{000C1084-0000-0000-C000-000000000046}<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p>Merge Module<\/p>\n<\/td>\n<td>\n<p>msm<\/p>\n<\/td>\n<td>\n<p><code>{000C1084-0000-0000-C000-000000000046}<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p>Patch Package<\/p>\n<\/td>\n<td>\n<p>msp<\/p>\n<\/td>\n<td>\n<p><code>{000C1086-0000-0000-C000-000000000046}<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p>Transform<\/p>\n<\/td>\n<td>\n<p>mst<\/p>\n<\/td>\n<td>\n<p><code>{000C1082-0000-0000-C000-000000000046}<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p>Patch Creation Properties<\/p>\n<\/td>\n<td>\n<p>pcp<\/p>\n<\/td>\n<td>\n<p><code>{000C1084-0000-0000-C000-000000000046}<\/code><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Keep in mind that this information could change any time. That said, the Windows Installer team is typically pretty good about maintaining backward compatibility. To discover this information, example code follows.<\/p>\n<p><font face=\"monospace\">HRESULT hr = NOERROR;<br \/>LPSTORAGE pStorage = NULL;<br \/>STATSTG stg = { 0 };<br \/><font color=\"blue\">const int<\/font> cchCLSID = 40;<br \/>OLECHAR szCLSID[cchCLSID];<\/p>\n<p><font color=\"green\">\/\/ Argument validation excluded for brevity.<\/font><\/p>\n<p><font color=\"green\">\/\/ Open the storage file exclusively. Files like MSPs seem to require this flag.<\/font><br \/>hr = StgOpenStorage(argv[1], NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &amp;pStorage);<br \/><font color=\"blue\">if<\/font> (SUCCEEDED(hr) &amp;&amp; pStorage)<br \/>{<br \/>&nbsp;&nbsp;&nbsp;&nbsp;<font color=\"green\">\/\/ Get the stats for the storage document.<\/font><br \/>&nbsp;&nbsp;&nbsp;&nbsp;pStorage-&gt;Stat(&amp;stg, STATFLAG_DEFAULT);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;<font color=\"green\">\/\/ Print STATSTG.clsid.<\/font><br \/>&nbsp;&nbsp;&nbsp;&nbsp;if (StringFromGUID2(stg.clsid, szCLSID, cchCLSID))<br \/>&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wprintf(L<font color=\"maroon\">&#8220;%sn&#8221;<\/font>, szCLSID);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;}<br \/>&nbsp;&nbsp;&nbsp;&nbsp;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;CoTaskMemFree(stg.pwcsName);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;pStorage-&gt;Release();<br \/>&nbsp;&nbsp;&nbsp;&nbsp;pStorage = NULL;<br \/>}<\/font><\/p>\n<p>For use in C and C++ source code, example definitions follow:<\/p>\n<p><font face=\"monospace\">EXTERN_C <font color=\"blue\">const<\/font> CLSID CLSID_MsiTransform = {0xC1082, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};<br \/>EXTERN_C <font color=\"blue\">const<\/font> CLSID CLSID_MsiPackage = {0xC1084, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};<br \/>EXTERN_C <font color=\"blue\">const<\/font> CLSID CLSID_MsiPatch = {0xC1086, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};<\/font><\/p>\n<p>You can <a href=\"http:\/\/hstewart.members.winisp.net\/downloads\/StgStats.zip\">download<\/a> the full implementation for a tool to print all <code>STATSTG<\/code> fields for structured storage files using the <a href=\"http:\/\/msdn.microsoft.com\/library\/en-us\/stg\/stg\/istorage_compound_file_implementation.asp\">compound file implementation<\/a>.<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been writing a number of helpful tools at work such as a tool to extract transforms and cabinets from a patch and wasn&#8217;t satisfied relying on the file extension to identify a patch, or other Windows Installer file types for that matter. File extensions are only one way to help the shell to invoke [&hellip;]<\/p>\n","protected":false},"author":389,"featured_media":3843,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[14,20],"class_list":["post-2403","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-development","tag-installation"],"acf":[],"blog_post_summary":"<p>I&#8217;ve been writing a number of helpful tools at work such as a tool to extract transforms and cabinets from a patch and wasn&#8217;t satisfied relying on the file extension to identify a patch, or other Windows Installer file types for that matter. File extensions are only one way to help the shell to invoke [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/posts\/2403","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/users\/389"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/comments?post=2403"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/posts\/2403\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/media\/3843"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/media?parent=2403"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/categories?post=2403"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/setup\/wp-json\/wp\/v2\/tags?post=2403"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}