从C#动态调用非托管代码

时间:2017-06-15 22:49:56

标签: c# dll pinvoke marshalling unmanaged

一般来说,我需要能够从编译时不知道的任何DLL调用任何非托管函数。

我看过的所有文章(比如https://blogs.msdn.microsoft.com/jonathanswift/2006/10/03/dynamically-calling-an-unmanaged-dll-from-net-c/)都建议使用代理,但我不知道在编译时我要调用哪个函数,甚至不需要调用哪些函数和参数。

基本上我有一个用户输入,如:call" Kernel32.dll"功能"删除文件"参数[" C:\ testfile.txt"]。

请问至少可以建议如何谷歌吗?单词"动态"没有帮助..

任务本身有点疯狂,因为它实际上是一个大学项目。不确定它在现实生活中是否有用..

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(?????));

2 个答案:

答案 0 :(得分:3)

我也同意Roslyn的想法,但当我看到&#34; Dynamic&#34; &#34; P / Invoke&#34; 时,<脑海中浮现出好的 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,并在完成调用时将其处置;因为这是卸载生成的动态程序集的唯一方法。

答案 1 :(得分:1)

不确定最终目标是什么,但我会采取略微不同的方法。在.NET中,编译器是一种可以使用的服务,因此您可以动态生成一个程序集,然后加载它并使用它。所以你的程序基本上是一个&#34;生成器&#34;您将输入转换为代码,编译,加载,运行它。你可以使用roslyn。