The following C# code example illustrates the following functionality: capture; apply; mount; and unmount.
Example
using System; using System.Collections; using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Xml; namespace Microsoft.WimgApi { ///<summary> ///Pulic interface to a WindowsImage object. ///</summary> public interface IImage { ///<summary> ///Gets image information from within a .wim file. ///</summary> XmlTextReader ImageInformation { get; } ///<summary> ///Sets image information about an image within a .wim file. ///</summary> ///<param name="imageInformation">The string being passed in should be in the form of a unicode XML file. ///Calling this function replaces any customized image data. To preserve existing XML information, call ImageInformation ///and append/edit desired data. ///</param> void SetImageInformation( string imageInformation ); ///<summary> ///Mounts an image in a .wim file to the specified directory. ///</summary> void Mount( string pathToMountTo ); ///<summary> ///Retrieves the path to which an image has been mounted. ///</summary> string MountedPath { get; } ///<summary> ///Unmounts a mounted image in a .wim file from the specified directory. ///</summary> ///<param name="commitChanges">Indicates whether changes (if any) to the .wim file should be committed ///before unmounting the .wim file. This flag will have no effect if the .wim file was mounted not to allow edits. ///</param> void DismountImage( bool commitChanges ); ///<summary> ///Applies an image to a drive root or to a directory path from a .wim file. ///</summary> void Apply( string pathToApplyTo ); } ///<summary> ///Class representing a .wim file. ///</summary> public sealed class WindowsImageContainer : IDisposable { ///<summary> ///Specifies the type of access to the .wim file. ///</summary> public enum CreateFileAccess { ///<summary> ///Specifies read-only access to the .wim file. ///</summary> Read ///<summary> ///Specifies write access to the .wim file. ///Includes WIM_GENERIC_READ access to enable apply and append operations with existing images. ///</summary> Write } ///<summary> ///Specifies which action to take on files that exist and ///which action to take when files do not exist. ///</summary> public enum CreateFileMode { ///<summary> ///RESERVED, DO NOT USE! ///</summary> None = 0, ///<summary> ///Creates a new .wim file. The function fails if the specified file already exists. ///</summary> CreateNew = 1, ///<summary> ///Creates a new .wim file. If the file exists, the function overwrites the file. ///</summary> CreateAlways = 2, ///<summary> ///Opens the .wim file. The function fails if the file does not exist. ///</summary> OpenExisting = 3, ///<summary> ///Opens the .wim file if it exists. If the file does not exist and the caller requests WIM_GENERIC_WRITE access, the ///function creates the file. ///</summary> OpenAlways = 4 } ///<summary> ///Public constructor to create a WIM object ///</summary> ///<param name="imageFilePath">Path of WIM to create or to open.</param> ///<param name="mode">Specifies Open, Create, Create/Open disposition of the .wim file.</param> ///<param name="access">Specifies access level of Read Only or Write.</param> //[CLSCompliant(false)] public WindowsImageContainer(string imageFilePath, CreateFileMode mode, CreateFileAccess access) { CreateFileAccessPrivate fileAccess = GetMappedFileAccess(access); if (fileAccess == CreateFileAccessPrivate.Read && (!File.Exists(imageFilePath) || (CreateFileMode.OpenExisting != mode))) { throw new System.UnauthorizedAccessException(string.Format(CultureInfo.CurrentCulture, "Read access can be specified only with OpenExisting mode or OpenAlways mode when the .wim file does not exist.")); } // //Imaging DLLs must be in the same directory. // try { m_ImageContainerHandle = NativeMethods.CreateFile(imageFilePath, (uint) fileAccess, (uint) mode); m_WindowsImageFilePath = imageFilePath; } catch (System.DllNotFoundException ex) { throw new System.DllNotFoundException(string.Format(CultureInfo.CurrentCulture, "Unable to load WIM libraries. Make sure the correct DLLs are present (Wimgapi.dll and Xmlrw.dll)."), ex.InnerException); } if (!m_ImageContainerHandle.Equals(IntPtr.Zero)) { // //Set the temporary path so that we can write to an image. This //cannot be %TEMP% as it does not exist on Windows PE // string tempDirectory = System.Environment.GetEnvironmentVariable("systemdrive"); NativeMethods.SetTemporaryPath(m_ImageContainerHandle, tempDirectory); } else { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to open the .wim file {0}.", imageFilePath)); } // //Finally, we must hook into the events. // m_MessageCallback = new NativeMethods.MessageCallback(ImageEventMessagePump); NativeMethods.RegisterCallback(m_MessageCallback); } ///<summary> Destructor to close open handles.</summary> ~WindowsImageContainer() { DisposeInner(); } ///<summary> ///Dispose all unmanaged resources ///</summary> public void Dispose() { DisposeInner(); GC.SuppressFinalize(this); } private void DisposeInner() { if (m_ImageContainerHandle != IntPtr.Zero) { NativeMethods.CloseHandle(m_ImageContainerHandle); m_ImageContainerHandle = IntPtr.Zero; } if (m_MessageCallback != null) { NativeMethods.UnregisterMessageCallback(m_MessageCallback); m_MessageCallback = null; } GC.KeepAlive(this); } ///<summary> ///Used to enumerate the WindowsImage array ///</summary> public IEnumerator GetEnumerator( ) { return m_Images.GetEnumerator(); } ///<summary> ///[] overload, used to enumerate the WindowsImage array ///</summary> public IImage this[int imageIndex] { get { // //Delay load images // if (m_Images == null || m_Images[imageIndex] == null) { ArrayList tempImages = new ArrayList(); tempImages.Add(new WindowsImage(m_ImageContainerHandle, m_WindowsImageFilePath, imageIndex + 1)); m_Images = (WindowsImage[])tempImages.ToArray(typeof(WindowsImage)); } GC.KeepAlive(this); return m_Images[imageIndex]; } } ///<summary> ///Retrieve the number of images in the .wim file. ///</summary> public int ImageCount { get { // //Verify if there is an image count; if not, get it. // if (m_ImageCount == 0) { m_ImageCount = NativeMethods.GetImageCount(m_ImageContainerHandle); } GC.KeepAlive(this); return m_ImageCount; } } ///<summary> ///Capture an image from the root of a drive or from an individual directory. ///</summary> public void CaptureImage(string pathToCapture) { // //Capture the image. // IntPtr windowsImageHandle = NativeMethods.CaptureImage(m_ImageContainerHandle, pathToCapture); NativeMethods.CloseHandle(windowsImageHandle); GC.KeepAlive(this); } ///<summary> ///Default event handler ///</summary> //[CLSCompliant(false)] public delegate void DefaultImageEventHandler(object sender, DefaultImageEventArgs e); //public delegate void DefaultImageEventHandler(IntPtr wParam, IntPtr lParam, IntPtr UserData); ///<summary> ///ProcessFileEvent handler ///</summary> //[CLSCompliant(false)] public delegate void ProcessFileEventHandler(object sender, ProcessFileEventArgs e); //public delegate void ProcessFileEventHandler(ProcessFile fileToProcess); ///<summary> ///Indicate an update in the progress of an image application. ///</summary> //[CLSCompliant(false)] public event DefaultImageEventHandler ProgressEvent; ///<summary> ///Enable the caller to prevent a file or a directory from being captured or applied. ///</summary> //[CLSCompliant(false)] public event ProcessFileEventHandler ProcessFileEvent; ///<summary> ///Enable the caller to prevent a file resource from being compressed during a capture. ///</summary> //[CLSCompliant(false)] public event DefaultImageEventHandler CompressEvent; ///<summary> ///Alert the caller that an error has occurred while capturing or applying an image. ///</summary> //[CLSCompliant(false)] public event DefaultImageEventHandler ErrorEvent; ///<summary> ///Enable the caller to align a file resource on a particular alignment boundary. ///</summary> //[CLSCompliant(false)] public event DefaultImageEventHandler AlignmentEvent; ///<summary> ///Enable the caller to align a file resource on a particular alignment boundary. ///</summary> //[CLSCompliant(false)] public event DefaultImageEventHandler SplitEvent; ///<summary> ///Indicate that volume information is being gathered during an image capture. ///</summary> //[CLSCompliant(false)] public event DefaultImageEventHandler ScanningEvent; ///<summary> ///Indicate the number of files that will be captured or applied. ///</summary> //[CLSCompliant(false)] public event DefaultImageEventHandler SetRangeEvent; ///<summary> ///Indicate the number of files that have been captured or applied. ///</summary> //[CLSCompliant(false)] public event DefaultImageEventHandler SetPosEvent; ///<summary> ///Indicate that a file has been either captured or applied. ///</summary> //[CLSCompliant(false)] public event DefaultImageEventHandler StepItEvent; ///<summary> ///Event callback to the Wimgapi events ///</summary> private uint ImageEventMessagePump( uint MessageId, IntPtr wParam, IntPtr lParam, IntPtr UserData ) { uint status = (uint) NativeMethods.WIMMessage.WIM_MSG_SUCCESS; DefaultImageEventArgs eventArgs = new DefaultImageEventArgs(wParam, lParam, UserData); switch ((ImageEventMessage)MessageId) { case ImageEventMessage.Progress: ProgressEvent(this, eventArgs); break; case ImageEventMessage.Process: string fileToImage = Marshal.PtrToStringUni(wParam); ProcessFileEventArgs fileToProcess = new ProcessFileEventArgs(fileToImage, lParam); ProcessFileEvent(this, fileToProcess); if (fileToProcess.Abort == true) { status = (uint)ImageEventMessage.Abort; } break; case ImageEventMessage.Compress: CompressEvent(this, eventArgs); break; case ImageEventMessage.Error: ErrorEvent(this, eventArgs); break; case ImageEventMessage.Alignment: AlignmentEvent(this, eventArgs); break; case ImageEventMessage.Split: SplitEvent(this, eventArgs); break; case ImageEventMessage.Scanning: ScanningEvent(this, eventArgs); break; case ImageEventMessage.SetRange: SetRangeEvent(this, eventArgs); break; case ImageEventMessage.SetPos: SetPosEvent(this, eventArgs); break; case ImageEventMessage.StepIt: StepItEvent(this, eventArgs); break; default: break; } return status; } ///<summary> ///Image inside of a .wim file ///</summary> private class WindowsImage : IImage, IDisposable { ///<summary> ///Public constructor to create an image object from inside a .wim file ///</summary> public WindowsImage(IntPtr imageContainerHandle, string imageContainerFilePath, int imageIndex) { m_ParentWindowsImageHandle = imageContainerHandle; m_ParentWindowsImageFilePath = imageContainerFilePath; m_Index = imageIndex; // //Load the image and stash away the handle. // m_ImageHandle = NativeMethods.LoadImage(imageContainerHandle, imageIndex); } ///<summary> Destructor to close open handles.</summary> ~WindowsImage() { DisposeInner(); } ///<summary> ///Dispose all unmanaged resources. ///</summary> public void Dispose() { DisposeInner(); GC.SuppressFinalize(this); } private void DisposeInner() { // //Do not leave any open handles or mounted images. // if (m_ImageHandle != IntPtr.Zero) { NativeMethods.CloseHandle(m_ImageHandle); m_ImageHandle = IntPtr.Zero; } if (m_Mounted == true) { // //Never commit changes when destroying this object. // this.DismountImage(false); } GC.KeepAlive(this); } ///<summary> ///Gets an image information header. ///</summary> ///<value></value> public XmlTextReader ImageInformation { get { // //Always get the image header (even if we have it already), removing the unicode file marker. // string str = NativeMethods.GetImageInformation(m_ImageHandle).Remove(0, 1); GC.KeepAlive(this); return ImageInformationHelper(str); } } ///<summary> ///Returns an XmlTextReader for a given node name. ///</summary> private XmlTextReader ImageInformationHelper(string raw) { XmlTextReader xmlTextReader = null; if (raw != null) { XmlDocument xmlDocument = new XmlDocument(); try { xmlDocument.LoadXml(raw); // //Look at all nodes. // foreach(XmlNode node in xmlDocument.ChildNodes) { // //Now, find the specified node // foreach(XmlNode childNode in node) { if (String.Equals(childNode.Name, node.ToString(), StringComparison.InvariantCultureIgnoreCase)) { StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter); xmlTextWriter.WriteStartElement(childNode.Name); // //We are in the specified node. Now, get all the attributes // foreach(XmlAttribute attribute in childNode.Attributes) { xmlTextWriter.WriteAttributeString(attribute.Name, attribute.InnerXml); } xmlTextWriter.WriteEndElement(); xmlTextReader = new XmlTextReader(null, new StringReader(stringWriter.ToString())); } } } } catch (System.Xml.XmlException) { throw new System.Xml.XmlException(string.Format(CultureInfo.CurrentCulture, "Unable to read XML header information from {0}", this.m_ParentWindowsImageFilePath)); } } return xmlTextReader; } ///<summary> ///Retrieves the path to which an image has been mounted. /// </summary> public string MountedPath { get { return (m_MountedPath != null) ? m_MountedPath : null; } } ///<summary> ///Sets the image information header ///</summary> ///<returns></returns> public void SetImageInformation(string imageInformation) { // //Format the incoming XML so that we can set the header. The XML must have: //1. Leading 0xFEFF //2. Be in <IMAGE></IMAGE> // string formattedXml = String.Format(CultureInfo.InvariantCulture, "{0}{1}{2}{3}", UNICODE_FILE_MARKER, "<IMAGE>", imageInformation, "</IMAGE>"); NativeMethods.SetImageInformation(m_ImageHandle, formattedXml); GC.KeepAlive(this); } ///<summary> ///Mounts an image to a directory. ///</summary> ///<returns></returns> public void Mount(string pathToMountTo) { // //Mount the image // m_MountedPath = pathToMountTo; NativeMethods.MountImage(pathToMountTo, m_ParentWindowsImageFilePath, m_Index); m_Mounted = true; } ///<summary> ///Unmounts an image from a directory. ///</summary> ///<returns></returns> public void DismountImage(bool commitChanges) { if (m_Mounted == true) { NativeMethods.DismountImage(m_MountedPath, m_ParentWindowsImageFilePath, m_Index, commitChanges); } } ///<summary> ///Applies an image to a drive root or to a directory path. ///</summary> ///<returns></returns> public void Apply(string pathToApplyTo) { NativeMethods.ApplyImage(m_ImageHandle, pathToApplyTo); GC.KeepAlive(this); } private IntPtr m_ParentWindowsImageHandle = IntPtr.Zero; //.wim file handle private string m_ParentWindowsImageFilePath; //path to .wim file private IntPtr m_ImageHandle = IntPtr.Zero; //image handle private int m_Index; //index of image private string m_MountedPath; //where the image has been mounted private bool m_Mounted; //true if image has been mounted // //DO NOT CHANGE! This controls the format of the image header //and it must be present. // private const string UNICODE_FILE_MARKER = "\uFEFF"; } ///<summary> ///Interop to Wimgapi.dll ///</summary> private class NativeMethods { ///<summary> ///Private null constructor ///</summary> private NativeMethods() { } [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMCreateFile", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern IntPtr WimCreateFile( [MarshalAs(UnmanagedType.LPWStr)] string WimPath, uint DesiredAccess, uint CreationDisposition, uint FlagsAndAttributes, uint CompressionType, out IntPtr CreationResult ); ///<summary> ///Creates a new .wim file or opens an existing .wim file. ///</summary> ///<param name="imageFile">Path to the .wim file to open or to create.</param> ///<param name="access">Specifies the file access to grant the file.</param> ///<param name="mode">Specifies the mode in which the file should be opened or created.</param> ///<returns>If the function succeeds, the return value is an open handle to the specified image file. ///If the function fails, the return value is NULL.</returns> public static IntPtr CreateFile(string imageFile, uint access, uint mode) { IntPtr creationResult = IntPtr.Zero; IntPtr windowsImageHandle = IntPtr.Zero; int rc = -1; windowsImageHandle = NativeMethods.WimCreateFile(imageFile, access, mode, 0, 0, out creationResult); rc = Marshal.GetLastWin32Error(); if (windowsImageHandle == IntPtr.Zero) { // //Everything failed; throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to open/create .wim file {0}. Error = {1}", imageFile, rc)); } return windowsImageHandle; } [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMCloseHandle", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern bool WimCloseHandle( IntPtr Handle ); ///<summary> ///Closes an open .wim file or an image handle. ///</summary> ///<param name="handle">Handle to an open imaging-based object.</param> ///<returns>If the function succeeds, the return value is nonzero. ///If the function fails, the return value is zero. </returns> public static void CloseHandle(IntPtr handle) { bool status = NativeMethods.WimCloseHandle(handle); int rc = Marshal.GetLastWin32Error(); if (status == false) { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to close image handle. Error = {0}", rc)); } } [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMSetTemporaryPath", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern bool WimSetTemporaryPath( IntPtr Handle, [MarshalAs(UnmanagedType.LPWStr)] string TemporaryPath ); ///<summary> ///Sets the location where temporary imaging files are to be stored. ///</summary> ///<param name="handle">Handle to a WIM file returned by CreateFile</param> ///<param name="temporaryPath">String value of path to set as a temporary location.</param> ///<returns>If the function succeeds, the return value is nonzero. ///If the function fails, the return value is NULL.</returns> public static void SetTemporaryPath(IntPtr handle, string temporaryPath) { bool status = NativeMethods.WimSetTemporaryPath(handle, temporaryPath); int rc = Marshal.GetLastWin32Error(); if (status == false) { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to set temporary path. Error = {0}", rc)); } } [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMLoadImage", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern IntPtr WimLoadImage( IntPtr Handle, uint ImageIndex ); ///<summary> ///Loads a volume image or from within a .wim file. ///</summary> ///<param name="handle">Wim handle.</param> ///<param name="imageIndex">Index of the image to load.</param> ///<returns>If the function succeeds, the return value is a handle to an object representing the volume image. ///If the function fails, the return value is NULL. </returns> public static IntPtr LoadImage(IntPtr handle, int imageIndex) { //Load the image data based on the .wim handle // IntPtr hWim = NativeMethods.WimLoadImage(handle, (uint)imageIndex); int rc = Marshal.GetLastWin32Error(); if (hWim == IntPtr.Zero) { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to load image. Error = {0}", rc)); } return hWim; } [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMCaptureImage", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern IntPtr WimCaptureImage( IntPtr Handle, [MarshalAs(UnmanagedType.LPWStr)] string Path, uint CaptureFlags ); ///<summary> ///Captures an image from a drive root or from a directory path and stores it in an image file. ///</summary> ///<param name="handle">Handle to a .wim file returned by CreateFile.</param> ///<param name="path">Drive root or directory path from where the image data will be captured.</param> ///<returns>Handle to an object representing the volume image. If the function fails, the return value is NULL.</returns> public static IntPtr CaptureImage(IntPtr handle, string path) { IntPtr hImage = NativeMethods.WimCaptureImage(handle, path, 0); int rc = Marshal.GetLastWin32Error(); if (hImage == IntPtr.Zero) { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Failed to capture image from {0}. Error = {1}", path, rc)); } return hImage; } ///<summary> ///Gets the number of volume images stored in a .wim file. ///</summary> ///<param name="Handle">Handle to a .wim file returned by CreateFile.</param> ///<returns>The number of images within the .wim file. </returns> [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMGetImageCount", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern int WimGetImageCount( IntPtr Handle ); ///<summary> ///Returns the number of volume images stored in a .wim file. ///</summary> ///<param name="windowsImageHandle">Handle to a .wim file returned by WIMCreateFile.</param> ///<returns>The return value is the number of images within the .wim file. ///If this value is zero, then the .wim file is invalid or does not contain any images that can be applied. ///</returns> public static int GetImageCount(IntPtr windowsImageHandle) { int count = NativeMethods.WimGetImageCount(windowsImageHandle); int rc = Marshal.GetLastWin32Error(); if (count == -1) { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to get image count. Error = {0}", rc)); } return count; } [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMMountImage", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern bool WimMountImage( [MarshalAs(UnmanagedType.LPWStr)] string MountPath, [MarshalAs(UnmanagedType.LPWStr)] string WimFileName, uint ImageIndex, [MarshalAs(UnmanagedType.LPWStr)] string TemporaryPath ); ///<summary> ///Mounts an image in a .wim file to the specified directory. ///</summary> ///<returns>Returns TRUE and sets the LastError to ERROR_SUCCESS. ///Returns FALSE in case of a failure and the LastError is set to the appropriate Win32 error value. ///</returns> public static void MountImage(string mountPath, string windowsImageFileName, int imageIndex) { bool status = false; int rc; try { status = NativeMethods.WimMountImage(mountPath, windowsImageFileName, (uint)imageIndex, System.Environment.GetEnvironmentVariable("temp")); rc = Marshal.GetLastWin32Error(); } catch (System.StackOverflowException) { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to mount image {0} to {1}.", windowsImageFileName, mountPath)); } if (status == false) { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to mount image {0} to {1}. Error = {2}", windowsImageFileName, mountPath, rc)); } } [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMApplyImage", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern bool WimApplyImage( IntPtr Handle, [MarshalAs(UnmanagedType.LPWStr)] string Path, uint Flags ); ///<summary> ///Applies an image to a drive root or to a directory path from a .wim file. ///</summary> ///<returns>If the function succeeds, the return value is nonzero. ///If the function fails, the return value is zero</returns> public static void ApplyImage(IntPtr imageHandle, string applicationPath) { // //Call WimApplyImage always with the Index flag for performance reasons. // bool status = NativeMethods.WimApplyImage(imageHandle, applicationPath, NativeMethods.WIM_FLAG_INDEX); int rc = Marshal.GetLastWin32Error(); if (status == false) { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to apply image to {0}. Error = {1}", applicationPath, rc)); } } [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMGetImageInformation", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern bool WimGetImageInformation( IntPtr Handle, out IntPtr ImageInfo, out IntPtr SizeOfImageInfo ); ///<summary> ///Returns information about an image within the .wim file. ///</summary> ///<param name="handle">Handle returned by CreateImage, LoadImage</param> ///<returns>If the function succeeds, the return value is nonzero. ///If the function fails, the return value is zero. ///</returns> public static string GetImageInformation(IntPtr handle) { IntPtr info = IntPtr.Zero, sizeOfInfo = IntPtr.Zero; bool status; status = NativeMethods.WimGetImageInformation(handle, out info, out sizeOfInfo); int rc = Marshal.GetLastWin32Error(); if (status == false) { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to get image information. Error = {0}", rc)); } string s = Marshal.PtrToStringUni(info); //If the function succeeds, return the pointer to the string. Otherwise, return NULL. // return s; } [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMSetImageInformation", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern bool WimSetImageInformation( IntPtr Handle, IntPtr ImageInfo, uint SizeOfImageInfo ); ///<summary> ///Stores information about an image within the .wim file. ///</summary> ///<param name="handle">Handle returned by CreateImage, LoadImage</param> ///<param name="imageInfo">String containing the unicode XML data to set.</param> ///<returns>If the function succeeds, the return value is nonzero. ///If the function fails, the return value is zero. </returns> public static void SetImageInformation(IntPtr handle, string imageInfo) { //Create a byte array for the stream, allocate some unmanaged memory, and then copy the bytes to the unmanaged memory. // byte[] byteBuffer = Encoding.Unicode.GetBytes(imageInfo); int byteBufferSize = byteBuffer.Length; IntPtr xmlBuffer = Marshal.AllocHGlobal(byteBufferSize); Marshal.Copy(byteBuffer, 0, xmlBuffer, byteBufferSize); bool status = NativeMethods.WimSetImageInformation(handle, xmlBuffer, (uint)byteBufferSize); int rc = Marshal.GetLastWin32Error(); if (status == false) { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to set image information. Error = {0}", rc)); } } [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMUnmountImage", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern bool WimUnmountImage( [MarshalAs(UnmanagedType.LPWStr)] string MountPath, [MarshalAs(UnmanagedType.LPWStr)] string WimFileName, uint ImageIndex, bool CommitChanges ); ///<summary> ///Unmounts a mounted image in a .wim file from the specified directory. ///</summary> ///<returns>Returns TRUE and sets the LastError to ERROR_SUCCESS. Returns FALSE in case of a failure and the LastError is set ///to the appropriate Win32 error value.</returns> public static void DismountImage(string mountPath, string wimdowsImageFileName, int imageIndex, bool commitChanges) { bool status = false; int rc; try { status = NativeMethods.WimUnmountImage(mountPath, wimdowsImageFileName, (uint) imageIndex, commitChanges); rc = Marshal.GetLastWin32Error(); } catch (System.StackOverflowException ex) { // //Throw an exception // throw new System.StackOverflowException(string.Format(CultureInfo.CurrentCulture, "Unable to unmount image {0} from {1}.", wimdowsImageFileName, mountPath), ex.InnerException); } if (status == false) { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to unmount image {0} from {1}. Error = {2}", wimdowsImageFileName, mountPath, rc)); } } ///<summary> ///User-defined function used with the RegisterMessageCallback or UnregisterMessageCallback function. ///</summary> ///<param name="MessageId">Specifies the message being sent.</param> ///<param name="wParam">Specifies additional message information. The contents of this parameter depend on the value of the ///MessageId parameter.</param> ///<param name="lParam">Specifies additional message information. The contents of this parameter depend on the value of the ///MessageId parameter.</param> ///<param name="UserData">Specifies the user-defined value passed to RegisterCallback.</param> ///<returns> ///To indicate success and to enable other subscribers to process the message return WIM_MSG_SUCCESS. ///To prevent other subscribers from receiving the message, return WIM_MSG_DONE. ///To cancel an image apply or capture, return WIM_MSG_ABORT_IMAGE when handling the WIM_MSG_PROCESS message. ///</returns> public delegate uint MessageCallback( uint MessageId, IntPtr wParam, IntPtr lParam, IntPtr UserData ); [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMRegisterMessageCallback", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern uint WimRegisterMessageCallback( IntPtr hWim, MessageCallback MessageProc, IntPtr ImageInfo ); ///<summary> ///Registers a function to be called with imaging-specific data. ///</summary> public static void RegisterCallback(MessageCallback callback) { uint callbackZeroBasedIndex = NativeMethods.WimRegisterMessageCallback(IntPtr.Zero, callback, IntPtr.Zero); int rc = Marshal.GetLastWin32Error(); if (rc != 0) { // //Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to register message callback.")); } } [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMUnregisterMessageCallback", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern bool WimUnregisterMessageCallback( IntPtr hWim, MessageCallback MessageProc ); ///<summary> ///Unregisters a function from being called with imaging-specific data. ///</summary> ///<param name="registeredCallback">Callback to be unregistered.</param> public static void UnregisterMessageCallback(MessageCallback registeredCallback) { bool status = NativeMethods.WimUnregisterMessageCallback(IntPtr.Zero, registeredCallback); int rc = Marshal.GetLastWin32Error(); if (status != true) { // // Throw an exception // throw new System.InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Unable to unregister message callback.")); } } private const uint WM_APP = 0x8000; ///<summary> ///Imaging Messages ///</summary> public enum WIMMessage: uint { WIM_MSG = WM_APP + 0x1476, WIM_MSG_TEXT, ///<summary> ///Indicates an update in the progress of an image application. ///</summary> WIM_MSG_PROGRESS, ///<summary> ///Enables the caller to prevent a file or a directory from being captured or applied. ///</summary> WIM_MSG_PROCESS, ///<summary> ///Indicates that volume information is being gathered during an image capture. ///</summary> WIM_MSG_SCANNING, ///<summary> ///Indicates the number of files that will be captured or applied. ///</summary> WIM_MSG_SETRANGE, ///<summary> ///Indicates the number of files that have been captured or applied. ///</summary> WIM_MSG_SETPOS, ///<summary> ///Indicates that a file has been either captured or applied. ///</summary> WIM_MSG_STEPIT, ///<summary> ///Enables the caller to prevent a file resource from being compressed during a capture. ///</summary> WIM_MSG_COMPRESS, ///<summary> ///Alerts the caller that an error has occurred while capturing or applying an image. ///</summary> WIM_MSG_ERROR, ///<summary> ///Enables the caller to align a file resource on a particular alignment boundary. ///</summary> WIM_MSG_ALIGNMENT, WIM_MSG_RETRY, ///<summary> ///Enables the caller to align a file resource on a particular alignment boundary. ///</summary> WIM_MSG_SPLIT, WIM_MSG_SUCCESS = 0x00000000, WIM_MSG_ABORT_IMAGE = 0xFFFFFFFF }; ///<summary> ///Capture will do byte-by-byte verification of single instance files. ///</summary> public const uint WIM_FLAG_VERIFY = 0x00000002; ///<summary> ///Specifies that the image is to be sequentially read for caching/performance purposes. ///</summary> public const uint WIM_FLAG_INDEX = 0x00000004; } ///<summary> ///Maps CreateFileAccess to CreateFileAccessPrivate ///</summary> /// private CreateFileAccessPrivate GetMappedFileAccess(CreateFileAccess access) { // //Map the file access specified from an int to uint. // CreateFileAccessPrivate fileAccess; switch (access) { case CreateFileAccess.Read: fileAccess = CreateFileAccessPrivate.Read; break; case CreateFileAccess.Write: fileAccess = CreateFileAccessPrivate.Write; break; default: throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "No file access level specified.")); } return fileAccess; } //[CLSCompliant(false)] [FlagsAttribute] private enum CreateFileAccessPrivate : uint { ///<summary> ///Mapping from CreateFileAccess.Read ///</summary> Read = 0x80000000, ///<summary> ///Mapping from CreateFileAccess.Write ///</summary> Write = 0x40000000 } ///<summary> ///Image event messages. ///</summary> //[CLSCompliant(false)] private enum ImageEventMessage : uint { ///<summary> ///Enables the caller to prevent a file or a directory from being captured or applied. ///</summary> Progress = NativeMethods.WIMMessage.WIM_MSG_PROGRESS, ///<summary> ///Notification sent to enable the caller to prevent a file or a directory from being captured or applied. ///To prevent a file or a directory from being captured or applied, call WindowsImageContainer.SkipFile(). ///</summary> Process = NativeMethods.WIMMessage.WIM_MSG_PROCESS, ///<summary> ///Enables the caller to prevent a file resource from being compressed during a capture. ///</summary> Compress = NativeMethods.WIMMessage.WIM_MSG_COMPRESS, ///<summary> ///Alerts the caller that an error has occurred while capturing or applying an image. ///</summary> Error = NativeMethods.WIMMessage.WIM_MSG_ERROR, ///<summary> ///Enables the caller to align a file resource on a particular alignment boundary. ///</summary> Alignment = NativeMethods.WIMMessage.WIM_MSG_ALIGNMENT, ///<summary> ///Enables the caller to align a file resource on a particular alignment boundary. ///</summary> Split = NativeMethods.WIMMessage.WIM_MSG_SPLIT, ///<summary> ///Indicates that volume information is being gathered during an image capture. ///</summary> Scanning = NativeMethods.WIMMessage.WIM_MSG_SCANNING, ///<summary> ///Indicates the number of files that will be captured or applied. ///</summary> SetRange = NativeMethods.WIMMessage.WIM_MSG_SETRANGE, ///<summary> ///Indicates the number of files that have been captured or applied. /// </summary> SetPos = NativeMethods.WIMMessage.WIM_MSG_SETPOS, ///<summary> ///Indicates that a file has been either captured or applied. ///</summary> StepIt = NativeMethods.WIMMessage.WIM_MSG_STEPIT, ///<summary> ///Success. ///</summary> Success = NativeMethods.WIMMessage.WIM_MSG_SUCCESS, ///<summary> ///Abort. ///</summary> Abort = NativeMethods.WIMMessage.WIM_MSG_ABORT_IMAGE } // //WindowsImageContainer Member Data // private IntPtr m_ImageContainerHandle; //Handle to the .wim file private string m_WindowsImageFilePath; //Path to the .wim file private WindowsImage[] m_Images; //Array of image objects inside a .wim file private int m_ImageCount; //Number of images inside a .wim file // //DO NOT CHANGE! // private static NativeMethods.MessageCallback m_MessageCallback; } ///<summary> ///Describes the file that is being processed for the ProcessFileEvent. ///</summary> public class DefaultImageEventArgs : EventArgs { ///<summary> ///Default constructor. ///</summary> public DefaultImageEventArgs(IntPtr wideParameter, IntPtr leftParameter, IntPtr userData) { m_wParam = wideParameter; m_lParam = leftParameter; m_UserData = userData; } ///<summary> ///wParam ///</summary> public IntPtr WideParameter { get { return m_wParam; } } ///<summary> ///lParam ///</summary> public IntPtr LeftParameter { get { return m_lParam; } } ///<summary> ///UserData ///</summary> public IntPtr UserData { get { return m_UserData; } } private IntPtr m_wParam; private IntPtr m_lParam; private IntPtr m_UserData; } ///<summary> ///Describes the file that is being processed for the ProcessFileEvent. ///</summary> public class ProcessFileEventArgs : EventArgs { ///<summary> ///Default constructor. ///</summary> ///<param name="file">Fully qualified path and file name. For example: c:\file.sys.</param> ///<param name="skipFileFlag">Default is false - skip file and continue. ///Set to true to abort the entire image capture.</param> public ProcessFileEventArgs(string file, IntPtr skipFileFlag) { m_FilePath = file; m_SkipFileFlag = skipFileFlag; } ///<summary> ///Skip file from being imaged. ///</summary> public void SkipFile() { byte[] byteBuffer = { 0 }; int byteBufferSize = byteBuffer.Length; Marshal.Copy(byteBuffer, 0, m_SkipFileFlag, byteBufferSize); } ///<summary> ///Fully qualified path and file name. ///</summary> public string FilePath { get { string stringToReturn = ""; if (m_FilePath != null) { stringToReturn = m_FilePath; } return stringToReturn; } } ///<summary> ///Flag to indicate if the entire image capture should be aborted. ///Default is false - skip file and continue. Setting to true will ///abort the entire image capture. ///</summary> public bool Abort { set { m_Abort = value; } get { return m_Abort; } } private string m_FilePath; private bool m_Abort; private IntPtr m_SkipFileFlag; } }