Overlapped.AsyncResult doesn't change even after operation completed successfully - c#

To communicate with a HID device, I use some functions from kernel32. Codes are borrowed from Microchip MLA custom HID device project. It uses blocking methods.
I found I can make these methods async. Here is what I tried for an async write:
//...
internal const uint FILE_FLAG_OVERLAPPED = 0x40000000;
//...
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool ReadFile(
SafeFileHandle hFile,
IntPtr lpBuffer,
uint nNumberOfBytesToRead,
ref uint lpNumberOfBytesRead,
Overlapped lpOverlapped); // Formerly: IntPtr lpOverlapped);
//...
WriteHandleToUSBDevice = CreateFile(DevicePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, IntPtr.Zero); // Formerly: 0 instead of FILE_FLAG_OVERLAPPED
//...
Overlapped OL = new Overlapped();
WriteFile(WriteHandleToUSBDevice, OUTBuffer, 65, ref BytesWritten, OL); // Formerly: IntPtr.Zero instead of OL
//Some code to run while write operation is in progress asynchronously...
while (OL.AsyncResult == null) ; // Wait until write is completed; waits forever.
You can find complete code in Microchip MLA custom HID device project.
OL.AsyncResult remains null although write is completed successfully; I'm sure because device receives data and responses correctly. What is wrong in my code?

Thanks to Gserg comment, I found a better solutions than using kernel32 C++ style functions:
SafeFileHandle HandleToUSBDevice = CreateFile(DevicePath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
IntPtr.Zero);
FileStream HID = new FileStream(HandleToUSBDevice, FileAccess.ReadWrite, (int)(PacketSize + 1), true);
Task WriteTask = Task.Factory.StartNew(() => HID.Write(OUTBuffer, 0, 65));
//Some Code
if (!WriteTask.Wait(2500)) throw new TimeoutException("Failed to send data within 2.5s timeout.");
You can use async/await and WriteAsync if your .Net framework target is more than 4.5.
I could use ReadFile instead of HID.Write but closing handles would be harder. Also using managed C# methods is better than importing and using unmanaged C++ functions.
EDIT:
I also add a code for BeginRead:
IAsyncResult result = HID.BeginRead(INBuffer, 0, 65, null, null);
while (FavoriteCondition)
{
MethodWhichShouldBeCalledRepeatedly();
if (result.IsCompleted)
{
ProcessData(INBuffer);
}
}

Related

Importing kernel32 functions for allocating virtual memory in C#?

I have several DLL files that are on my hard disk. A process on my server contains important file data that I want to log by allocating virtual memory inside the process. I don't have the source code of that process, so I need to reside to more extreem measures. I want it to start the DLL main function. The allocation of memory externally needs to be written in C# due to the fact I want to use it with WPF.
How can you excute your own source code in another process with C#?
In order to execute your own source code inside a process you need to virtually allocate memory for the process and write the path of your DLL inside that memory address you allocated. You will use that DLL path to catapult your dll inside the process using the exported function in kernel32.dll LoadLibraryW.
Each process on the windows platform has a specified memory size dedicated to that process. One of the reasons is for security, a process can’t read or write data to other processes. So in order to be able to write/inject your DLL you need to open a HANDLE. You can do this if you import the OpenProcess function from the kernel32.dll. What this briefly means is that you are using the windows api. Here is how you import the kernel32 DLL in C#
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(
uint dwDesiredAccess,
int bInheritHandle,
uint dwProcessId
);
You can find the full documentation of the windows api in the holy bible
Now, you want to allocate memory to the process that you got a handle from by using the OpenProcess function. Use the VirtualAllocEx function, lets consult the MSDN
How hath thou allocated thou memory?
LPVOID WINAPI VirtualAllocEx(
_In_ HANDLE hProcess,
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
As we can see it takes 5 parameters. The HANDLE object that you collected earlier. An optional parameter that we won’t use. The size of your DLL that you can get if you convert your DLL into an array of bytes. The type of memory allocation, we want to both reserve and commit allocation so use (0x1000 | 0x2000) and last the protection for the allocated memory that we will put on write 0x40.
STEP 1 Allocate memory ✓
STEP 2 Write DLL path
STEP 3 use LoadLibraryW
The second step involves using WriteProcessMemory to simply write the dll path in memory. Convert String to array of bytes
byte[] bytes = Encoding.ASCII.GetBytes(DllPath);
Write that array of bytes on the memory you allocated with the windows api function WriteProcessMemory like so.
WriteProcessMemory(processHandle, allocatedMemory, bytes, (uint)bytes.Length, 0)
STEP 1 Allocate memory ✓
STEP 2 Write DLL path ✓
STEP 3 use LoadLibraryW
This will be a bit tricky to explain if you have no clue on what exported functions are so ill try to give you an abstract understanding.
When creating an application you need to import DLLs that windows provided in order to use some functionalities. For example, you want to send a HTTP request in your application. Even without you knowing you need to load windows ws2.dll (windows socket) library. The windows OS provided a handy function that will literally load a library called LoadLibraryW. Where can I find this fantastic function? Well no worries child, the kernel32.dll got you covered. All you need to do is find a pointer to the LoadLibraryW function. Again, show faith in the MSDN and it shall reward you.
FARPROC WINAPI GetProcAddress(
_In_ HMODULE hModule,
_In_ LPCSTR lpProcName
);
HMODULE WINAPI GetModuleHandle(
_In_opt_ LPCTSTR lpModuleName
);
You can read the documentation for more information. Simply put this will find your LoadLibraryW function inside kernel32.dll since it is an exported function.
IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");
STEP 1 Allocate memory ✓
STEP 2 Write DLL path ✓
STEP 3 use LoadLibraryW ✓
Start a remotethread inside your process that will simply execute your loadlibrary code
CreateRemoteThread(hndProc, (IntPtr)null, (IntPtr)null, lpLLAddress, lpAddress, 0, (IntPtr)null)
After that simply close the handle to the process and your dll should be ‘injected’ inside the process. At any rate if you still haven't figured it out or simply want a class that does it for you here is some source code
DLLinjector
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace dllInjectExample
{
public enum DllInjectionResult
{
DllNotFound,
GameProcessNotFound,
InjectionFailed,
Success
}
public static class DllInjector
{
static readonly IntPtr INTPTR_ZERO = (IntPtr)0;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, uint size, int lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttribute, IntPtr dwStackSize, IntPtr lpStartAddress,
IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
public static DllInjectionResult Inject(string sProcName, string sDllPath)
{
if (!File.Exists(sDllPath))
{
return DllInjectionResult.DllNotFound;
}
uint _procId = 0;
Process[] _procs = Process.GetProcesses();
for (int i = 0; i < _procs.Length; i++)
{
if (_procs[i].ProcessName == sProcName)
{
_procId = (uint)_procs[i].Id;
break;
}
}
if (_procId == 0)
{
return DllInjectionResult.GameProcessNotFound;
}
if (!bInject(_procId, sDllPath))
{
return DllInjectionResult.InjectionFailed;
}
return DllInjectionResult.Success;
}
private static bool bInject(uint pToBeInjected, string sDllPath)
{
IntPtr hndProc = OpenProcess((0x2 | 0x8 | 0x10 | 0x20 | 0x400), 1, pToBeInjected);
if (hndProc == INTPTR_ZERO)
{
return false;
}
IntPtr lpAddress = VirtualAllocEx(hndProc, (IntPtr)null, (IntPtr)sDllPath.Length, (0x1000 | 0x2000), 0X40);
if (lpAddress == INTPTR_ZERO)
{
return false;
}
byte[] bytes = Encoding.ASCII.GetBytes(sDllPath);
if (WriteProcessMemory(hndProc, lpAddress, bytes, (uint)bytes.Length, 0) == 0)
{
return false;
}
IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");
if (lpLLAddress == INTPTR_ZERO)
{
return false;
}
if (CreateRemoteThread(hndProc, (IntPtr)null, INTPTR_ZERO, lpLLAddress, lpAddress, 0, (IntPtr)null) == INTPTR_ZERO)
{
return false;
}
CloseHandle(hndProc);
return true;
}
}
}
Example injecting into csgo since I have no other idea why you would want to inject a dll?
if (Process.GetProcessesByName("csgo").Count() == 0)
{
Process Proc = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo(#"D:\Application\Steam\Steam.exe");
Proc.StartInfo = startInfo;
Proc.StartInfo.Arguments = "-applaunch 730";
Proc.StartInfo.UseShellExecute = false;
Proc.StartInfo.CreateNoWindow = false;
Proc.Start();
Thread.Sleep(15000);
}
while (Process.GetProcessesByName("csgo").Count() == 0)
{
}
var something = DllInjector.Inject("csgo", #"C:\Visual Studio 2015\Projects\XGame\Debug\XGamedll.dll");

Custom HID Async Read give strange GetOverlappedResults results

I have been working with a USB device (HID custom device), I wrote some code for test the device, simple things: the detection of the device connected and a Write-then-Read cycle, the task of the write/read cycle is send a 64 bytes block with the command in the first byte and the device send me back a block of 64 bytes with the same command in the first byte, the numbers from 1 to 6 in the next six bytes and the rest is uninitialized garbage, then that block is passed to a rich textbox to be displayed.
The program detect the device and the first time that I call the write/read cycle it work without problems but only the first time, the subsecuents calls may result ok o maybe not, in the case of not the read value is garbage and in some occations something occurs and vshost.exe stops work and close my program...
This is the code of the read file:
public bool ReadUSB18F(ref byte[] InBuffer)
{
int Bsize = 65;
InBuffer = new byte[Bsize];
IntPtr UnManagedBuffer = Marshal.AllocHGlobal(Bsize);
IntPtr UnManagedOverlapStruct = Marshal.AllocHGlobal(Marshal.SizeOf(Overlappedbuffer));
Marshal.StructureToPtr(Overlappedbuffer, UnManagedOverlapStruct, false);
if (ReadFile(USBDeviceInfo.ReadHandle, UnManagedBuffer, Bsize, IntPtr.Zero, UnManagedOverlapStruct) == false)
{
if (Marshal.GetLastWin32Error().ToString() == ERROR_IO_PENDING)
{
long bytesreadcount = 0;
bool final = GetOverlappedResult(USBDeviceInfo.ReadHandle, ref Overlappedbuffer, ref bytesreadcount, true);
MessageBox.Show("GetOverlappedResult:"+ final.ToString()+", GetLastWin32Error: " + Marshal.GetLastWin32Error().ToString()+", Byte read count: " + bytesreadcount.ToString());
}
else
{
string error = Marshal.GetLastWin32Error().ToString();
if (error != "0")
{
return false;
}
}
}
Marshal.Copy(UnManagedBuffer, InBuffer, 0, Bsize);
Marshal.FreeHGlobal(UnManagedBuffer);
Marshal.FreeHGlobal(UnManagedOverlapStruct);
return true;
}
I use two handles one for read and other to write. Doing some debug I found that GetOverlappingResult give me a true and ERROR_IO_PENDING, but bWait is true and GetOverlappingResult must wait until the read is complete at least in theory.
In a desperate effort to found a solution I put a messagebox that show the result of GetOverlappingResult, the error from calling the function and the count of bytes read but then something happened, whenever the error ocurs and the messagebox appears (showing effectively that GetOverlappingResult give true, and a ERROR_IO_PENDING), at the moment that I click OK all the data is displayed in the rich textbox as if read was done correctly, like magic, I suppose that the messagebox wait of click event to continue give the necessary time to complete the read, but that wait is supossed to be completed by the GetOverlappingResult, is like GetOverlappingResult don't do their work OR I do something wrong.
Those are my declarations of CreateFile, ReadFile, GetOverlappingResult:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern SafeFileHandle CreateFile(
[MarshalAs(UnmanagedType.LPStr)]
string strName,
uint nAccess,
uint nShareMode,
IntPtr lpSecurity,
uint nCreationFlags,
uint nAttributes,
IntPtr lpTemplate
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadFile
(
SafeFileHandle hFile, // SafeFileHandle to file
IntPtr pBuffer, // data buffer
int NumberOfBytesToRead, // number of bytes to read
IntPtr pNumberOfBytesRead, // number of bytes read
IntPtr OverlappedBuffer
//IntPtr OverlappedBuffer // overlapped buffer
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetOverlappedResult(
SafeFileHandle hFile,
[In] ref Overlapped lpOverlapped,
ref long lpNumberofBytesTransferred,
bool bWait
);
Declaration of the read and write handles:
USBDeviceInfo.ReadHandle = CreateFile(USBDeviceInfo.DevicePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, IntPtr.Zero);
USBDeviceInfo.WriteHandle = CreateFile(USBDeviceInfo.DevicePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
Help me guys please, I´ve been stuck on this for a week.

WinUSB_Initialize function occurs INVALID_FUNCTION (0x1) Error

Why does the WinUSB_Initialize function occur INVALID_FUNCTION (0x1) Error?
This is a function from the winusb.dll which returns an interface handle.
I would like to get an Interface handle.
I already have a Device handle.
internal struct devInfo
{
internal SafeFileHandle deviceHandle;
internal IntPtr winUsbHandle;
internal Byte bulkInPipe;
internal Byte bulkOutPipe;
internal Byte interruptInPipe;
internal Byte interruptOutPipe;
internal UInt32 devicespeed;
}
internal const Int32 FILE_ATTRIBUTE_NORMAL = 0X80;
internal const Int32 FILE_FLAG_OVERLAPPED = 0X40000000;
internal const Int32 FILE_SHARE_READ = 1;
internal const Int32 FILE_SHARE_WRITE = 2;
internal const UInt32 GENERIC_READ = 0X80000000;
internal const UInt32 GENERIC_WRITE = 0X40000000;
internal const Int32 OPEN_EXISTING = 3;
[DllImport("winusb.dll", SetLastError = true)]
internal static extern Boolean WinUsb_Initialize
(SafeFileHandle DeviceHandle,
ref IntPtr InterfaceHandle);
internal devInfo myDevInfo; // = new devInfo();
public IntPtr Get_WinUSB_handle()
{
Guid myGuid = Get_HID_GUID();
IntPtr deviceInfoSet = Get_Device_Info_Set(myGuid);
SP_DEVICE_INTERFACE_DATA MyDeviceInterfaeData = Get_Device_Interface_Data(deviceInfoSet, myGuid);
IntPtr detailDataBuffer = Get_Structure_with_Device_PathName(deviceInfoSet, ref MyDeviceInterfaeData);
string devicePathName = Get_Device_PathName(detailDataBuffer);
myDevInfo.deviceHandle= CreateFile(devicePathName,
(GENERIC_WRITE | GENERIC_READ),
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
Boolean success;
success = WinUsb_Initialize(myDevInfo.deviceHandle, ref myDevInfo.winUsbHandle);
System.Console.WriteLine(Marshal.GetLastWin32Error());
System.Console.WriteLine(success);
return myDevInfo.winUsbHandle;
}
success = WinUsb_Initialize(...);
System.Console.WriteLine(Marshal.GetLastWin32Error());
This kind of error checking is wrong. It is only valid to call Marshal.GetLastWin32Error() when a winapi function failed. So a rock-hard requirement is to check success first. Calling GetLastWin32Error() anyway produces an arbitrary garbage value if the function actually succeeded. ERROR_INVALID_FUNCTION certainly has a high garbage value.
The code is also fairly broken when there actually is an error, it doesn't nearly make enough noise and the client code can easily ignore the invalid handle value. Proper code is:
bool success = WinUsb_Initialize(...);
if (!success) throw new System.ComponentModel.Win32Exception();
The exception constructor already calls Marshal.GetLastWin32Error() and will produce an appropriate localized error message.
I believe you are connecting to a device that is not actually using winusb.sys as one of its drivers. To other people who might read this, you can check if a device uses winusb.sys by double-clicking it in the Device Manager, going to the "Driver" tab, and clicking on "Driver Details". If you don't see winusb.sys there then this is not a WinUSB device.
To have a WinUSB device, you need to write a proper INF file and then tell Windows to use it one way or another.
It looks like you are trying to access an HID. Instead of using WinUSB I would recommend HIDAPI.

Injecting Python Code into Process

I want to Inject Python Code into a process and It seems to be crashing my process when it injects. I do not get any errors on my own program but the target process stops working. The called unmanaged APIs have not given me any errors and seem to have carried out their execution properly.
[DllImport("kernel32")]
public static extern IntPtr CreateRemoteThread(IntPtr hProcess,IntPtr lpThreadAttributes,uint dwStackSize, IntPtr lpStartAddress,IntPtr lpParameter,uint dwCreationFlags, out uint lpThreadId);
[Flags]
enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VMOperation = 0x00000008,
VMRead = 0x00000010,
VMWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000
}
[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
[Flags]
public enum AllocationType
{
Commit = 0x1000,
Reserve = 0x2000,
Decommit = 0x4000,
Release = 0x8000,
Reset = 0x80000,
Physical = 0x400000,
TopDown = 0x100000,
WriteWatch = 0x200000,
LargePages = 0x20000000,
VIRTUAL_MEM = (0x1000 | 0x2000)
}
[Flags]
public enum MemoryProtection
{
Execute = 0x10,
ExecuteRead = 0x20,
ExecuteReadWrite = 0x40,
ExecuteWriteCopy = 0x80,
NoAccess = 0x01,
ReadOnly = 0x02,
ReadWrite = 0x04,
WriteCopy = 0x08,
GuardModifierflag = 0x100,
NoCacheModifierflag = 0x200,
WriteCombineModifierflag = 0x400,
PAGE_EXECUTE_READWRITE = 0x00000040
}
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize, uint dwFreeType);
[DllImport("kernel32", SetLastError = true, ExactSpelling = true)]
internal static extern Int32 WaitForSingleObject( IntPtr handle,Int32 milliseconds);
[DllImport("kernel32.dll")]
public static extern Int32 CloseHandle(IntPtr hObject);
private void InjectCode(string shellcode = "print('Hello, World!')")
{
foreach (Process proc in Process.GetProcesses())
{
if (proc.ProcessName == "Toontown")
{
int shellcode_length = shellcode.Length;
IntPtr h_process = OpenProcess(ProcessAccessFlags.All, false, (int)proc.Id);
IntPtr shellcode_address = (IntPtr)VirtualAllocEx(h_process, (IntPtr)0, (uint)shellcode_length, AllocationType.VIRTUAL_MEM, MemoryProtection.PAGE_EXECUTE_READWRITE);
byte[] bytes = new byte[shellcode.Length * sizeof(char)];
Buffer.BlockCopy(shellcode.ToCharArray(), 0, bytes, 0, bytes.Length);
UIntPtr bytesout;
uint t_id;
bool Written = WriteProcessMemory(h_process, shellcode_address, bytes, (uint)shellcode_length, out bytesout);
IntPtr hThread = (IntPtr)CreateRemoteThread(h_process, (IntPtr)null, 0, (IntPtr)shellcode_length, (IntPtr)shellcode_address, 0, out t_id);
int Result = WaitForSingleObject(hThread, 10 * 1000);
if (Result == 0x00000080L || Result == 0x00000102L || Result == 0xFFFFFFFF)
{
if (hThread != null)
{
CloseHandle(hThread);
}
}
Thread.Sleep(1000);
VirtualFreeEx(h_process, shellcode_address, (UIntPtr)0, 0x8000);
if (hThread != null)
{
CloseHandle(hThread);
}
}
}
}
As you may see, I have saved the returned values of the unmanaged API into variables which I used to see if it was working or not, it seemed to be doing fine but it crashes the target process, logs haven't recorded any errors related to it.
Can managed programs inject into unmanaged processes? Am I casting wrong variable types? Is the shellcode translated into byte array incorrectly? Please let me know, thanks.
EDIT: It crashes at CreateRemoteThread
CreateRemoteThread creates a native thread in another process, the start address it receives must point to valid machine code or the thread will crash the process.
The scenario you describe is different, you want to instruct the Python interpreter of another process to execute some code. This can be done, but it is different and considerably more difficult.
Inject a native library into the other process which does two things:
setup the Python interpreter
setup some means of interprocess communication (IPC)
Use the IPC to send the Python code you want to execute to the other process and the code in the library you injected then executes that code using the Python interpreter.
You can find an example of how to inject a DLL into another process in this Codeproject article.
It looks like you are trying to run some arbitrary Python code from .net. Now you are trying to invoke the Python interpreter to actually do this.
The cons of doing this are:-
It is complicated as you found out.
Interprocess communication makes it even harder, as you move bytes across the boundary
Then you need to parse the information that you get from each side into something that makes sense (probably using some kind of XML)
Finally with all the above overhead its slow
Now one way around this is to invoke the python program directly within .net. Now I have never done so in my life AND I have never seen a python in my life (except maybe the type that hisses). Take a look at http://msdn.microsoft.com/en-us/library/ee461504.aspx, unfortunately it looks like they are storing the python in a file and invoking it there. However I am sure you can invoke code stored as a string.
The main disadvantage of using the DLR implementation of python is that you are relying on a third party to get the Python -> CLR translation correct. But I think IronPython is a microsoft sponsored open source project.
For more information see: http://ironpython.codeplex.com/

Problem with Marshal class

I was going through my Win32 class today to work on some long-needed improvements. I am stuck on my disk geometry code. On the
var ob =
(DiskGeometry)Marshal.PtrToStructure(geomp,
typeof (DiskGeometry));
line, it keeps throwing an exception..
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
My code is..
if (Handle.IsInvalid)
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
return new DiskGeometry();
}
var geom = new DiskGeometry();
var geomp = Marshal.AllocHGlobal(Marshal.SizeOf(geom));
Marshal.StructureToPtr(geom, geomp, false);
uint returnedBytes;
if (!DeviceIoControl(Handle, (uint) IOCTL_CONTROL_CODE_CONSTANTS.IOCTL_DISK_GET_DRIVE_GEOMETRY, IntPtr.Zero, 0, ref geomp, (uint)Marshal.SizeOf(typeof(DiskGeometry)), out returnedBytes, IntPtr.Zero))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
return new DiskGeometry();
}
var ob = (DiskGeometry)Marshal.PtrToStructure(geomp, typeof (DiskGeometry));
What am I doing wrong?
Try something like this:
//you don't need to instantiate the managed type before this
var geomp = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DiskGeometry)));
//remove this
Marshal.StructureToPtr(geom, geomp, false);
You just need to allocate a block of memory that DiskIoControl will populate with an unmanaged type. After your pointer is referencing that data, then you marshal it to your managed type.
You can also check Marshal.GetlastWin32Error() for ERROR_INSUFFICIENT_BUFFER after calling DeviceIoControl and make sure that returnedBytes == Marshal.SizeOf(typeof(DiskGeometry))
When marshaling from unmanaged memory to managed memory, "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." errors are a good indication that you do not have the appropriate permissions to access the memory location specified at the given pointer location.
These are the definitions used to validate your code works fine:
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode,
IntPtr lpInBuffer, uint nInBufferSize,
IntPtr lpOutBuffer, uint nOutBufferSize,
out uint lpBytesReturned, IntPtr lpOverlapped);
(other code omitted)
IntPtr Handle = CreateFile("\\\\.\\PhysicalDrive0", (EFileAccess)0, EFileShare.Read | EFileShare.Write, IntPtr.Zero, ECreationDisposition.OpenExisting, (EFileAttributes)0, IntPtr.Zero);
var geom = new DiskGeometry();
var geomp = Marshal.AllocHGlobal(Marshal.SizeOf(geom));
uint returnedBytes = 0;
Marshal.StructureToPtr(geom, geomp, false);
if (!DeviceIoControl(Handle, (uint)IOCTL_DISK_GET_DRIVE_GEOMETRY, IntPtr.Zero, 0, geomp,
(uint)Marshal.SizeOf(typeof(DiskGeometry)),
out returnedBytes,
IntPtr.Zero))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
return;
}
var ob = (DiskGeometry)Marshal.PtrToStructure(geomp, typeof(DiskGeometry));

Categories