从 C# 动态调用非托管代码
Dynamically invoke unmanaged code from C#
一般来说,我需要能够从我在编译时不知道的任何 DLL 调用任何非托管函数。
我看到的所有文章(比如这篇 https://blogs.msdn.microsoft.com/jonathanswift/2006/10/03/dynamically-calling-an-unmanaged-dll-from-net-c/)都建议使用委托,但我不知道在编译时我要调用哪个函数,甚至不知道它需要哪些参数以及需要多少参数。
基本上我有这样的用户输入:call "Kernel32.dll" function "DeleteFile" arguments ["C:\testfile.txt"].
能否请您至少建议如何 google 呢? "dynamically"这个词没用..
这个任务本身有点疯狂,因为它实际上是一个大学项目。不确定它在现实生活中是否有用..
var dll = "kernel32.dll";
var fun = "DeleteFile";
var args = new object[] { "C:\dev\test.txt" };
IntPtr pDll = NativeMethods.LoadLibrary(dll);
IntPtr pFun = NativeMethods.GetProcAddress(pDll, fun);
// How can I call it in a different way, without having a delegate?
Marshal.GetDelegateForFunctionPointer(pFun, typeof(?????));
不确定最终目标到底是什么,但我会采取稍微不同的方法。在 .NET 中,编译器是您可以使用的服务,因此您可以动态生成程序集,然后加载并使用它。所以你的程序本质上是一个 "generator" 你将输入翻译成代码,编译它,加载它,运行 它。您可以为此使用 roslyn。
我也同意 Roslyn 的想法,但是当我看到 "Dynamic" 和 "P/Invoke" 时,好老 System.Reflection.Emit
想到:
var asmName = new AssemblyName("Win32");
var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
var modBuilder = asmBuilder.DefineDynamicModule("Win32", emitSymbolInfo: false);
var typeBuilder = modBuilder.DefineType("Win32.User32", TypeAttributes.Class | TypeAttributes.Public);
// Optional: Use if you need to set properties on DllImportAttribute
var dllImportCtor = typeof(DllImportAttribute).GetConstructor(new Type[] { typeof(string) });
var dllImportBuilder = new CustomAttributeBuilder(dllImportCtor, new object[] { "user32.dll" });
var pinvokeBuilder = typeBuilder.DefinePInvokeMethod(
name: "ShowMessageBox",
dllName: "user32.dll",
entryName: "MessageBoxW",
attributes: MethodAttributes.Static | MethodAttributes.Public,
callingConvention: CallingConventions.Standard,
returnType: typeof(int), // typeof(void) if there is no return value.
// TODO: Construct this array from user input somehow:
parameterTypes: new Type[] { typeof(IntPtr), typeof(string), typeof(string), typeof(uint) },
nativeCallConv: CallingConvention.Winapi,
nativeCharSet: CharSet.Unicode);
pinvokeBuilder.SetCustomAttribute(dllImportBuilder);
Type user32Type = typeBuilder.CreateType();
const uint MB_YESNOCANCEL = 3;
user32Type
.GetMethod("ShowMessageBox", BindingFlags.Static | BindingFlags.Public)
// TODO: User input goes here:
.Invoke(null, new object[] { IntPtr.Zero, "Message Text", "Message Caption", MB_YESNOCANCEL });
不漂亮,我知道。只是我的 0.02 美元。
警告:如果此代码将在较长的 运行 应用程序中被多次调用,请考虑每次都创建一个新的 AppDoman
,并在调用完成后将其释放;因为这是卸载生成的动态程序集的唯一方法。
一般来说,我需要能够从我在编译时不知道的任何 DLL 调用任何非托管函数。
我看到的所有文章(比如这篇 https://blogs.msdn.microsoft.com/jonathanswift/2006/10/03/dynamically-calling-an-unmanaged-dll-from-net-c/)都建议使用委托,但我不知道在编译时我要调用哪个函数,甚至不知道它需要哪些参数以及需要多少参数。
基本上我有这样的用户输入:call "Kernel32.dll" function "DeleteFile" arguments ["C:\testfile.txt"].
能否请您至少建议如何 google 呢? "dynamically"这个词没用..
这个任务本身有点疯狂,因为它实际上是一个大学项目。不确定它在现实生活中是否有用..
var dll = "kernel32.dll";
var fun = "DeleteFile";
var args = new object[] { "C:\dev\test.txt" };
IntPtr pDll = NativeMethods.LoadLibrary(dll);
IntPtr pFun = NativeMethods.GetProcAddress(pDll, fun);
// How can I call it in a different way, without having a delegate?
Marshal.GetDelegateForFunctionPointer(pFun, typeof(?????));
不确定最终目标到底是什么,但我会采取稍微不同的方法。在 .NET 中,编译器是您可以使用的服务,因此您可以动态生成程序集,然后加载并使用它。所以你的程序本质上是一个 "generator" 你将输入翻译成代码,编译它,加载它,运行 它。您可以为此使用 roslyn。
我也同意 Roslyn 的想法,但是当我看到 "Dynamic" 和 "P/Invoke" 时,好老 System.Reflection.Emit
想到:
var asmName = new AssemblyName("Win32");
var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
var modBuilder = asmBuilder.DefineDynamicModule("Win32", emitSymbolInfo: false);
var typeBuilder = modBuilder.DefineType("Win32.User32", TypeAttributes.Class | TypeAttributes.Public);
// Optional: Use if you need to set properties on DllImportAttribute
var dllImportCtor = typeof(DllImportAttribute).GetConstructor(new Type[] { typeof(string) });
var dllImportBuilder = new CustomAttributeBuilder(dllImportCtor, new object[] { "user32.dll" });
var pinvokeBuilder = typeBuilder.DefinePInvokeMethod(
name: "ShowMessageBox",
dllName: "user32.dll",
entryName: "MessageBoxW",
attributes: MethodAttributes.Static | MethodAttributes.Public,
callingConvention: CallingConventions.Standard,
returnType: typeof(int), // typeof(void) if there is no return value.
// TODO: Construct this array from user input somehow:
parameterTypes: new Type[] { typeof(IntPtr), typeof(string), typeof(string), typeof(uint) },
nativeCallConv: CallingConvention.Winapi,
nativeCharSet: CharSet.Unicode);
pinvokeBuilder.SetCustomAttribute(dllImportBuilder);
Type user32Type = typeBuilder.CreateType();
const uint MB_YESNOCANCEL = 3;
user32Type
.GetMethod("ShowMessageBox", BindingFlags.Static | BindingFlags.Public)
// TODO: User input goes here:
.Invoke(null, new object[] { IntPtr.Zero, "Message Text", "Message Caption", MB_YESNOCANCEL });
不漂亮,我知道。只是我的 0.02 美元。
警告:如果此代码将在较长的 运行 应用程序中被多次调用,请考虑每次都创建一个新的 AppDoman
,并在调用完成后将其释放;因为这是卸载生成的动态程序集的唯一方法。