I need to use the following C++ function in my WPF application:
/****************************************
* BOOL WINAPI SetWindowFeedbackSetting(
* _In_ HWND hwnd,
* _In_ FEEDBACK_TYPE feedback,
* _In_ DWORD dwFlags,
* _In_ UINT32 size,
* _In_opt_ const VOID *configuration
*);
*****************************************/
But I'm not sure how to Marshal it and how to PInvoke it. This is what I have so far:
public enum FEEDBACK_TYPE : uint {
FEEDBACK_TOUCH_CONTACTVISUALIZATION = 1,
FEEDBACK_PEN_BARRELVISUALIZATION = 2,
FEEDBACK_PEN_TAP = 3,
FEEDBACK_PEN_DOUBLETAP = 4,
FEEDBACK_PEN_PRESSANDHOLD = 5,
FEEDBACK_PEN_RIGHTTAP = 6,
FEEDBACK_TOUCH_TAP = 7,
FEEDBACK_TOUCH_DOUBLETAP = 8,
FEEDBACK_TOUCH_PRESSANDHOLD = 9,
FEEDBACK_TOUCH_RIGHTTAP = 10,
FEEDBACK_GESTURE_PRESSANDTAP = 11,
FEEDBACK_MAX = 0xFFFFFFFF
}
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] // (1)
public static extern bool SetWindowFeedbackSetting(
[In] IntPtr hwnd,
[In] FEEDBACK_TYPE feedback,
[In] uint dwFlags,
[In] uint size, // (2)
[In, Optional] IntPtr configuration // (3)
);
So first, is (1),(2),(3) correct?
Second, if I want to PInvoke this function according to this C++ function call:
BOOL fEnabled = FALSE;
BOOL res = SetWindowFeedbackSetting(
hwnd,
FEEDBACK_TOUCH_CONTACTVISUALIZATION,
0,
sizeof(fEnabled),
&fEnabled
);
What it the way to send the HWND and the boolean?
I'm asking this question to better understand the pinvoke\Marshal mechanism and also since the way I tried is not working.
Thanks
Your translation is accurate. But personally, for convenience, I'd make one overload for each type you need to use. For a boolean:
[DllImport("user32.dll"])
public static extern bool SetWindowFeedbackSetting(
IntPtr hwnd,
FEEDBACK_TYPE feedback,
uint dwFlags,
uint size,
[In] ref bool configuration
);
I removed the attributes that were not needed because they restate default values.
Remember that the Win32 BOOL type, the default marshalling option for C# bool is a 4 byte type. So you must pass 4 as the size.
See this question to learn how to obtain a window handle for your WPF window: How to get the hWnd of Window instance?
From what I remember, P/Invoke mechanism has problems with passing/returning .NET's bool. I'd do:
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] // (1)
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowFeedbackSetting(
[In] IntPtr hwnd,
[In] FEEDBACK_TYPE feedback,
[In] uint dwFlags,
[In] uint size, // (2)
[In, Optional] IntPtr configuration // (3)
);
Then, you have to get HWND for current window in WPF. This question: How to get the hWnd of Window instance? should help in this matter.
For your convenience:
Window window = Window.GetWindow(this);
var wih = new WindowInteropHelper(window);
IntPtr hWnd = wih.Handle;
(credit goes to Drahcir)
Finally, to get address of the boolean, I'd do the following:
int myBool; // Win32's BOOL is actually an 4-byte integral number, 0 or non-zero
GCHandle handle = GCHandle.Alloc(myBool, GCHandleType.Pinned);
try
{
IntPtr ptr = handle.AddrOfPinnedObject();
// use ptr
}
finally
{
handle.Free();
}
Related
So I am trying to use C# and the ObRegisterCallbacks function to get notified about any calls to OpenProcess.
This is the code I have so far:
internal static class Win32SelfProtection
{
[DllImport("NtosKrnl.exe", SetLastError = true, PreserveSig = false)]
private static extern uint ObRegisterCallbacks(IntPtr callbackRegistration, out IntPtr registrationHandle);
[DllImport("NtosKrnl.exe", SetLastError = true, PreserveSig = false)]
private static extern void ObUnRegisterCallbacks(IntPtr registrationHandle);
[DllImport("kernel32.dll")]
internal static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
private const uint OB_OPERATION_HANDLE_CREATE = 0x00000001;
private const uint OB_OPERATION_HANDLE_DUPLICATE = 0x00000002;
private const uint PAGE_READWRITE = 0x04;
[StructLayout(LayoutKind.Sequential)]
internal struct OB_CALLBACK_REGISTRATION
{
internal ushort Version;
internal ushort OperationRegistrationCount; // 1
internal IntPtr Altitude;
internal IntPtr RegistrationContext; // NULL, probably
internal IntPtr OperationRegistration; // OB_OPERATION_REGISTRATION*
}
[StructLayout(LayoutKind.Sequential)]
internal struct OB_OPERATION_REGISTRATION
{
internal IntPtr ObjectType; // PsProcessType
internal uint Operations; // OB_OPERATION_HANDLE_CREATE
internal IntPtr PreOperation; // POB_PRE_OPERATION_CALLBACK
internal IntPtr PostOperation; // POB_POST_OPERATION_CALLBACK
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct UNICODE_STRING
{
internal ushort Length;
internal ushort MaximumLength;
internal IntPtr Buffer;
}
internal static unsafe void Protect()
{
PobPreOperationCallback preOperationCallback = PreOperationCallback;
IntPtr pPreOperationCallback = Marshal.GetFunctionPointerForDelegate(preOperationCallback);
PobPostOperationCallback postOperationCallback = PostOperationCallback;
IntPtr pPostOperationCallback = Marshal.GetFunctionPointerForDelegate(postOperationCallback);
OB_OPERATION_REGISTRATION operationRegistration = new OB_OPERATION_REGISTRATION
{
ObjectType = IntPtr.Zero, // I have no idea ... <-- Need pointer to PsProcessType
Operations = OB_OPERATION_HANDLE_CREATE,
PreOperation = pPreOperationCallback,
PostOperation = pPostOperationCallback
};
IntPtr pOperationRegistration = Marshal.AllocHGlobal(sizeof(OB_OPERATION_REGISTRATION));
Marshal.StructureToPtr(operationRegistration, pOperationRegistration, false);
const ushort buffersize = sizeof(ushort) * 64;
IntPtr buffer = Marshal.AllocHGlobal(buffersize);
// No idea what kind of string I should put in here :C just zero it for now ...
Marshal.Copy(new byte[buffersize], 0, buffer, buffersize);
UNICODE_STRING unicodeString = new UNICODE_STRING
{
Length = buffersize,
MaximumLength = buffersize,
Buffer = buffer
};
IntPtr pUnicodeString = Marshal.AllocHGlobal(sizeof(UNICODE_STRING));
Marshal.StructureToPtr(unicodeString, pUnicodeString, false);
OB_CALLBACK_REGISTRATION callbackRegistration = new OB_CALLBACK_REGISTRATION
{
Version = 0x0100,
OperationRegistrationCount = 1,
Altitude = pUnicodeString,
RegistrationContext = IntPtr.Zero,
OperationRegistration = pOperationRegistration
};
IntPtr pCallbackRegistration = Marshal.AllocHGlobal(sizeof(OB_CALLBACK_REGISTRATION));
Marshal.StructureToPtr(callbackRegistration, pCallbackRegistration, false);
uint status = ObRegisterCallbacks(pCallbackRegistration, out IntPtr hRegistration); // FAILS WITH: AccessViolationException
// yeah, yeah I'll remember to call Marshal.FreeHGlobal() later ... :D
}
public delegate uint PobPreOperationCallback(IntPtr registrationContext, IntPtr operationInformation);
// dummy method for now
internal static uint PreOperationCallback(IntPtr registrationContext, IntPtr operationInformation)
{
Console.WriteLine("PreOperationCallback!");
return 0x0;
}
public delegate void PobPostOperationCallback(IntPtr registrationContext, IntPtr operationInformation);
// dummy method for now
internal static void PostOperationCallback(IntPtr registrationContext, IntPtr operationInformation)
{
Console.WriteLine("PostOperationCallback!");
}
}
The ObRegisterCallbacks function takes an OB_CALLBACK_REGISTRATION struct (docs here) as parameter that itself consists of an array of OB_OPERATION_REGISTRATION structs (docs here).
This is where I'm stuck:
The OB_OPERATION_REGISTRATION's first member, "ObjectType", is documented as follows
ObjectType
A pointer to the object type that triggers the callback routine. Specify one of the following values:
PsProcessType for process handle operations
PsThreadType for thread handle operations
ExDesktopObjectType for desktop handle operations. This value is supported in Windows 10 and not in the earlier versions of the operating system.
After a few hour of searching I still have no clue how I'm supposed to specify PsProcessType and initialize my struct with it. PsProcessType seems to be defined in process.c in line 20.
However it literally just says
POBJECT_TYPE PsProcessType = NULL;
which isn't especially helpful, since when setting the ObjectType field to IntPtr.Zero when initializing the OB_OPERATION_REGISTRATION struct a System.AccessViolationException is triggered when calling ObRegisterCallbacks. (There's also a UNICODE_STRING in the OB_OPERATION_REGISTRATION struct called Altitude that has to be set to some value (but currently isn't lol :D), but that string is initialized and allocated, so it shouldn't be responsible for the access violation... right?)
This is my first time diving this deep into Windows kernel stuff, so it would be nice if someone could help me out with this or point me to some hidden resources I didn't manage to dig up :)
There's an article that uses ObRegisterCallbacks for similar things (in C++ though), however they don't really specify where they're getting PsProcessType from, or how it's defined. So there has to be documentation somewhere out there, if they can successfully use that "ObjectType" field, right?
PsProcessType is exported at ntoskrnl.exe and is the same as ObRegisterCallbacks, the difference between them is that one is an exported global variable and the other is an exported function.
In C, these global variables are declared in wdm.h:
extern POBJECT_TYPE *CmKeyObjectType;
extern POBJECT_TYPE *IoFileObjectType;
extern POBJECT_TYPE *ExEventObjectType;
extern POBJECT_TYPE *ExSemaphoreObjectType;
extern POBJECT_TYPE *TmTransactionManagerObjectType;
extern POBJECT_TYPE *TmResourceManagerObjectType;
extern POBJECT_TYPE *TmEnlistmentObjectType;
extern POBJECT_TYPE *TmTransactionObjectType;
extern POBJECT_TYPE *PsProcessType;
extern POBJECT_TYPE *PsThreadType;
extern POBJECT_TYPE *PsJobType;
extern POBJECT_TYPE *SeTokenObjectType;
#if (NTDDI_VERSION >= NTDDI_THRESHOLD)
extern POBJECT_TYPE *ExDesktopObjectType;
#endif
So you can just use these variables without having to do anything else.
But I'm not good at C#, and I'm not even sure if C# modules can be loaded into the kernel.
The most recommended approach is to use C/C++ for kernel programming, and I've never heard of anyone doing this with C#.
I've tried running this with Process.EnterDebugMode(), but it also doesn't work.
I want to read out the Notepad-memory but I don't know how to access it, or if the 64bit system is doing troubles.
This is what I've done:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
public class MemoryRead
{
[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
static extern bool ReadProcessMemory(int hProcess, Int64 lpBaseAddress, byte[] buffer, int size, ref int lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
static extern bool CloseHandle(IntPtr hObject);
static void Main(string[] args)
{
var pid = 10956; //notepad.exe
var processHandle = OpenProcess(0x10, false, pid);
byte[] buffer = new byte[24];
int bytesRead = 0;
ReadProcessMemory((int)processHandle, 0x21106B35770, buffer, buffer.Length, ref bytesRead); //0x21106B35770 is the address where "hello world" is written in notepad
Console.WriteLine(Encoding.Unicode.GetString(buffer) +
" (" + bytesRead.ToString() + "bytes)");
Console.ReadLine();
CloseHandle(processHandle);
Console.ReadLine();
}
}
Your PInvoke declaration of ReadProcessMemory is incorrect (though it should work on a 32 bit system).
As can be seen from the native declaration of this function
BOOL WINAPI ReadProcessMemory(
_In_ HANDLE hProcess,
_In_ LPCVOID lpBaseAddress,
_Out_ LPVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesRead
);
its first parameter is HANDLE, and it is a PVOID:
A pointer to any type.
This type is declared in WinNT.h as follows:
typedef void *PVOID;
And pointer to anything in 64-bit process is a 64-bit value - IntPtr.
Basically the same goes to the size and lpNumberOfBytesRead parameters - they are 64 bit as well in a 64 bit process.
Thus your declaration should be something like:
[[DllImport("kernel32.dll", SetLastError = true)]]
[return: MarshalAs(UnmanagedType.Bool)]
static extern Boolean ReadProcessMemory(
[In] IntPtr hProcess,
[In] IntPtr lpBaseAddress,
[Out] Byte[] lpBuffer,
[In] UIntPtr nSize,
[Out] out UIntPtr lpNumberOfBytesRead
);
P.S.: And a bit of shameless self-promotion - if you ever have to work a lot with PInvoke, then there are a few good recommendations I've learned a hard way.
I'm trying to write a DWORD to registry using c#.
Using p/invoke because of registry reddirection.
I've searched for this issue and finally could get it working but i don't understand.
[DllImport("advapi32.dll", SetLastError = true)]
static extern uint RegSetValueEx(
IntPtr hKey,
[MarshalAs(UnmanagedType.LPStr)]
string lpValueName,
int Reserved,
RegistryValueKind dwType,
ref IntPtr lpData,
int cbData);
int checkreturn = RegOpenKeyEx(HKeyLocalMachine, #"SOFTWARE\Test", 0, (int) RegistrySecurity.KEY_WOW64_64KEY | (int) RegistrySecurity.KEY_SET_VALUE, ref keyHandle);
const int dataStored = 0;
IntPtr p = new IntPtr(dataStored);
int size = Marshal.SizeOf(dataStored);
uint checkreturn2 = RegSetValueEx(keyHandle, "valueName", 0, RegistryValueKind.DWord, ref p, size);
This works if i put out or ref on lpData parameter, if i don't it returns error 998 (ERROR_NOACCESS), why is that? The same thing happens if i change the IntPtr to int, and pass the actual value, but this time i get an first exception AccessViolation on my code.
the winapi declaration for that it's *lpData, which i assume is what passing a IntPtr is.
_In_ const BYTE *lpData,
The api requires a pointer to the data plus the size of the data. You can't pass an int, or a char, or a bool. You need to pass a pointer to the data. If you pass something else, the API will interpret it as a pointer to the data, and random results will happen.
With P/Invoke, a ref to something is translated to a pointer to that something.
Now, you can
[DllImport("advapi32.dll", SetLastError = true)]
static extern uint RegSetValueEx(
IntPtr hKey,
[MarshalAs(UnmanagedType.LPStr)]
string lpValueName,
int Reserved,
RegistryValueKind dwType,
ref uint lpData,
int cbData);
and then in cbData pass sizeof(uint) and this will work, because a ref for P/Invoke is a ref.
Only thing, I would suggest removing the
[MarshalAs(UnmanagedType.LPStr)]
because without it the P/Invoke will use the Unicode version of the method, that is more correct.
I am working on a dll injection soft in c#, the injected dll is also in c# and i'am using pinvoke for certain system functions.
When using extTextOut i get the string scrambled and the lines get mixed together
What am i doing wrong?
I hooked extTextOut using EasyHook from codeplex.com like this:
try
{
CreateFileHook = LocalHook.Create(
LocalHook.GetProcAddress("gdi32.dll", "ExtTextOutW"),
new DExtTextOutW(ExtTextOutW_Hooked),
this);
CreateFileHook.ThreadACL.SetExclusiveACL(new Int32[1]);
}
and my extTextOut method is
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
static extern bool ExtTextOutW(IntPtr hdc,
int X,
int Y,
uint fuOptions,
[In] ref RECT lprc,
string lpString,
uint cbCount,
[In] IntPtr lpDx);
static bool ExtTextOutW_Hooked(
IntPtr hdc,
int X,
int Y,
uint fuOptions,
[In] ref RECT lprc,
string lpString,
uint cbCount,
[In] IntPtr lpDx)
{
try
{
DemoInjection This = (DemoInjection)HookRuntimeInfo.Callback;
lock (This.Queue)
{
This.Queue.Push(lpString);
}
}
catch
{
}
return ExtTextOutW(
hdc,
X,
Y,
fuOptions,
ref lprc,
lpString,
cbCount,
lpDx
);
}
And another question if i may. How can i constantly monitor a window which is out of focus or minimized(using this approach it does not work properly)
Thanks a lot!
If I understand correctly what you meant by "string scrambled and the lines get mixed" than there are two issues that might help you:
The string could be output as Glyphs indices and not as Chars (therefore will appear as scrambled text).
You should refer only to the amount of chars supplied by cbCount param other chars in the string may be "garbage" chars.
Hope that helped.
I want to use the MiniDumpWriteDump function to create some custom dump files (mainly, i want to export a dump file that contains the minimum amount of information for the thread callstacks), but i am having difficulties defining the structures that need to be passed as a parameter to the callback function
[StructLayout(LayoutKind.Explicit)]
internal struct MINIDUMP_CALLBACK_OUTPUT
{
[FieldOffset(0)]
public ulong ModuleWriteFlags;
[FieldOffset(0)]
public ulong ThreadWriteFlags;
}
public struct MINIDUMP_CALLBACK_INFORMATION
{
public IntPtr CallbackRoutine;
public IntPtr CallbackParam;
}
public delegate bool MINIDUMP_CALLBACK_ROUTINE(
IntPtr CallBackParam,
MINIDUMP_CALLBACK_INPUT input,
MINIDUMP_CALLBACK_OUTPUT output);
[DllImport("dbghelp.dll")]
public static extern bool MiniDumpWriteDump(IntPtr hProcess, Int32 ProcessId, IntPtr hFile, int DumpType,
IntPtr ExceptionParam, IntPtr UserStreamParam, IntPtr CallStackParam);
And the call looks like this:
MINIDUMP_CALLBACK_INFORMATION mci;
MINIDUMP_CALLBACK_ROUTINE r = new MINIDUMP_CALLBACK_ROUTINE(MyCallback);
GC.KeepAlive(r);
mci.CallbackRoutine = Marshal.GetFunctionPointerForDelegate(r);
mci.CallbackParam = IntPtr.Zero;
IntPtr structPointer = Marshal.AllocHGlobal(Marshal.SizeOf(mci));
Marshal.StructureToPtr(mci, structPointer, true);
MiniDumpWriteDump(process[0].Handle, process[0].Id,
fs.SafeFileHandle.DangerousGetHandle(),
(int)MINIDUMP_TYPE.MiniDumpNormal,
Marshal.GetExceptionPointers(),
IntPtr.Zero,
structPointer);
Marshal.FreeHGlobal(structPointer);
So my question is how to define MINIDUMP_CALLBACK_INPUT:
The definition of the structures in C that pose problems are:
typedef struct _MINIDUMP_CALLBACK_INPUT
{
ULONG ProcessId;
HANDLE ProcessHandle;
ULONG CallbackType;
union
{
MINIDUMP_THREAD_CALLBACK Thread;
MINIDUMP_THREAD_EX_CALLBACK ThreadEx;
MINIDUMP_MODULE_CALLBACK Module;
MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread;
MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule;
} u;
} MINIDUMP_CALLBACK_INPUT
typedef struct _MINIDUMP_MODULE_CALLBACK
{
PWCHAR FullPath;
ULONGLONG BaseOfImage;
ULONG SizeOfImage;
ULONG CheckSum;
ULONG TimeDateStamp;
VS_FIXEDFILEINFO VersionInfo;
PVOID CvRecord;
ULONG SizeOfCvRecord;
PVOID MiscRecord;
ULONG SizeOfMiscRecord;
} MINIDUMP_MODULE_CALLBACK
It's not a direct answer of your question but a workaround...
Do you know the ClrDump lib which does what you need ? I've used it for a project several years ago and it works fine for me.
Answer to author comment:
Read on the site:
ClrDump can produce small minidumps that contain enough information to recover the call stacks of all threads in the application.
I wrapped the API in the following class:
internal class ClrDump
{
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("clrdump.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern bool CreateDump(uint ProcessId, string FileName, MINIDUMP_TYPE DumpType, uint ExcThreadId, IntPtr ExtPtrs);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("clrdump.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern bool RegisterFilter(string FileName, MINIDUMP_TYPE DumpType);
[DllImport("clrdump.dll")]
public static extern FILTER_OPTIONS SetFilterOptions(FILTER_OPTIONS Options);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("clrdump.dll", SetLastError=true)]
public static extern bool UnregisterFilter();
[Flags]
public enum FILTER_OPTIONS
{
CLRDMP_OPT_CALLDEFAULTHANDLER = 1
}
[Flags]
public enum MINIDUMP_TYPE
{
MiniDumpFilterMemory = 8,
MiniDumpFilterModulePaths = 0x80,
MiniDumpNormal = 0,
MiniDumpScanMemory = 0x10,
MiniDumpWithCodeSegs = 0x2000,
MiniDumpWithDataSegs = 1,
MiniDumpWithFullMemory = 2,
MiniDumpWithFullMemoryInfo = 0x800,
MiniDumpWithHandleData = 4,
MiniDumpWithIndirectlyReferencedMemory = 0x40,
MiniDumpWithoutManagedState = 0x4000,
MiniDumpWithoutOptionalData = 0x400,
MiniDumpWithPrivateReadWriteMemory = 0x200,
MiniDumpWithProcessThreadData = 0x100,
MiniDumpWithThreadInfo = 0x1000,
MiniDumpWithUnloadedModules = 0x20
}
}
and then, somewhere in my initialization code, I called the method RegisterFilter which registers an internal filter for unhandled exceptions in the current process. If the process crashes with unhandled exception (it can be native or managed exception), the filter catches it and creates a minidump (with the specified file name). Here is a sample code for this:
StringBuilder sb = new StringBuilder();
sb.Append(Path.GetFileNameWithoutExtension(Application.ExecutablePath));
sb.Append("_");
sb.Append(DateTime.Now.ToString("yyyyMMddHHmmssFF"));
sb.Append(".dmp");
string dmpFilePath = Path.Combine(Path.GetTempPath(), sb.ToString());
ClrDump.RegisterFilter(_dmpFilePath, ClrDump.MINIDUMP_TYPE.MiniDumpNormal);
You can read this article to understand the different MINIDUMP_TYPE options, but I think the basic one (MiniDumpNormal) could fit your needs.
Use this code to define a structure with union in 32 bits:
[StructLayout(LayoutKind.Explicit)]
internal struct MINIDUMP_CALLBACK_INPUT
{
[FieldOffset(0)]
UInt32 ProcessId;
[FieldOffset(4)]
IntPtr ProcessHandle;
[FieldOffset(8)]
UInt32 CallbackType;
[FieldOffset(12)]
MINIDUMP_THREAD_CALLBACK Thread;
[FieldOffset(12)]
MINIDUMP_THREAD_EX_CALLBACK ThreadEx;
[FieldOffset(12)]
MINIDUMP_MODULE_CALLBACK Module;
[FieldOffset(12)]
MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread;
[FieldOffset(12)]
MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule;
};
I think that on a 64 bits platform, the offsets should be respectively { 0, 8, 16, 24 } or { 0, 4, 12, 16 } whether ULONG is 64 or 32 bits.
Edit
I think you can use the MarshalAsAttribute to specifically convert fields:
[StructLayout(LayoutKind.Sequential)]
struct VS_FIXEDFILEINFO
{
UInt32 dwSignature;
UInt32 dwStrucVersion;
UInt32 dwFileVersionMS;
UInt32 dwFileVersionLS;
UInt32 dwProductVersionMS;
UInt32 dwProductVersionLS;
UInt32 dwFileFlagsMask;
UInt32 dwFileFlags;
UInt32 dwFileOS;
UInt32 dwFileType;
UInt32 dwFileSubtype;
UInt32 dwFileDateMS;
UInt32 dwFileDateLS;
}
[StructLayout (LayoutKind.Sequential)]
struct MINIDUMP_MODULE_CALLBACK
{
[MarshalAs(UnmanagedType.LPWStr)]
String FullPath;
UInt64 BaseOfImage;
UInt32 SizeOfImage;
UInt32 CheckSum;
UInt32 TimeDateStamp;
VS_FIXEDFILEINFO VersionInfo;
IntPtr CvRecord;
UInt32 SizeOfCvRecord;
IntPtr MiscRecord;
UInt32 SizeOfMiscRecord;
}
I take it that it is the union that is giving you trouble?
If CallbackType==KernelMinidumpStatusCallback, then the CALLBACK_INPUT structure is defined as:
ULONG ProcessId;
HANDLE ProcessHandle;
ULONG CallbackType;
HRESULT Status;
If CallbackType==ThreadCallback, then it is:
ULONG ProcessId;
HANDLE ProcessHandle;
ULONG CallbackType;
MINIDUMP_THREAD_CALLBACK Thread;
If CallbackType==ThreadExCallback, then it is:
ULONG ProcessId;
HANDLE ProcessHandle;
ULONG CallbackType;
MINIDUMP_THREAD_EX_CALLBACK ThreadEx;
And so on (this is from MSDN) -- it looks like that 4th member can be one of 8 different types, depending on what CallbackType is equal to. Internally, Windows will use the same chunk of memory for all of these structures (padding the smaller ones to the largest one's size). In C++, it's an easy typecast to get the type you need.
I'm not sure how to do this in C#. I have used MiniDumpWriteDump in C++, but never used the callback function. If you could be sure that CallbackType was always one value, you could just code that one structure, but I don't know if this is the case.
Sorry I can't provide more information, but maybe this helps describe the problem.