Passing a Class to an Unmanaged function as parameter
-
Hai all... I was trying to pass a class to an Unmanaged function. The class has a member of type, of the same class. Is it possible to pass a Managed class(Class having a member of it's own type) to an Unmanaged function. Thanks in advance:rose: Below is what i did... This is the class i created to pass into an Unmanaged function as parameter [StructLayout(LayoutKind.Explicit )] public class MyWindow { [FieldOffset (0)] public String className; [FieldOffset (16)] public String caption; [FieldOffset (32)] public MyWindow child ; } But if i remove the class member 'child' from the class it works well. Unmanaged function Decleration [DllImport("user32")] public static extern bool EnumChildWindows(int hwndParent, EnumChildDelegare lpEnumFunc, MyWindow lParam) ; This is the way how i call the unmanaged function MyWindow m = new MyWindow (); Win32Calls.EnumChildWindows (winHandle,w.enumChildDlgate ,m); And i am getting this error. An unhandled exception of type 'System.TypeLoadException' occurred in CSRecorder.exe Additional information: Can not marshal field child of type CSRecorder.MyWindow: This type can not be marshaled as a structure field. Shaju Mathew
-
Hai all... I was trying to pass a class to an Unmanaged function. The class has a member of type, of the same class. Is it possible to pass a Managed class(Class having a member of it's own type) to an Unmanaged function. Thanks in advance:rose: Below is what i did... This is the class i created to pass into an Unmanaged function as parameter [StructLayout(LayoutKind.Explicit )] public class MyWindow { [FieldOffset (0)] public String className; [FieldOffset (16)] public String caption; [FieldOffset (32)] public MyWindow child ; } But if i remove the class member 'child' from the class it works well. Unmanaged function Decleration [DllImport("user32")] public static extern bool EnumChildWindows(int hwndParent, EnumChildDelegare lpEnumFunc, MyWindow lParam) ; This is the way how i call the unmanaged function MyWindow m = new MyWindow (); Win32Calls.EnumChildWindows (winHandle,w.enumChildDlgate ,m); And i am getting this error. An unhandled exception of type 'System.TypeLoadException' occurred in CSRecorder.exe Additional information: Can not marshal field child of type CSRecorder.MyWindow: This type can not be marshaled as a structure field. Shaju Mathew
First, change the class to a struct. This allocates the data on the stack so it will not be moved. While this isn't the direct cause of your problem, it may lead to them. If it's a class - which is allocated on the heap - the GC (Garbage Collector) may move it when necessary and your handle that your enumerator is using would be invalid. Declaring this as a struct should also fix the other error. There is a problem with your
EnumChildWindows
as well. AnHWND
is a processor-dependent type. You should really declare this asIntPtr
, which works well since P/Invoking other unmanaged Windows APIs will useIntPtr
andControl.Handle
(theHWND
for the control) is also of typeIntPtr
. Any native int or unsigned int should be declared as anIntPtr
. Also, for your struct, just useLayoutKind.Sequential
. You really don't even need that, however, since the memory address to your struct's instance is being passed to your enumerator so it doesn't need to be marshaled for use with unmanaged code. Just a couple of tips.Microsoft MVP, Visual C# My Articles
-
Hai all... I was trying to pass a class to an Unmanaged function. The class has a member of type, of the same class. Is it possible to pass a Managed class(Class having a member of it's own type) to an Unmanaged function. Thanks in advance:rose: Below is what i did... This is the class i created to pass into an Unmanaged function as parameter [StructLayout(LayoutKind.Explicit )] public class MyWindow { [FieldOffset (0)] public String className; [FieldOffset (16)] public String caption; [FieldOffset (32)] public MyWindow child ; } But if i remove the class member 'child' from the class it works well. Unmanaged function Decleration [DllImport("user32")] public static extern bool EnumChildWindows(int hwndParent, EnumChildDelegare lpEnumFunc, MyWindow lParam) ; This is the way how i call the unmanaged function MyWindow m = new MyWindow (); Win32Calls.EnumChildWindows (winHandle,w.enumChildDlgate ,m); And i am getting this error. An unhandled exception of type 'System.TypeLoadException' occurred in CSRecorder.exe Additional information: Can not marshal field child of type CSRecorder.MyWindow: This type can not be marshaled as a structure field. Shaju Mathew
When I was marshalling EnumChildWindows, I declared the function like that:
[DllImport("user32.dll",SetLastError=true)] public static extern bool EnumChildWindows( IntPtr hWndParent, User32Functions.EnumWindowsCallback lpEnumFunc, IntPtr lParam );
The point is, why do you need to pass a class or struct as the third parameter? I followed the MSDN recommendation and called the function like that:GCHandle gch=GCHandle.Alloc(this.twHandles); User32.EnumChildWindows(handleParent,this.enumThreadCallback,(IntPtr)gch); gch.Free();
Here this.twHandles is a text writer, which i later (in the callback function) use like so:private bool CaptureEnumThreadWindows(int handle, IntPtr param) { GCHandle gch=(GCHandle)param; TextWriter tw=(TextWriter)gch.Target; twHandles.Write(handle.ToString()+" "); twHandles.Flush(); return true; }
Anyway, MSDN recommends to use GCHandle , 'so the delegate does not get moved by GC before the call ends, however I was trying to use without GCHandle, just passing IntPtr.Zero as the last parameter and it works anyway. Frankly I don't understand how this (GCHandle) can prevent the delegate from being moved by GC, but that's what MSDN says. (see GCHandle sample) -
First, change the class to a struct. This allocates the data on the stack so it will not be moved. While this isn't the direct cause of your problem, it may lead to them. If it's a class - which is allocated on the heap - the GC (Garbage Collector) may move it when necessary and your handle that your enumerator is using would be invalid. Declaring this as a struct should also fix the other error. There is a problem with your
EnumChildWindows
as well. AnHWND
is a processor-dependent type. You should really declare this asIntPtr
, which works well since P/Invoking other unmanaged Windows APIs will useIntPtr
andControl.Handle
(theHWND
for the control) is also of typeIntPtr
. Any native int or unsigned int should be declared as anIntPtr
. Also, for your struct, just useLayoutKind.Sequential
. You really don't even need that, however, since the memory address to your struct's instance is being passed to your enumerator so it doesn't need to be marshaled for use with unmanaged code. Just a couple of tips.Microsoft MVP, Visual C# My Articles
Thanks... Heath Stewart The tips helped .. But i cannot change class to struct. Since struct won't allow the same struct as a member Shaju Mathew
-
When I was marshalling EnumChildWindows, I declared the function like that:
[DllImport("user32.dll",SetLastError=true)] public static extern bool EnumChildWindows( IntPtr hWndParent, User32Functions.EnumWindowsCallback lpEnumFunc, IntPtr lParam );
The point is, why do you need to pass a class or struct as the third parameter? I followed the MSDN recommendation and called the function like that:GCHandle gch=GCHandle.Alloc(this.twHandles); User32.EnumChildWindows(handleParent,this.enumThreadCallback,(IntPtr)gch); gch.Free();
Here this.twHandles is a text writer, which i later (in the callback function) use like so:private bool CaptureEnumThreadWindows(int handle, IntPtr param) { GCHandle gch=(GCHandle)param; TextWriter tw=(TextWriter)gch.Target; twHandles.Write(handle.ToString()+" "); twHandles.Flush(); return true; }
Anyway, MSDN recommends to use GCHandle , 'so the delegate does not get moved by GC before the call ends, however I was trying to use without GCHandle, just passing IntPtr.Zero as the last parameter and it works anyway. Frankly I don't understand how this (GCHandle) can prevent the delegate from being moved by GC, but that's what MSDN says. (see GCHandle sample)Thanks Ael GCHandle worked well And it solved my problem. Shaju Mathew
-
Thanks... Heath Stewart The tips helped .. But i cannot change class to struct. Since struct won't allow the same struct as a member Shaju Mathew
In that case, use a
GCHandle
to pin the class instance in memory. The GC (Garbage Collector) may relocate the object in memory, so the address would change. Unmanaged code can't deal with those changes so you'll get all sorts of errors since your object isn't where it's supposed to be. You can find more information about theGCHandle
class in the .NET Framework SDK.Microsoft MVP, Visual C# My Articles