Introduction
Deploying a new operating systems to an enterprise is no small task, but to reduce the complexity of deployment, Microsoft based the installation of Windows Vista on the file based disk imaging technology called Windows Imaging(WIM). Microsoft also provided a set of APIs to programmatically capture,modify and apply images for deployment in a manufacturing or corporate environment. These APIs are available in a C++ Dll (WIMGAPI.DLL) and used by ImageX.exe. However calling these APIs from a C# module needs a little bit of work from developers. Microsoft provided few samples to use these APIs in C++ but there is not any sample to show how these APIs can be used in a C# environment.
Background
WIMGAPI.DLL is a C++ DLL and Microsoft provides a header file, library and documentation for developers to use with their C++ application. However in C#, the APIs need to be invoked as unmanaged code. This article is about how to call these APIs in a C# application using P/Invoke and DllImport features available in .NET and C#.
Using the code
This article has two classes in C#. WimApi class is a wrapper class to provide a DllImport statement for each API entry point available in WIMGAPI. It also has a generic WindowsImage class, which is used to construct a Windows Image object with most commonly used properties of a WIM object. To use these classes, simply add the source code to your project and include the reference to the namespace in your application. These is also small executable included to show how to use these two classes in your C# application.
WimApi class has an entry point defined for each WIMGAPI function using DllImport
as listed below:
[DllImport("wimgapi.dll", EntryPoint = "WIMCreateFile",
SetLastError = true)]
public static extern IntPtr WIMCreateFile(
[MarshalAs (UnmanagedType .LPWStr )] string lpszWimPath,
UInt32 dwDesiredAccess,
Int32 dwCreationDisposition,
Int32 dwFlagsAndAttributes,
Int32 dwCompressionType,
out Int32 lpdwCreationResult
);
[DllImport("wimgapi.dll", EntryPoint = "WIMApplyImage",
SetLastError = true)]
public static extern int WIMApplyImage(
IntPtr hImage ,
[MarshalAs (UnmanagedType .LPWStr )] string lpszPath,
Int32 dwApplyFlags
);
[DllImport("wimgapi.dll", EntryPoint = "WIMCaptureImage",
SetLastError = true)]
public static extern IntPtr WIMCaptureImage(
IntPtr hWim,
[MarshalAs (UnmanagedType .LPWStr )] string lpszPath ,
Int32 dwApplyFlags
);
[DllImport("wimgapi.dll", EntryPoint = "WIMExportImage",
SetLastError = true)]
public static extern int WIMExportImage(
IntPtr hImage,
IntPtr hWim ,
Int32 dwApplyFlags
);
[DllImport("wimgapi.dll", EntryPoint = "WIMGetAttributes",
SetLastError = true)]
public static extern int WIMGetAttributes(
IntPtr hWim ,
ref _WIM_INFO lpWimInfo,
Int32 cbWimInfo
);
[DllImport("wimgapi.dll", EntryPoint = "WIMGetImageCount",
SetLastError = true)]
public static extern Int32 WIMGetImageCount(
IntPtr hwim
);
The utility class WindowsImage has a constructor that calls these APIs to create a C# object with some attributes of the WIM Image. Following code snippet shows how to invoke the C# method from a C# application: First include a reference to the WimApi namespace
using Library.WimApi
private void WIMGetImageInformation_Click(object sender, EventArgs e)
{
if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
{
wimFile = this.openFileDialog1.FileName;
}
else
{
return;
}
IntPtr hWIM;
IntPtr XMLInfo = (IntPtr)0;
Int32 iLength = 0;
Int32 iReturn;
int created;
hWIM = WimApi.WIMCreateFile(wimFile,
WimApi.WIM_GENERIC_READ,
WimApi.WIM_OPEN_EXISTING,
WimApi.WIM_FLAG_VERIFY,
WimApi.WIM_COMPRESS_XPRESS,
out created);
iReturn = WimApi.WIMGetImageInformation(hWIM,
ref XMLInfo, ref iLength);
if (iReturn != 0)
{
String XMLStr = Marshal.PtrToStringUni(XMLInfo);
this.textBox1.Text = XMLStr;
WimApi.LocalFree(XMLInfo);
}
else
{
string str = "Error from WIMGapi : " +
Convert.ToString ( Marshal.GetLastWin32Error());
MessageBox.Show(str, "WIMGapi_Error");
}
WimApi.WIMCloseHandle(hWIM);
}
Points of Interest
Even though Microsoft has provided a reasonable help documentation for WIMGAPI, there are few errors in the online help file. For example the
WIMINFO
structure defined in the help document does not match the structure defined in the Wimgapi.h header file. It is worthwhile to check the header file for all references rather than going with the online documentation.