Type a page name and press Enter. You'll jump to the page if it exists, or you can create it if it doesn't.
To create a page in a module other than kernel32, prefix the name with the module name and a period.
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool DeviceIoControl(
IntPtr hDevice,
uint ioControlCode,wdray)]
[In] byte[] inBuffer,
int ninBufferSize,
[MarshalAs(UnmanagedType.LPArray)]
[Out] byte[] outBuffedqwdwr,qwdqw
int noutBufferSize,
out uint bytesReturned,
[In] IntPtr overlapped
);
VB Signature:
<DllImport("kernel32.dll", ExactSpelling := True, SetLastError := True, CharSet := CharSet.Auto)>
Shared Function DeviceIoControl(ByVal hDevice As IntPtr, ByVal dwIoControlCode As UInteger, ByVal lpInBuffer As IntPtr, ByVal nInBufferSize As UInteger, ByVal lpOutBuffer As IntPtr, ByVal nOutBufferSize As UInteger, ByRef lpBytesReturned As UInteger, ByVal lpOverlapped As IntPtr) As Boolean
End Function
VB Signature:
<DllImport("Kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Public Shared Function DeviceIoControl(ByVal hDevice As IntPtr, _
ByVal dwIoControlCode As UInteger, ByRef InBuffer As Long, _
ByVal nInBufferSize As Integer, ByRef OutBuffer As Long, _
ByVal nOutBufferSize As Integer, ByRef pBytesReturned As Integer, _
<[In]()> ByRef lpOverlapped As NativeOverlapped) As Boolean
End Function
VB Signature:
<DllImport("Kernel32.dll", SetLastError := False, CharSet := CharSet.Auto)>
Public Shared Function DeviceIoControl( _
ByVal hDevice As Microsoft.Win32.SafeHandles.SafeFileHandle, _
ByVal IoControlCode As EIOControlCode, _
<MarshalAs(UnmanagedType.AsAny), [In]()> ByVal InBuffer As Object, _
ByVal nInBufferSize As UInteger, <MarshalAs(UnmanagedType.AsAny), _
Out()> ByVal OutBuffer As Object, ByVal nOutBufferSize As UInteger, _
ByRef pBytesReturned As UInteger, <[In]()> _
ByRef Overlapped As System.Threading.NativeOverlapped) As Boolean
End Function
User-Defined Types:
None.
Notes:
hDevice - To retrieve a handle to a volume, call CreateFile with the lpFileName parameter set to a string of the following form: \\.\DriveLetter:. DriveLetter is not case-sensitive and does not require a colon after it.
lpOverlapped - Main use in asynchronous deviceIoControl. NativeOverlapped is the managed version of the structure and use is the same. The difference between NativeOverlapped and Overlapped is managed Struct vs managed Class respectively. NativeOverlapped was more condusive for one-way device driver communication. Convert from Overlapped to NativeOverlapped to make the call, since NativeOverlapped is explicitly defined to mimic the unmanaged Overlapped structure.
This is great for interacting with devices; now perhaps someone can help with the SetupDi calls to actually discover the device handles, etc...? If you are able to conquer it (I wasn't) toss me a mail at dotnet at richardgoodwin dot com
-
Pin your NativeOverlapped structure, DeviceIoControl is asynchronous and will write into the overlapped structure upon completion of IO requested. If you NativeOverlapped structure has been moved by garbage collection it will write into the wrong area causing heap corruption.
-
If you want x64 proccessor support, you CANNOT use the System.Threading.NativeOverlapped structure as a ref parameter described above. The overlap structure must be allocated in global memory space. See the section "DeviceIoControl w/x64 support":
Regards,
Travis
-
Sample Code:
Public ReadOnly Property CardID() As String
Get
Dim dwErrorCode As FarcConstants
Dim dwBytesReceived As Int32
Dim ip As IntPtr = Marshal.AllocHGlobal(13)
Dim erg As String
If DeviceIoControl(hDriver, IOCTL_FARC_GET_CARDID, Nothing, 0, ip, 13, dwBytesReceived, Nothing) Then
erg = Marshal.PtrToStringAnsi(ip)
Marshal.FreeHGlobal(ip)
Else
dwErrorCode = Marshal.GetLastWin32Error
Marshal.FreeHGlobal(ip)
Throw New InvalidOperationException("Get Card ID fails. Errorcode: " & _
dwErrorCode.ToString, New System.ComponentModel.Win32Exception(dwErrorCode))
End If
Return erg
End Get
End Property
Sample Code:
public bool DeviceIoControl( IntPtr hDevice, uint dwIoControlCode, ref long buffer, int bufferSize, ref NativeOverlapped pOverlapped)
{
int NoReturn = 0;
return DeviceIoControl( hDevice, dwIoControlCode, ref buffer, bufferSize, ref buffer, bufferSize, ref NoReturn, ref pOverlapped );
}
public bool PlxIntrAttach(IntPtr handle, PlxIntr intrType)
{
// Call to PLX card to attach wait event to an Interrupts
// Declare control code
uint Control;
DriverMsgs AttachMsg = DriverMsgs.MsgIntrAttach;
Control = CtrCode( cFileDeviceUnknown, (int)AttachMsg, cMethodBuffered, cFileAnyAccess );
// Set return variable up
bool Status = false;
// Initialize the "buffer"
long DeviceBuffer = 0;
// Fill the buffer with the interrupt bitflag
DeviceBuffer = (long)intrType;
// Call the P/Invoked function through masking method
Status = DeviceIoControl( handle, Control, ref DeviceBuffer, 8, ref AdcOverlapData );
// Return with Status
return Status;
}
Sample Code:
public byte[] ReadRawPartition(int harddisk, int partition, int sectors)
{
var name = string.Format(
@"\\?\GLOBALROOT\Device\Harddisk{0}\Partition{1}",
harddisk, partition);
var handle = Win32.CreateFile(name, FileAccess.Read, FileShare.ReadWrite,
IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero);
int dummy;
var diskGeo = new DISK_GEOMETRY();
Win32.DeviceIoControl(handle, IOCTL.DISK_GET_DRIVE_GEOMETRY,
IntPtr.Zero, 0, out diskGeo, Marshal.SizeOf(diskGeo), out dummy, IntPtr.Zero);
var partInfo = new PARTITION_INFORMATION();
Win32.DeviceIoControl(handle, IOCTL.DISK_GET_PARTITION_INFO,
IntPtr.Zero, 0, out partInfo, Marshal.SizeOf(partInfo), out dummy, IntPtr.Zero);
var length = sectors * diskGeo.BytesPerSector;
var data = new byte[length];
int len;
if (!Win32.ReadFile(handle, data, length, out len, IntPtr.Zero))
return null;
if (length != len) Array.Resize(ref data, len);
return data;
}
public static byte[] ObjectToByteArray<T>(T obj)
{
if (null == obj) return (new byte[0]);
else if (obj.GetType() == typeof(string)) return (Encoding.ASCII.GetBytes((obj as string) + '\0'));
else
{
int size = Marshal.SizeOf(obj);
byte[] arr = new byte[size];
internal class DeviceIoOverlapped
{
private IntPtr mPtrOverlapped = IntPtr.Zero;
private int mFieldOffset_InternalLow = 0;
private int mFieldOffset_InternalHigh = 0;
private int mFieldOffset_OffsetLow = 0;
private int mFieldOffset_OffsetHigh = 0;
private int mFieldOffset_EventHandle = 0;
public DeviceIoOverlapped()
{
// Globally allocate the memory for the overlapped structure
mPtrOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(typeof (NativeOverlapped)));
public IntPtr InternalLow
{
get { return Marshal.ReadIntPtr(mPtrOverlapped, mFieldOffset_InternalLow); }
set { Marshal.WriteIntPtr(mPtrOverlapped, mFieldOffset_InternalLow, value); }
}
public IntPtr InternalHigh
{
get { return Marshal.ReadIntPtr(mPtrOverlapped, mFieldOffset_InternalHigh); }
set { Marshal.WriteIntPtr(mPtrOverlapped, mFieldOffset_InternalHigh, value); }
}
public int OffsetLow
{
get { return Marshal.ReadInt32(mPtrOverlapped, mFieldOffset_OffsetLow); }
set { Marshal.WriteInt32(mPtrOverlapped, mFieldOffset_OffsetLow, value); }
}
public int OffsetHigh
{
get { return Marshal.ReadInt32(mPtrOverlapped, mFieldOffset_OffsetHigh); }
set { Marshal.WriteInt32(mPtrOverlapped, mFieldOffset_OffsetHigh, value); }
}
/// <summary>
/// The overlapped event wait handle.
/// </summary>
public IntPtr EventHandle
{
get { return Marshal.ReadIntPtr(mPtrOverlapped, mFieldOffset_EventHandle); }
set { Marshal.WriteIntPtr(mPtrOverlapped, mFieldOffset_EventHandle, value); }
}
/// <summary>
/// Pass this into the DeviceIoControl and GetOverlappedResult APIs
/// </summary>
public IntPtr GlobalOverlapped
{
get { return mPtrOverlapped; }
}
/// <summary>
/// Set the overlapped wait handle and clear out the rest of the structure.
/// </summary>
/// <param name="hEventOverlapped"></param>
public void ClearAndSetEvent(IntPtr hEventOverlapped)
{
EventHandle = hEventOverlapped;
InternalLow = IntPtr.Zero;
InternalHigh = IntPtr.Zero;
OffsetLow = 0;
OffsetHigh = 0;
}
// Clean up the globally allocated memory.
~DeviceIoOverlapped()
{
if (mPtrOverlapped != IntPtr.Zero)
{
Marshal.FreeHGlobal(mPtrOverlapped);
mPtrOverlapped = IntPtr.Zero;
}
}
}
Use the above class something like this:
DeviceIoOverlapped deviceIoOverlapped = new DeviceIoOverlapped();
ManualResetEvent hEvent = new ManualResetEvent(false);
deviceIoOverlapped.ClearAndSetEvent(hEvent.SafeWaitHandle.DangerousGetHandle());
int ret;
DeviceIoControl(hDevice, iCtlCode, inBuffer, inSize, outBuffer, outSize, out ret, deviceIoOverlapped.GlobalOverlapped)
The DeviceIoControl API must declare an IntPtr for the OVERLAPPED parameter. All other deviations are OK.
Private Const DFP_GET_VERSION As Integer = &H74080
Private Const DFP_SEND_DRIVE_COMMAND As Integer = &H7C084
Private Const DFP_RECEIVE_DRIVE_DATA As Integer = &H7C088
Private Const GENERIC_READ As Integer = &H80000000
Private Const GENERIC_WRITE As Integer = &H40000000
Private Const IDE_ATAPI_ID As Integer = &HA1 ' Returns ID sector for ATAPI.
Private Const IDE_ID_FUNCTION As Integer = &HEC ' Returns ID sector for ATA.
Private Const IDE_EXECUTE_SMART_FUNCTION As Integer = &HB0 ' Performs SMART cmd.
Public Const MAX_IDE_DRIVES As Integer = 4 ' // Max number of drives assuming primary/secondary, topology
Public Const READ_ATTRIBUTE_BUFFER_SIZE As Integer = 512
Public Const IDENTIFY_BUFFER_SIZE As Integer = 512
Public Const READ_THRESHOLD_BUFFER_SIZE As Integer = 512
Public Const OUTPUT_DATA_SIZE As Integer = IDENTIFY_BUFFER_SIZE + 16
Private Const FILE_SHARE_READ As Short = &H1S
Private Const FILE_SHARE_WRITE As Short = &H2S
Private Const OPEN_EXISTING As Short = 3
Private Const FILE_ATTRIBUTE_SYSTEM As Short = &H4S
Private Const CREATE_NEW As Short = 1
Private Const IOCTL_STORAGE_CHECK_VERIFY2 As Integer = &H2D0800
Private Const FILE_READ_ATTRIBUTES As Integer = &H80
Private Const IOCTL_DISK_GET_DRIVE_GEOMETRY As Integer = &H70000
Public di As DRIVE_INFO
Private Declare Function DeviceIoControl Lib "kernel32" (ByVal hDevice As Integer, ByVal dwIoControlCode As Integer, ByRef lpInBuffer As IntPtr, ByVal nInBufferSize As Integer, ByRef lpOutBuffer As IntPtr, ByVal nOutBufferSize As Integer, ByRef lpBytesReturned As Integer, ByVal lpOverlapped As IntPtr) As Integer
Private Declare Ansi Function DeviceIoControl Lib "kernel32" (ByVal hDevice As Integer, ByVal dwIoControlCode As Integer, ByVal lpInBuffer As Integer, ByVal nInBufferSize As Integer, ByRef lpOutBuffer As Integer, ByVal nOutBufferSize As Integer, ByRef lpBytesReturned As Integer, ByVal lpOverlapped As Integer) As Integer
Private Declare Function DeviceIoControl Lib "kernel32" (ByVal hDevice As Integer, ByVal dwIoControlCode As Integer, ByRef lpInBuffer As IntPtr, ByVal nInBufferSize As Integer, ByRef lpOutBuffer As DISK_GEOMETRY, ByVal nOutBufferSize As Integer, ByRef lpBytesReturned As Integer, ByVal lpOverlapped As IntPtr) As Integer
Private Declare Function DeviceIoControl Lib "kernel32" (ByVal hDevice As Integer, ByVal dwIoControlCode As Integer, ByRef lpInBuffer As IntPtr, ByVal nInBufferSize As Integer, ByRef lpOutBuffer As GETVERSIONOUTPARAMS, ByVal nOutBufferSize As Integer, ByRef lpBytesReturned As Integer, ByVal lpOverlapped As IntPtr) As Integer
'Pentru DFP_RECEIVE_DRIVE_DATA
Private Declare Function DeviceIoControl Lib "kernel32" (ByVal hDevice As Integer, ByVal dwIoControlCode As Integer, ByRef lpInBuffer As SENDCMDINPARAMS, ByVal nInBufferSize As Integer, ByRef lpOutBuffer As IntPtr, ByVal nOutBufferSize As Integer, ByRef lpBytesReturned As Integer, ByVal lpOverlapped As IntPtr) As Integer
Private Declare Ansi Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Integer, ByVal dwShareMode As Integer, ByVal lpSecurityAttributes As IntPtr, ByVal dwCreationDisposition As Integer, ByVal dwFlagsAndAttributes As Integer, ByVal hTemplateFile As IntPtr) As Integer
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Integer) As Integer
Private Declare Ansi Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (ByRef i As OSVERSIONINFO) As Boolean
Private Declare Function GetLastError Lib "kernel32" Alias "GetLastError" () As Integer
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As IDSECTOR, ByVal Source As Byte, ByVal Length As Long)
Structure GETVERSIONOUTPARAMS
Dim bVersion As Byte ' Binary driver version.
Dim bRevision As Byte ' Binary driver revision.
Dim bReserved As Byte ' Not used.
Dim bIDEDeviceMap As Byte ' Bit map of IDE devices.
Dim fCapabilities As Integer ' Bit mask of driver capabilities.
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=3)> _
Dim dwReserved() As Integer
End Structure
Structure IDEREGS
Dim bFeaturesReg As Byte ' // Used for specifying SMART "commands".
Dim bSectorCountReg As Byte ' // IDE sector count register
Dim bSectorNumberReg As Byte ' // IDE sector number register
Dim bCylLowReg As Byte ' // IDE low order cylinder value
Dim bCylHighReg As Byte ' // IDE high order cylinder value
Dim bDriveHeadReg As Byte ' // IDE drive/head register
Dim bCommandReg As Byte ' // Actual IDE command.
Dim bReserved As Byte ' // reserved for future use. Must be zero.
End Structure
Structure IDSECTOR
Dim wGenConfig As Short
Dim wNumCyls As Short
Dim wReserved As Short
Dim wNumHeads As Short
Dim wBytesPerTrack As Short
Dim wBytesPerSector As Short
Dim wSectorsPerTrack As Short
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> _
Dim wVendorUnique() As Short
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=19)> _
Dim sSerialNumber() As Byte
Dim wBufferType As Short
Dim wBufferSize As Short
Dim wECCSize As Short
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=7)> _
Dim sFirmwareRev() As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=39)> _
Dim sModelNumber() As Byte
Dim wMoreVendorUnique As Short
Dim wDoubleWordIO As Short
Dim wCapabilities As Short
Dim wReserved1 As Short
Dim wPIOTiming As Short
Dim wDMATiming As Short
Dim wBS As Short
Dim wNumCurrentCyls As Short
Dim wNumCurrentHeads As Short
Dim wNumCurrentSectorsPerTrack As Short
Dim ulCurrentSectorCapacity As Long
Dim wMultSectorStuff As Short
Dim ulTotalAddressableSectors As Long
Dim wSingleWordDMA As Short
Dim wMultiWordDMA As Short
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=127)> _
Dim bReserved() As Byte
End Structure
Structure SENDCMDINPARAMS
Dim cBufferSize As Integer ' Buffer size in bytes
Dim irDriveRegs As IDEREGS ' Structure with drive register values.
Dim bDriveNumber As Byte ' Physical drive number to send command to (0,1,2,3).
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=3)> _
Dim bReserved() As Byte ' Bytes reserved
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> _
Dim dwReserved() As Integer ' DWORDS reserved
Dim bBuffer As Byte ' Input buffer.
Dim AttrID As Byte
Dim AttrName As String
Dim AttrValue As Byte
Dim ThresholdValue As Byte
Dim WorstValue As Byte
Dim StatusFlags As STATUS_FLAGS
End Structure
Structure DRIVE_INFO
Dim bDriveType As Byte
Dim SerialNumber As String
Dim Model As String
Dim FirmWare As String
Dim Cylinders As Long
Dim Heads As Integer
Dim SecPerTrack As Integer
Dim BytesPerSector As Integer
Dim BytesperTrack As Integer
Dim NumAttributes As Byte
Dim Attributes() As ATTR_DATA
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure OSVERSIONINFO
Public dwOSVersionInfoSize As Integer
Public dwMajorVersion As Integer
Public dwMinorVersion As Integer
Public dwBuildNumber As Integer
Public dwPlatformId As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=128)> _
Public szCSDVersion As String
End Structure
Public Structure DISK_GEOMETRY
Public Cylinders As Long
Public MediaType As Integer
Public TracksPerCylinder As Integer
Public SectorsPerTrack As Integer
Public BytesPerSector As Integer
End Structure
Private Sub test(ByVal VerParam As GETVERSIONOUTPARAMS, ByVal hdrive As Integer)
di.bDriveType = 0
di.NumAttributes = 0
ReDim di.Attributes(0)
If Not IsBitSet(VerParam.bIDEDeviceMap, 0) Then
MsgBox("Not OK")
Else
MsgBox("OK")
End If
End Sub
Private Function IsBitSet(ByVal iBitString As Byte, ByVal lBitNo As Integer) As Boolean
If lBitNo = 7 Then
IsBitSet = iBitString < 0
Else
IsBitSet = iBitString And (2 ^ lBitNo)
End If
End Function
Private Function SwapStringBytes(ByVal sIn As String) As String
Dim sTemp As String
Dim i As Short
sTemp = Space(Len(sIn))
For i = 1 To Len(sIn) - 1 Step 2
Mid(sTemp, i, 1) = Mid(sIn, i + 1, 1)
Mid(sTemp, i + 1, 1) = Mid(sIn, i, 1)
Next i
SwapStringBytes = sTemp
End Function
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MsgBox(GetLastError())
Dim hdrive As Integer
Dim VersionParams As New GETVERSIONOUTPARAMS()
'NOTE: .PHYSICALDRIVE0? Maybe better to use \\?\{HDD LETTER}\{PATH}
'hDrive - Get a Handle to Drive/Path/File - If returns -1 then Access Denied or destination not found
hdrive = CreateFile(".PHYSICALDRIVE0", GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero)
'Issue a Command GET VERSION and test results
Dim bytesReturned As Integer
Dim result As Boolean
MsgBox(GetLastError())
result = DeviceIoControl(hdrive, DFP_GET_VERSION, IntPtr.Zero, 0, VersionParams, 24, bytesReturned, IntPtr.Zero)
MsgBox(GetLastError())
'Issue a full IDE Command
'
Dim SCIP As SENDCMDINPARAMS
Dim IDSEC As IDSECTOR
Dim bArrOut(OUTPUT_DATA_SIZE - 1) As Byte
Dim sMsg As String
Dim lpcbBytesReturned As Integer
Dim barrfound(100) As Integer
Dim i As Integer
For i = 0 To OUTPUT_DATA_SIZE - 1
bArrOut(i) = 0
Next
Dim lng As Integer
With SCIP
.cBufferSize = IDENTIFY_BUFFER_SIZE
.bDriveNumber = CByte(0)
With .irDriveRegs
.bFeaturesReg = 0
.bSectorCountReg = 1
.bSectorNumberReg = 1
.bCylLowReg = 0
.bCylHighReg = 0
.bDriveHeadReg = &HA0S
.bCommandReg = CByte(IDE_ID_FUNCTION)
End With
End With
Dim arraySize As Integer = bArrOut.Length
Dim buffer As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(arraySize) * bArrOut.Length)
If DeviceIoControl(hdrive, DFP_RECEIVE_DRIVE_DATA, SCIP, 32, buffer, OUTPUT_DATA_SIZE, lpcbBytesReturned, IntPtr.Zero) Then
Marshal.Copy(buffer, bArrOut, 0, arraySize)
End If
CloseHandle(hdrive)
End Sub
End Class
here's how to set a file to be a sparse file:
Sample Code:
FileStream f=File.Open(filename,System.IO.FileMode.Open,System.IO.FileAccess.ReadWrite,System.IO.FileShare.None);
int dwTemp=0;
short shTemp=0;
IntPtr fileHandle=f.SafeFileHandle.DangerousGetHandle();
int result=DeviceIoControl(fileHandle,(int)EIOControlCode.FsctlSetSparse,ref shTemp,0,IntPtr.Zero,0,ref dwTemp,IntPtr.Zero);
TODO - a short description
3/31/2008 9:16:38 AM - anonymous
Click to read this page
3/31/2016 3:44:13 AM - oxewadrgwmo-85.235.206.106
Click to read this page
3/31/2016 3:44:13 AM - oxewadrgwmo-85.235.206.106
Click to read this page
3/31/2016 3:44:13 AM - oxewadrgwmo-85.235.206.106
Click to read this page
3/31/2016 3:44:13 AM - oxewadrgwmo-85.235.206.106
Click to read this page
3/31/2016 3:44:13 AM - oxewadrgwmo-85.235.206.106
Click to read this page
3/31/2016 3:44:13 AM - oxewadrgwmo-85.235.206.106
Click to read this page
3/31/2016 3:44:13 AM - oxewadrgwmo-85.235.206.106
The DISK_GEOMETRY structure contains the geometry of disk devices and media.
10/22/2010 1:25:47 PM - -80.2.36.104
TODO - a short description
11/12/2015 8:07:05 AM - -80.2.36.104
An IntPtr is a pointer to a memory location (unmanaged) that adapts to the platform it is running on (64-bit, etc.) UNLIKE a standard int/Integer. You should always use this type for unmanaged calls that require it, even though an int will appear to work on your development machine.
1/13/2008 4:00:13 AM - Damon Carr-72.43.165.29
Please edit this page!
Do you have...
helpful tips or sample code to share for using this API in managed code?
corrections to the existing content?
variations of the signature you want to share?
additional languages you want to include?
Select "Edit This Page" on the right hand toolbar and edit it! Or add new pages containing supporting types needed for this API (structures, delegates, and more).