using System; using System.Collections; using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Text; namespace Disco.ClientBootstrapper.Interop.WIMInterop { /// ///Pulic interface to a WindowsImage object. /// public interface IImage : IDisposable { /// ///Gets image information from within a .wim file. /// string ImageInformation { get; } /// ///Sets image information about an image within a .wim file. /// ///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. /// void SetImageInformation( string imageInformation ); /// ///Mounts an image in a .wim file to the specified directory. /// void Mount( string pathToMountTo ); /// ///Retrieves the path to which an image has been mounted. /// string MountedPath { get; } /// ///Unmounts a mounted image in a .wim file from the specified directory. /// ///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. /// void DismountImage( bool commitChanges ); /// ///Applies an image to a drive root or to a directory path from a .wim file. /// void Apply( string pathToApplyTo ); } /// ///Class representing a .wim file. /// public sealed class WindowsImageContainer : IDisposable { /// ///Specifies the type of access to the .wim file. /// public enum CreateFileAccess { /// ///Specifies read-only access to the .wim file. /// Read, /// ///Specifies write access to the .wim file. ///Includes WIM_GENERIC_READ access to enable apply and append operations with existing images. /// Write } /// ///Specifies which action to take on files that exist and ///which action to take when files do not exist. /// public enum CreateFileMode { /// ///RESERVED, DO NOT USE! /// None = 0, /// ///Creates a new .wim file. The function fails if the specified file already exists. /// CreateNew = 1, /// ///Creates a new .wim file. If the file exists, the function overwrites the file. /// CreateAlways = 2, /// ///Opens the .wim file. The function fails if the file does not exist. /// OpenExisting = 3, /// ///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. /// OpenAlways = 4 } /// ///Public constructor to create a WIM object /// ///Path of WIM to create or to open. ///Specifies Open, Create, Create/Open disposition of the .wim file. ///Specifies access level of Read Only or Write. //[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); } /// Destructor to close open handles. ~WindowsImageContainer() { DisposeInner(); } /// ///Dispose all unmanaged resources /// 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); } /// ///Used to enumerate the WindowsImage array /// public IEnumerator GetEnumerator( ) { return m_Images.GetEnumerator(); } /// ///[] overload, used to enumerate the WindowsImage array /// 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]; } } /// ///Retrieve the number of images in the .wim file. /// 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; } } /// ///Capture an image from the root of a drive or from an individual directory. /// public void CaptureImage(string pathToCapture) { // //Capture the image. // IntPtr windowsImageHandle = NativeMethods.CaptureImage(m_ImageContainerHandle, pathToCapture); NativeMethods.CloseHandle(windowsImageHandle); GC.KeepAlive(this); } /// ///Default event handler /// //[CLSCompliant(false)] public delegate void DefaultImageEventHandler(object sender, DefaultImageEventArgs e); //public delegate void DefaultImageEventHandler(IntPtr wParam, IntPtr lParam, IntPtr UserData); /// ///ProcessFileEvent handler /// //[CLSCompliant(false)] public delegate void ProcessFileEventHandler(object sender, ProcessFileEventArgs e); //public delegate void ProcessFileEventHandler(ProcessFile fileToProcess); /// ///Indicate an update in the progress of an image application. /// //[CLSCompliant(false)] public event DefaultImageEventHandler ProgressEvent; /// ///Enable the caller to prevent a file or a directory from being captured or applied. /// //[CLSCompliant(false)] public event ProcessFileEventHandler ProcessFileEvent; /// ///Enable the caller to prevent a file resource from being compressed during a capture. /// //[CLSCompliant(false)] public event DefaultImageEventHandler CompressEvent; /// ///Alert the caller that an error has occurred while capturing or applying an image. /// //[CLSCompliant(false)] public event DefaultImageEventHandler ErrorEvent; /// ///Enable the caller to align a file resource on a particular alignment boundary. /// //[CLSCompliant(false)] public event DefaultImageEventHandler AlignmentEvent; /// ///Enable the caller to align a file resource on a particular alignment boundary. /// //[CLSCompliant(false)] public event DefaultImageEventHandler SplitEvent; /// ///Indicate that volume information is being gathered during an image capture. /// //[CLSCompliant(false)] public event DefaultImageEventHandler ScanningEvent; /// ///Indicate the number of files that will be captured or applied. /// //[CLSCompliant(false)] public event DefaultImageEventHandler SetRangeEvent; /// ///Indicate the number of files that have been captured or applied. /// //[CLSCompliant(false)] public event DefaultImageEventHandler SetPosEvent; /// ///Indicate that a file has been either captured or applied. /// //[CLSCompliant(false)] public event DefaultImageEventHandler StepItEvent; /// ///Event callback to the Wimgapi events /// 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; } /// ///Image inside of a .wim file /// private class WindowsImage : IImage { /// ///Public constructor to create an image object from inside a .wim file /// 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); } /// Destructor to close open handles. ~WindowsImage() { DisposeInner(); } /// ///Dispose all unmanaged resources. /// 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); } /// ///Gets an image information header. /// /// public string 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 str; } } // /// // ///Returns an XmlTextReader for a given node name. // /// // 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; // } /// ///Retrieves the path to which an image has been mounted. /// public string MountedPath { get { return (m_MountedPath != null) ? m_MountedPath : null; } } /// ///Sets the image information header /// /// 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 // string formattedXml = String.Format(CultureInfo.InvariantCulture, "{0}{1}{2}{3}", UNICODE_FILE_MARKER, "", imageInformation, ""); NativeMethods.SetImageInformation(m_ImageHandle, formattedXml); GC.KeepAlive(this); } /// ///Mounts an image to a directory. /// /// public void Mount(string pathToMountTo) { // //Mount the image // m_MountedPath = pathToMountTo; NativeMethods.MountImage(pathToMountTo, m_ParentWindowsImageFilePath, m_Index, System.IO.Path.GetTempPath()); m_Mounted = true; } /// ///Unmounts an image from a directory. /// /// public void DismountImage(bool commitChanges) { if (m_Mounted == true) { NativeMethods.DismountImage(m_MountedPath, m_ParentWindowsImageFilePath, m_Index, commitChanges); } } /// ///Applies an image to a drive root or to a directory path. /// /// 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"; } /// ///Interop to Wimgapi.dll /// public class NativeMethods { /// ///Private null constructor /// 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 ); /// ///Creates a new .wim file or opens an existing .wim file. /// ///Path to the .wim file to open or to create. ///Specifies the file access to grant the file. ///Specifies the mode in which the file should be opened or created. ///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. 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 ); /// ///Closes an open .wim file or an image handle. /// ///Handle to an open imaging-based object. ///If the function succeeds, the return value is nonzero. ///If the function fails, the return value is zero. 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 ); /// ///Sets the location where temporary imaging files are to be stored. /// ///Handle to a WIM file returned by CreateFile ///String value of path to set as a temporary location. ///If the function succeeds, the return value is nonzero. ///If the function fails, the return value is NULL. 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 ); /// ///Loads a volume image or from within a .wim file. /// ///Wim handle. ///Index of the image to load. ///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. 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 ); /// ///Captures an image from a drive root or from a directory path and stores it in an image file. /// ///Handle to a .wim file returned by CreateFile. ///Drive root or directory path from where the image data will be captured. ///Handle to an object representing the volume image. If the function fails, the return value is NULL. 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; } /// ///Gets the number of volume images stored in a .wim file. /// ///Handle to a .wim file returned by CreateFile. ///The number of images within the .wim file. [DllImport("Wimgapi.dll", ExactSpelling = true, EntryPoint = "WIMGetImageCount", CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern int WimGetImageCount( IntPtr Handle ); /// ///Returns the number of volume images stored in a .wim file. /// ///Handle to a .wim file returned by WIMCreateFile. ///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. /// 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 = "WIMMountImageHandle", // CallingConvention = CallingConvention.StdCall, // SetLastError = true)] //private static extern //bool //WIMMountImageHandle( // IntPtr hImage, // [MarshalAs(UnmanagedType.LPWStr)] string pszMountPath, // uint dwMountFlags // ); ///// /////Mounts an image in a .wim file to the specified directory. ///// /////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. ///// //public //static //void //MountImageHandle(string mountPath, ) //{ // 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 = "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 ); /// ///Mounts an image in a .wim file to the specified directory. /// ///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. /// public static void MountImage(string mountPath, string windowsImageFileName, int imageIndex, string temporaryPath) { bool status = false; int rc; try { status = NativeMethods.WimMountImage(mountPath, windowsImageFileName, (uint)imageIndex, temporaryPath); 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 ); /// ///Applies an image to a drive root or to a directory path from a .wim file. /// ///If the function succeeds, the return value is nonzero. ///If the function fails, the return value is zero 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 ); /// ///Returns information about an image within the .wim file. /// ///Handle returned by CreateImage, LoadImage ///If the function succeeds, the return value is nonzero. ///If the function fails, the return value is zero. /// 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 ); /// ///Stores information about an image within the .wim file. /// ///Handle returned by CreateImage, LoadImage ///String containing the unicode XML data to set. ///If the function succeeds, the return value is nonzero. ///If the function fails, the return value is zero. 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 ); /// ///Unmounts a mounted image in a .wim file from the specified directory. /// ///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. 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)); } } /// ///User-defined function used with the RegisterMessageCallback or UnregisterMessageCallback function. /// ///Specifies the message being sent. ///Specifies additional message information. The contents of this parameter depend on the value of the ///MessageId parameter. ///Specifies additional message information. The contents of this parameter depend on the value of the ///MessageId parameter. ///Specifies the user-defined value passed to RegisterCallback. /// ///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. /// 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 ); /// ///Registers a function to be called with imaging-specific data. /// 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 ); /// ///Unregisters a function from being called with imaging-specific data. /// ///Callback to be unregistered. 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; /// ///Imaging Messages /// public enum WIMMessage : uint { WIM_MSG = WM_APP + 0x1476, WIM_MSG_TEXT, /// ///Indicates an update in the progress of an image application. /// WIM_MSG_PROGRESS, /// ///Enables the caller to prevent a file or a directory from being captured or applied. /// WIM_MSG_PROCESS, /// ///Indicates that volume information is being gathered during an image capture. /// WIM_MSG_SCANNING, /// ///Indicates the number of files that will be captured or applied. /// WIM_MSG_SETRANGE, /// ///Indicates the number of files that have been captured or applied. /// WIM_MSG_SETPOS, /// ///Indicates that a file has been either captured or applied. /// WIM_MSG_STEPIT, /// ///Enables the caller to prevent a file resource from being compressed during a capture. /// WIM_MSG_COMPRESS, /// ///Alerts the caller that an error has occurred while capturing or applying an image. /// WIM_MSG_ERROR, /// ///Enables the caller to align a file resource on a particular alignment boundary. /// WIM_MSG_ALIGNMENT, WIM_MSG_RETRY, /// ///Enables the caller to align a file resource on a particular alignment boundary. /// WIM_MSG_SPLIT, WIM_MSG_FILEINFO, WIM_MSG_INFO, WIM_MSG_WARNING, WIM_MSG_CHK_PROCESS, WIM_MSG_WARNING_OBJECTID, WIM_MSG_STALE_MOUNT_DIR, WIM_MSG_STALE_MOUNT_FILE, WIM_MSG_MOUNT_CLEANUP_PROGRESS, WIM_MSG_SUCCESS = 0x00000000, WIM_MSG_ABORT_IMAGE = 0xFFFFFFFF }; /// ///Capture will do byte-by-byte verification of single instance files. /// public const uint WIM_FLAG_VERIFY = 0x00000002; /// ///Specifies that the image is to be sequentially read for caching/performance purposes. /// public const uint WIM_FLAG_INDEX = 0x00000004; } /// ///Maps CreateFileAccess to CreateFileAccessPrivate /// /// 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 { /// ///Mapping from CreateFileAccess.Read /// Read = 0x80000000, /// ///Mapping from CreateFileAccess.Write /// Write = 0x40000000 } /// ///Image event messages. /// //[CLSCompliant(false)] public enum ImageEventMessage : uint { /// ///Enables the caller to prevent a file or a directory from being captured or applied. /// Progress = NativeMethods.WIMMessage.WIM_MSG_PROGRESS, /// ///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(). /// Process = NativeMethods.WIMMessage.WIM_MSG_PROCESS, /// ///Enables the caller to prevent a file resource from being compressed during a capture. /// Compress = NativeMethods.WIMMessage.WIM_MSG_COMPRESS, /// ///Alerts the caller that an error has occurred while capturing or applying an image. /// Error = NativeMethods.WIMMessage.WIM_MSG_ERROR, /// ///Enables the caller to align a file resource on a particular alignment boundary. /// Alignment = NativeMethods.WIMMessage.WIM_MSG_ALIGNMENT, /// ///Enables the caller to align a file resource on a particular alignment boundary. /// Split = NativeMethods.WIMMessage.WIM_MSG_SPLIT, /// ///Indicates that volume information is being gathered during an image capture. /// Scanning = NativeMethods.WIMMessage.WIM_MSG_SCANNING, /// ///Indicates the number of files that will be captured or applied. /// SetRange = NativeMethods.WIMMessage.WIM_MSG_SETRANGE, /// ///Indicates the number of files that have been captured or applied. /// SetPos = NativeMethods.WIMMessage.WIM_MSG_SETPOS, /// ///Indicates that a file has been either captured or applied. /// StepIt = NativeMethods.WIMMessage.WIM_MSG_STEPIT, /// ///Success. /// Success = NativeMethods.WIMMessage.WIM_MSG_SUCCESS, /// ///Abort. /// Abort = NativeMethods.WIMMessage.WIM_MSG_ABORT_IMAGE, MountCleanupProgress = NativeMethods.WIMMessage.WIM_MSG_MOUNT_CLEANUP_PROGRESS } // //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; } /// ///Describes the file that is being processed for the ProcessFileEvent. /// public class DefaultImageEventArgs : EventArgs { /// ///Default constructor. /// public DefaultImageEventArgs(IntPtr wideParameter, IntPtr leftParameter, IntPtr userData) { m_wParam = wideParameter; m_lParam = leftParameter; m_UserData = userData; } /// ///wParam /// public IntPtr WideParameter { get { return m_wParam; } } /// ///lParam /// public IntPtr LeftParameter { get { return m_lParam; } } /// ///UserData /// public IntPtr UserData { get { return m_UserData; } } private IntPtr m_wParam; private IntPtr m_lParam; private IntPtr m_UserData; } /// ///Describes the file that is being processed for the ProcessFileEvent. /// public class ProcessFileEventArgs : EventArgs { /// ///Default constructor. /// ///Fully qualified path and file name. For example: c:\file.sys. ///Default is false - skip file and continue. ///Set to true to abort the entire image capture. public ProcessFileEventArgs(string file, IntPtr skipFileFlag) { m_FilePath = file; m_SkipFileFlag = skipFileFlag; } /// ///Skip file from being imaged. /// public void SkipFile() { byte[] byteBuffer = { 0 }; int byteBufferSize = byteBuffer.Length; Marshal.Copy(byteBuffer, 0, m_SkipFileFlag, byteBufferSize); } /// ///Fully qualified path and file name. /// public string FilePath { get { string stringToReturn = ""; if (m_FilePath != null) { stringToReturn = m_FilePath; } return stringToReturn; } } /// ///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. /// public bool Abort { set { m_Abort = value; } get { return m_Abort; } } private string m_FilePath; private bool m_Abort; private IntPtr m_SkipFileFlag; } }