关于在P/Invoke 中抛出MissingMethodException 的原因
平台调用P/Invoke 是.net Framework 中提供的一套调用运行平台上的native API 的机制,类似于Java 的JNI,通过P/Invoke ,使得.net 编写的程序可以调用外部的(非.net 的)动态链接库(Windows 中是DLL),从而使能力得到扩展。
P/Invoke 只能调用C 方式的导出函数,但是.net 编程是没法引用.h 文件的(数据类型也不兼容),只是执行的时候数据按照函数声明进行封装和传送,因此P/Invoke 能否正常执行就完全依赖于函数声明了,也就是,完全依赖于程序员了。
如果程序员在P/Invoke 函数声明中把函数名写错了,那么执行的时候就会抛出“找不到入口点 XXXX” 的异常。这个问题的原因比较直接,因此也比较容易解决,只需要检查一下相应的函数名即可。
还有一个经常容易碰到,但是又比较诡异的异常,如下图。出错信息是“找不到dll”,于是就纳闷了,dll 文件明明是存在的呀。其实这个出错信息实在是有误导嫌疑,这个异常是“MissingMethodException”,即找不到方法,但是注意,这里不是“找不到入口点 XXXX”异常,所以,不是因为函数名写错了导致的。
在dll 有正常的对应的C导出函数,文件已经正确放到与exe 同一目录的情况下,出现这个异常,是因为系统无法正常加载这个dll,造成无法加载的原因则可能是:
- DLL 本身要求的子系统版本高于当前运行的系统的版本。如:基于WM6 SDK 编译的DLL,放到WM5 环境中被调用。
- DLL 中引用了其他的DLL,而被引用的其他DLL 无法在当前执行环境中正常加载(找不到或者版本不对,等)。
可见这个异常一般出现在调用第三方DLL 的时候,解决的办法是:使用正确的或者兼容子系统版本的DLL;检查其引用的其他DLL 是否存在及其子系统版本。
另外,标准函数调用过程中,参数传递都是把相关指针或者值压栈,所以,P/Invoke 声明中,参数类型被写错、个数不对(即参数被传错),调用仍然可以正常进行,只是函数内部执行的时候可能会异常。如果函数内部没有用到参数,则是完全没有问题的,大家有兴趣可以试试。