private static void saveStorage(VsInterop.IStorage storage, string saveDirectory, string storageName, string storageExtension) { Trace.Assert(storage != null); Trace.Assert(!string.IsNullOrWhiteSpace(saveDirectory)); VsInterop.IStorage sourceStorage = null; storage.OpenStorage(storageName, null, (uint)(STGM.STGM_READ | STGM.STGM_SHARE_EXCLUSIVE), IntPtr.Zero, 0, out sourceStorage); if (sourceStorage != null) { string savePath = saveDirectory + Path.DirectorySeparatorChar + storageName + (storageExtension == null ? string.Empty : storageExtension); Console.WriteLine(@"Extracting: ""{0}""", savePath); VsInterop.IStorage destinationStorage = null; HRESULT hr = NativeMethods.StgCreateDocfile(savePath, STGM.STGM_WRITE | STGM.STGM_SHARE_EXCLUSIVE | STGM.STGM_CREATE, 0, out destinationStorage); if (HResultHelper.IsSucceeded(hr) && destinationStorage != null) { sourceStorage.CopyTo(0, null, IntPtr.Zero, destinationStorage); } else { throw new Exception(string.Format(@"Failed: StgCreateDocfile(): Failed to create storage ""{0}""", savePath)); } } else { throw new Exception(string.Format(@"Failed: OpenStorage(): Failed to save storage ""{0}""", storageName)); } }
static void Main(string[] args) { string extractDir = @"F:\Takatano\Desktop\experiment\storages"; bool includeExtension = true; string msiFilePath = @"F:\Takatano\Projects\MsixEx\NDP45-KB3037581.msp"; VsInterop.IStorage rootStorage = null; HRESULT hr = NativeMethods.StgOpenStorage(msiFilePath, null, STGM.STGM_READ | STGM.STGM_SHARE_EXCLUSIVE, null, 0, out rootStorage); if (HResultHelper.IsSucceeded(hr) && rootStorage != null) { // // もしかすると、この辺関係ないかも // (構造を維持して展開できれば、話は違うかも) // //VsInterop.IEnumSTATSTG enumStatStg = null; //rootStorage.EnumElements(0, IntPtr.Zero, 0, out enumStatStg); //if (enumStatStg != null) //{ // while (true) // { // VsInterop.STATSTG[] stg = new VsInterop.STATSTG[1]; // uint fetched; // hr = (HRESULT)enumStatStg.Next(1, stg, out fetched); // if (hr == HRESULT.S_FALSE) // { // break; // } // if (hr != HRESULT.S_OK) // { // throw new Exception(@"Failed: IEnumSTATSTG.Next(): Failed to enumerate next storage status"); // } // Console.WriteLine(@"Name:{0}, Type:{1}", stg[0].pwcsName, stg[0].type); // if ((VsInterop.STGTY)stg[0].type == VsInterop.STGTY.STGTY_STORAGE) // { // saveStorage(rootStorage, extractDir, stg[0].pwcsName, includeExtension ? @".mst" : null); // } // //if (stg.pwcsName) // //{ // // CoTaskMemFree(stg.pwcsName); // これ必要なのかも, Marshal.FreeCoTaskMem(), string になっているし、不要かな。 // // stg.pwcsName = NULL; // //} // } // Marshal.ReleaseComObject(enumStatStg); //} // // A Database and Patch Example // https://msdn.microsoft.com/en-us/library/aa367813(v=vs.85).aspx // // http://www.pinvoke.net/default.aspx/msi.msirecordsetstring // http://blogs.msdn.com/b/heaths/archive/2006/03/31/566288.aspx // MsiDbOpenPersist msiDbOpenPersist = MsiDbOpenPersist.MSIDBOPEN_READONLY; if (isPatch(rootStorage)) { msiDbOpenPersist = MsiDbOpenPersist.MSIDBOPEN_READONLY | MsiDbOpenPersist.MSIDBOPEN_PATCHFILE; } // Release COM object of root storage. Marshal.ReleaseComObject(rootStorage); IntPtr msiDatabaseHandle = IntPtr.Zero; uint err = NativeMethods.MsiOpenDatabase(msiFilePath, new IntPtr((uint)msiDbOpenPersist), out msiDatabaseHandle); if (err == WinError.ERROR_SUCCESS) { IntPtr msiViewHandle = IntPtr.Zero; err = NativeMethods.MsiDatabaseOpenView(msiDatabaseHandle, @"SELECT Name, Data FROM _Streams", out msiViewHandle); if (err == WinError.ERROR_SUCCESS) { err = NativeMethods.MsiViewExecute(msiViewHandle, IntPtr.Zero); if (err == WinError.ERROR_SUCCESS) { while (true) { IntPtr msiRecordHandle = IntPtr.Zero; err = NativeMethods.MsiViewFetch(msiViewHandle, out msiRecordHandle); if (err != WinError.ERROR_SUCCESS) { break; } saveStream(msiRecordHandle, extractDir, includeExtension); NativeMethods.MsiCloseHandle(msiRecordHandle); } } } // Close MSI view handle. if (msiViewHandle != IntPtr.Zero) { NativeMethods.MsiCloseHandle(msiViewHandle); } } // Close MSI database handle. if (msiDatabaseHandle != IntPtr.Zero) { NativeMethods.MsiCloseHandle(msiDatabaseHandle); } } else { throw new Exception(string.Format(@"Failed: StgOpenStorage(): Failed to open root storage ""{0}""", msiFilePath)); } }