I am currently trying to heavily optimize the runtime of a program and stumbled across the following problem.
Problem
At some point I have to call EnumWindows from the user32.dll (see Microsoft Docs), definition looks like this:
internal static class NativeMethods
{
public delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(EnumWindowsProc enumFunc, IntPtr lParam);
//...
}
As you can see I pass a delegate to do something with each window.
I call this method like this:
NativeMethods.EnumWindows(GetVisibleWindowDelegate, IntPtr.Zero);
with
private bool GetVisibleWindowDelegate(IntPtr windowHandle, int _)
Note: I don't use the int parameter in the delegate, thus the name.
This works just fine. Now for the optimization: I have to access and store several dynamic lists of types List<IntPtr> and IDictionary<int, Rectangle> wrapped in an object called RuntimeInformation across multiple methods in various classes.
Copying the values back and forth from this RuntimeInformation object uses precious runtime of about 20ms on my hardware for each method call. That's why I want to pass this object by reference instead, but I fail to get the reference into my GetVisibleWindowDelegate.
Approach
I can not change the delegate-type because I have no control over calling it.
If I try calling the EnumWindows like this:
NativeMethods.EnumWindows(
(windowHandle, _) => GetVisibleWindowDelegate(windowHandle, ref runtimeInformation),
IntPtr.Zero
);
I get the error
Error CS1628 Cannot use ref, out, or in parameter 'runtimeInformation' inside an anonymous method, lambda expression, query expression, or local function
A class property for references does not exist to my knowledge.
Question
How do I get a reference to my RuntimeInformation into the function I use as delegate? Are there alternatives to this approach?
The solution should have high performance (first priority) and be maintainable.
You can use GCHandle for this. In fact the docs for GCHandle.Alloc have an example for exactly what you're trying to do.
private static bool GetVisibleWindowDelegate(IntPtr windowHandle, IntPtr lparam)
{
var handle = GCHandle.FromIntPtr(lparam);
var runtimeInformation = (RuntimeInformation)handle.Target;
// ...
}
RuntimeInformation runtimeInformation = ...
var handle = GCHandle.Alloc(runtimeInformation);
try
{
var callback = new EnumWindowsProc(GetVisibleWindowDelegate);
NativeMethods.EnumWindows(callback, GCHandle.ToIntPtr(handle));
}
finally
{
handle.Free();
}
Related
I'm trying to implement some P/Invoke code using the new LibraryImport attribute, as opposed to the old DllImport. Specifically, I am trying to marshal a WNDCLASSEXW struct for use in RegisterClassEx.
Here is a simplified, shortened version of my managed implementation of WNDCLASSEXW:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct WindowClass
{
private uint StructSize;
public WindowClassStyle Style;
[MarshalAs(UnmanagedType.FunctionPtr)]
public Win32API.WindowProcedure? WindowProcedure;
private int ClassAdditionalBytes;
private int WindowAdditionalBytes;
public IntPtr Instance;
public IntPtr Icon;
public IntPtr Cursor;
public IntPtr BackgroundBrush;
[MarshalAs(UnmanagedType.LPWStr)]
public string? ClassMenuResourceName;
[MarshalAs(UnmanagedType.LPWStr)]
public string? ClassName;
public IntPtr SmallIcon;
}
And my definition of Win32API.WindowProcedure:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate nint WindowProcedure(IntPtr windowHandle, MessageID messageID, nuint wParam, nint lParam);
And finally my definition of RegisterClassEx:
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")]
public static partial ushort RegisterClassEx(in WindowClass classDefinition);
However, this results in the error:
Error SYSLIB1051: The type 'xxx.WindowClass' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter 'classDefinition'.
Therefore I believe I require custom marshalling for the WindowClass struct.
However, with this system being relatively new, I'm having difficulty finding good guidance on how to do this correctly and optimally. Previously, DllImport would magically marshal most types with little guidance, but LibraryImport appears to require more information, and be a bit stricter.
I could circumvent the problem by changing the type to IntPtr and requiring conversion of the delegate to IntPtr elsewhere in the program, but I would much prefer to do it as close to the managed/unmanaged boundary as possible and keep the structs and exposed native functions usable with more descriptive types.
Some of the resources I have found while searching:
The old P/Invoke documentation regarding delegates/function pointers
The new information regarding CustomMarshaller
The design documentation for the new source generator-based system
Primary Question: How do I correctly implement custom marshalling for my WNDPROC and the LP(C)WSTRs?
Question 2:
I would prefer to use a readonly struct, and turn all of the members into { get; init; } properties instead of fields, due to the nicer semantics. However I've noticed that the MarshalAs attribute cannot be applied to properties. Is there a good way to both use readonly structs with properties, while also providing the necessary information to ensure everything gets marshalled in/out correctly? Specifically for more complex types such as string? <-> LPCWSTR, delegate? <-> void*, and other such types I may encounter.
Bonus Question:
It appears that LibraryImport de-emphasizes the importance of specifying the correct calling convention. It's no longer part of the main attribute like DllImport, instead using a secondary attribute that looks like this: [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvStdcall) })] which frankly looks terrible. Is specifying calling convention necessary or beneficial now?
I was able to get it working with custom marshaling. While Simon's advice of changing the struct to contain the native types makes sense in the general case, in my case it doesn't, as these will be exposed for others to use.
The answer might be different for faster, more frequently called methods, but in this case registering a class and creating a window is inherently quite an expensive operation, so the added overhead of copying data to/from a different struct isn't worth any concern.
The marshaler was implemented like this:
[CustomMarshaller(typeof(WindowClass), MarshalMode.UnmanagedToManagedIn, typeof(WindowClassMarshaler))]
[CustomMarshaller(typeof(WindowClass), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToUnmanagedIn))]
internal static unsafe class WindowClassMarshaler
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal unsafe struct WindowClassUnmanaged
{
public uint StructSize;
public uint Style;
public IntPtr WindowProcedure;
public int ClassAdditionalBytes;
public int WindowAdditionalBytes;
public IntPtr Instance;
public IntPtr Icon;
public IntPtr Cursor;
public IntPtr BackgroundBrush;
public char* ClassMenuResourceName;
public char* ClassName;
public IntPtr SmallIcon;
}
internal static unsafe WindowClass ConvertToManaged(WindowClassUnmanaged unmanaged)
{
return new()
{
WindowProcedure = Marshal.GetDelegateForFunctionPointer<Win32API.WindowProcedure>(unmanaged.WindowProcedure),
ClassMenuResourceName = MarshalHelpers.Win32WideCharArrToString(unmanaged.ClassMenuResourceName),
ClassName = MarshalHelpers.Win32WideCharArrToString(unmanaged.ClassName),
// (remainder omitted, just simple copies)
};
}
internal unsafe ref struct ManagedToUnmanagedIn
{
public static int BufferSize => sizeof(WindowClassUnmanaged);
private byte* UnmanagedBufferStruct;
private char* UnmanagedStrResourceName, UnmanagedStrClassName;
public void FromManaged(WindowClass managed, Span<byte> buffer)
{
IntPtr WindowProcedure = (managed.WindowProcedure == null) ? IntPtr.Zero : Marshal.GetFunctionPointerForDelegate(managed.WindowProcedure);
this.UnmanagedStrResourceName = (managed.ClassMenuResourceName == null) ? null : (char*)Marshal.StringToHGlobalUni(managed.ClassMenuResourceName);
this.UnmanagedStrClassName = (managed.ClassName == null) ? null : (char*)Marshal.StringToHGlobalUni(managed.ClassName);
WindowClassUnmanaged Result = new()
{
WindowProcedure = WindowProcedure,
ClassMenuResourceName = this.UnmanagedStrResourceName,
ClassName = this.UnmanagedStrClassName,
// (remainder omitted, just simple copies)
};
Span<byte> ResultByteView = MemoryMarshal.Cast<WindowClassUnmanaged, byte>(MemoryMarshal.CreateSpan(ref Result, 1));
Debug.Assert(buffer.Length >= ResultByteView.Length, "Target buffer isn't large enough to hold the struct data.");
ResultByteView.CopyTo(buffer);
this.UnmanagedBufferStruct = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer));
}
public byte* ToUnmanaged() => this.UnmanagedBufferStruct;
public void Free()
{
if (this.UnmanagedStrResourceName != null)
{
Marshal.FreeHGlobal((nint)this.UnmanagedStrResourceName);
this.UnmanagedStrResourceName = null;
}
if (this.UnmanagedStrClassName != null)
{
Marshal.FreeHGlobal((nint)this.UnmanagedStrClassName);
this.UnmanagedStrClassName = null;
}
}
}
}
With this helper function to convert a Win32 LP(C)WSTR into a regular .NET string:
public static unsafe string? Win32WideCharArrToString(char* unmanagedArr)
{
if (unmanagedArr == null) { return null; }
int Length = 0;
while (*(unmanagedArr + Length) != 0x0000) { Length++; }
return Encoding.Unicode.GetString((byte*)unmanagedArr, Length * sizeof(char));
}
The nicer WindowClass struct is pretty much the same as before, except readonly, and with all elements being { get; init; }. The MarshalAs attributes on members are no longer required, as the custom marshaling handles everything.
Finally, the actual extern function now looks like this:
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")]
[UnmanagedCallConv(CallConvs = new[] { typeof(CallConvStdcall) })]
public static partial ushort RegisterClassEx([MarshalUsing(typeof(WindowClassMarshaler))] WindowClass classDefinition);
Note that this has been corrected. Previously I used the in keyword on the parameter, but this causes it to pass a pointer to the pointer to the struct data, which is an extra level of indirection that will cause the code to fail. Above is the updated version that works correctly.
I've tested and verified this works both in regular publish modes, as well as with AOT compilation, which was the reason for using LibraryImport in this case.
My bonus question still stands however, is there any benefit in specifying stdcall using UnmanagedCallConv?
I'm having trouble converting a C++ .dll function to C#.
The function is this:
void funct(void*(*handler)(void*));
I think this means passing a pointer to function taking a void pointer and returning a void pointer, as explained here:
Passing Function Pointer.
What I'm trying to do is do the same thing in C#, but I have do idea how. I tried to use delegates, but I am both unsure how to and also if they can even do what I am trying to do.
Thanks for the help!
EDIT:
Here are the C++ functions for register_message_handler and message_handler:
void register_message_handler(void*(*handler)(void*));
void *message_handler(void *raw_message);
EDIT:
xanatos has the exact explanation and conversion to C# below. Thanks a ton xanatos!
void funct(void*(*handler)(void*));
is a function that accepts a pointer and returns a pointer.
In C# it would be:
IntPtr MyFunc(IntPtr ptr);
So you'll need a delegate like:
public IntPtr delegate MessageHandlerDelegate(IntPtr ptr);
[DllImport("mydll.dll")]
public static extern void register_message_handler(MessageHandlerDelegate del);
Note that P/Invoke (calling native methods) is one of the rare cases where Action<...> and Func<...> delegates don't work, and you have to build "specific" delegate.
BUT to call it, it's a little complex, because you must save a "copy" of the delegate so that if the C functions calls this method at any time, this copy is still "alive" and hasn't been GC (see for example https://stackoverflow.com/a/5465074/613130). The most common way to do it is to encapsulate everything in a class, and put the copy in a property/field of the class:
class MyClass
{
public delegate IntPtr MessageHandlerDelegate(IntPtr ptr);
[DllImport("mydll.dll")]
public static extern void register_message_handler(MessageHandlerDelegate del);
[DllImport("mydll.dll")]
public static extern IntPtr message_handler(IntPtr message);
public MessageHandlerDelegate Del { get; set; }
public void Register()
{
// Make a copy of the delegate
Del = Handler;
register_message_handler(Del);
}
public IntPtr Handler(IntPtr ptr)
{
// I don't know what ptr is
Console.WriteLine("Handled");
return IntPtr.Zero; // Return something sensible
}
}
Note that if you use IntPtr then you don't need the unsafe.
If you want to pass message_handler to register_message_handler the safest way is to
// Make a copy of the delegate
Del = message_handler;
register_message_handler(Del);
There is a possibility that you can do directly no there isn't, checked
register_message_handler(message_handler);
and that the CLR will solve this, BUT I'm not sure of this... I can't easily test it, and I wouldn't do it. (if you want to test it, add a GC.Collect() just after the register_message_handler. If after some time you receive a CallbackOnCollectedDelegate error then you know you can't do it :-) )
Mmmh... checked. You can't do the raw register_message_handler(message_handler), you have to use MyClass.
Be very aware of something: it's better to always specify the calling convention C-side and C#-side even in function pointers. C# uses stdcall, while C uses cdecl. In x86 mode you can get very awful silent crashes (in x64 there is a single calling convention)
void __stdcall register_message_handler(void* (__stdcall *handler)(void*));
void * __stdcall message_handler(void *raw_message);
and C# side
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr MessageHandlerDelegate(IntPtr ptr);
[DllImport("Win32Project1.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void register_message_handler(MessageHandlerDelegate del);
[DllImport("Win32Project1.dll", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr message_handler(IntPtr message);
(or everywhere cdecl)
I have some C code which will be called from C# using P/Invoke. I am trying to define an C# equivalent for this C function.
SomeData* DoSomething();
struct SomeData
{
...
}
How do I import this C method to C#? I am having trouble defining the return type of the function.
EDIT:
i had a bunch of functions to import. This is one which had me stuck.
[DllImport("SomeDll.dll")]
public static extern IntPtr DoSomething();
I thought about using IntPtr, even if its the right way what after that?
I'm not quite sure I understand your question but I'll give a shot at answering it. You need to define the structure that is being returned from your C function and use Marshal.PtrToStructure to use the returned structure.
[DllImport("SomeDll.dll")]
public static extern IntPtr DoSomething();
public struct SomeData
{
//...
}
//code to use returned structure
IntPtr result = DoSomething();
SomeData structResult = (SomeData)Marshal.PtrToStructure(result, typeof(SomeData));
I am guessing that what you are trying to achieve is the following:
Your C/C++ native method takes no parameters and returns a pointer to a structure.
The C# equivalent is to return an IntPtr (pointer).
The problem is that you cannot resolve the IntPtr to the structure in C#
...research this:
Marshal.PtrToStructure(IntPtr, Type)
http://msdn.microsoft.com/en-us/library/4ca6d5z7.aspx
You can wrap your code up like so
public static class UnsafeNativeMethods
{
[DllImport("SomeDll.dll")]
private static extern IntPtr DoSomething(); //NO DIRECT CALLS TO NATIVE METHODS!!
public static SomeData SafeDoSomething()
{
try
{
return (SomeData)Marshal.PtrToStructure(DoSomething(), typeof(SomeData));
}
catch(Exception ex)
{
//handle exception
}
}
}
I know the title is bit confusing for my question.
Let me explain:-
There are some DLLs written by my seniors and I use them in C# as follows:
Say, Existing DLL name is SeniorDLL and I want to use function SeniorFunc from that DLL.
What I do is:-
private delegate int SeniorFunc(IntPtr Blah);
[DllImport("kernel32")]
public extern static IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi)]
public extern static IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
SeniorFunc fp_Senior;
and in function where I want to use this function, Before first function call I write:
IntPtr handle;
handle = IntPtr.Zero;
handle = LoadLibrary("<DLL Path>");
IntPtr fPtr = GetProcAddress(handle, "SeniorFunc");
fp_Senior = (SeniorFunc)Marshal.GetDelegateForFunctionPointer(fPtr, typeof(SeniorFunc));
and then I use this function via fp_Senior(<Parameter>);
Now I want to create such DLL for me in C# by which I'll be able to call functions from DLL.
Currently I created a DLL but I have create an instance of class in DLL and then have to access like ClassInstance.MyFunction(<Parameters>);
How can I get directly function calls without creating an instance?
In other words, (I don't know I am correct or wrong) How can I create APIs??
Thanks!!
You don't need an instance here, everything can be static. Something like this, with the necessary error checking added:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
internal static class NativeMethods {
public static void SeniorFunc(IntPtr arg) {
if (fp_Senior == null) lookUpSenior();
fp_Senior(arg);
}
private static void lookUpSenior() {
loadSenior();
IntPtr addr = GetProcAddress(SeniorModule, "seniorfunc");
if (addr == IntPtr.Zero) throw new Win32Exception();
fp_Senior = (SeniorFuncDelegate)Marshal.GetDelegateForFunctionPointer(addr, typeof(SeniorFuncDelegate));
}
private static void loadSenior() {
if (SeniorModule == IntPtr.Zero) {
SeniorModule = LoadLibrary("mumble.dll");
if (SeniorModule == IntPtr.Zero) throw new Win32Exception();
}
}
private static IntPtr SeniorModule;
private delegate int SeniorFuncDelegate(IntPtr Blah);
private static SeniorFuncDelegate fp_Senior;
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
private extern static IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true)]
public extern static IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
}
The point of keeping lookupSenior in a separate method is to allow SeniorFunc() to get inlined so it is fast. If you know you'll always use these functions in your program then you can also write a static constructor for the class and do the lookup there. Saves the null check but makes an exception a bit harder to interpret.
There is no such a thing as a method outside a class in C#. So if you must call a method, you have to specify the class name.
The difference with the DLLs you are currently using is that those DLLs are written in C/C++ or other non-.NET language which does not enforce a strict object-oriented approach like C# does.
Thus, nothing forces you to create an instance of a class when calling a method from a .NET library. If a method is declared as static, you can call it directly through ClassName.MethodName().
When I want get total value of memory in C# I found a kernel32 function in MSDN to invoke data from system. MSDN declare function this way:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
but this don't work correctly. I change "ref" to "[In, Out]" then it work correctly.
How can tell me what is [In, Out] parameters in C#?
In: http://msdn.microsoft.com/de-de/library/system.runtime.interopservices.inattribute.aspx
Out: http://msdn.microsoft.com/de-de/library/system.runtime.interopservices.outattribute.aspx
Short: They control the way data is marshalled. In this case, where you specify both of them, it means that data is marshalled to both sides (caller and callee).
The out and the ref parameters are used to return values in the same variables, ref is enough if you don't know you will use it in or out.
Out if you just want to use the variable to receive data from the function, In if you just want to send data to the function.
ref if you want to send and receive data from a function, if you put nothing so it will be In by default
Note: ref and out parameters are very useful when your method needs to return more than one values.
The following definition works (define the MEMORYSTATUSEX as a class):
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GlobalMemoryStatusEx(MEMORYSTATUSEX lpBuffer);
[StructLayout(LayoutKind.Sequential)]
public sealed class MEMORYSTATUSEX {
public uint dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;
}
Usage
var status = new MEMORYSTATUSEX();
GlobalMemoryStatusEx(status);
If you look at the function definition on MSDN it will tell you whether the parameters are In/Out:
BOOL WINAPI GlobalMemoryStatusEx(
__inout LPMEMORYSTATUSEX lpBuffer
);
In general if it says out, you should use a ref parameter, it makes is easier on any future developers trying to figure out how the code is working. When looking at the function call, you know the developer meant for the argument to be affected.