精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
近期项目里使用到了此技术,研究后有几个心得和大家分享一二,本文描述了2个调用问题和一些原理的英语翻译,希望大家有所收获。
问题如下图:
使用的import语句如下:
[DllImport("authdll.dll")]
private static extern int KeyPass(StringBuilder key, StringBuilder pass);
经过研究,修改如下,还是没有解决:
[DllImport("authdll.dll",EntryPoint="#1")]
private static extern int KeyPass(StringBuilder key, StringBuilder pass);
再改如下,PInvoke不匹配问题解决了,但是函数执行后,参数获取的值不对:
[DllImport("authdll.dll",EntryPoint="#1", CallingConvention = CallingConvention.Cdecl)]
private static extern int KeyPass(StringBuilder key, StringBuilder pass);
参数问题就是下面问题了。
经研究char*参数对应StringBuilder,调用语句如下:
StringBuilder slkey = new StringBuilder(), slpass = new StringBuilder();
int ireturn = KeyPass(slkey, slpass);
执行后变量里为空,没有值。把import语句修改如下,字符串变量里有值了:
[DllImport("authdll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int KeyPass(StringBuilder key, StringBuilder pass);
这里去掉EntryPoint只是乱试,并没觉得它会是个问题,因为#1入口是通过depends查看dll后是对应的,不会有问题。去掉后可以获取值,只能用实践证明理论,EntryPoint对调用参数有影响。
对函数调用后效果评估后发现和C++的效果不一样,结果字符串的长度不一样,这就更奇怪了,没办法,只有再试着想是不是StringBuilder的空间长度有影响,试着把调用修改如下:
StringBuilder slkey = new StringBuilder(256), slpass = new StringBuilder(256);
int ireturn = KeyPass(slkey, slpass);
在构造函数里,加上长度,扩大内部空间,参数得到的字符串长度正确了。
After spending some time trying to implement this simple task, I started to search similar code examples over the Internet. I was really very surprised when found that all examples were slightly different from what I needed. Finally, I realized that there is no (at least spending 30 min in the net) easy-to-use example, that’s why I decided to write this article.通过互联网找不到满意的例子,所以自己写个。
Assuming that you already know what a DLL is, let's begin with creating a simple one.假设熟悉DLL。
OK, now we should attach an empty source file to our blank project.
In the opened window, enter the following code:输入如下代码
#include <stdio.h> extern "C" { __declspec(dllexport) void DisplayHelloFromDLL() { printf ("Hello from DLL !\n"); } }
Please note that __declspec(dllexport) is an obligatory prefix which makes DLL functions available from an external application.__declspec(dllexport)是必须的前缀,它使DLL函数面向外部的项目可用。
extern “C” (with brackets) is also very important, it shows that all code within brackets is available from “outside”. Although code will compile even without this statement, during runtime, you’ll get a very unpleasant error. So, do not forget to include it.
Build this application and your DLL will be ready-to-use.
Now it’s time to create an application which will use our DLL, as the main title explains. We will create this type of application using Microsoft’s C#.
Into the specified class, insert the following two lines:
[DllImport("TestLib.dll")] public static extern void DisplayHelloFromDLL ();
In C#, keyword extern indicates that the method is implemented externally.extern表示方法在外部实现。
Your code should look something like this:
using System; using System.Runtime.InteropServices; // DLL support class HelloWorld { [DllImport("TestLib.dll")] public static extern void DisplayHelloFromDLL (); static void Main () { Console.WriteLine ("This is C# program"); DisplayHelloFromDLL (); } }
Please, note that System.Runtime.InteropServices is required for operations with the DLL.注意 System.Runtime.InteropServices是强制需要的。
According to MSDN:
“The System.Runtime.InteropServices namespace provides a collection of classes useful for accessing COM objects, and native APIs from .NET”它提供集合类用于存取COM对象,和本地API
OK, now build this application, and then copy the previously built DLL into the Debug/Release directory of the current application. The DLL should be in the same directory as your main application.
Now start an application. If everything you’ve made was correct, you should get something like this:拷贝dll文件到C#项目的debug/release目录来测试。