Monotouch PInvoke System.EntryPointNotFoundException
我使用 monotouch 将一些 C# 代码嵌入到 iPhone Objective-C 应用程序中。我能够调用 C# 代码并获取返回值,但无法使用 PInvoke 从 C# 代码调用 C 函数。我正在尝试让一个简单的例子起作用。这是一个简单的计算器。目标 c 代码调用 C# 代码来添加两个整数。然后,C# 代码应该回调 Objective-C 代码并为其提供更新的值。下面是处理计算的 C# 代码:
public class MyClass
{
static public void Add(int a, int b)
{
updateResult(a + b);
}
[DllImport("__Internal", EntryPoint="updateResult")]
static extern public void updateResult(int result);
}
这是我初始化 mono 并处理 add 方法的代码:
@implementation Mono
- (id)init {
self = [super init];
if (self) {
NSBundle *main = [NSBundle mainBundle];
NSString *path = [main bundlePath];
const char *c_path = [path UTF8String];
[main autorelease];
[path autorelease];
chdir (c_path);
setenv ("MONO_PATH", c_path, 1);
setenv ("MONO_XMLSERIALIZER_THS", "no", 1);
setenv ("DYLD_BIND_AT_LAUNCH", "1", 1);
setenv ("MONO_REFLECTION_SERIALIZER", "yes", 1);
#if defined (__arm__)
mono_aot_register_module (mono_aot_module_mscorlib_info);
mono_aot_register_module (mono_aot_module_Math_info);
mono_jit_set_aot_only (TRUE);
#endif
mono_jit_init("MonoTouch");
MonoAssembly *assembly = mono_assembly_open("Math.dll", NULL);
MonoImage *img = mono_assembly_get_image(assembly);
MonoClass *cls = mono_class_from_name(img, "Math", "MyClass");
MonoMethodDesc *methodDesc = mono_method_desc_new("Math.MyClass:Add", TRUE);
_addMethod = mono_method_desc_search_in_class(methodDesc, cls);
}
return self;
}
- (void)addA:(int)a plusB:(int)b {
void *params[] = { &a, &b };
mono_runtime_invoke(_addMethod, NULL, params, NULL);
}
@end
这里是 updateResults 方法的定义:
extern void updateResult(int result) {
printf("Got Result");
}
当从 C# 端调用 updateResults 时,我得到以下异常:
Unhandled Exception: System.EntryPointNotFoundException: updateResult
at (wrapper managed-to-native) Math.MyClass:updateResult (int)
at Math.MyClass.Add (Int32 a, Int32 b) [0x00000] in <filename unknown>:0
我可以使用以下命令查看二进制文件中的符号:
$ nm Calc | grep updateResult
00002b2e t _updateResult
设置 MONO_LOG_LEVEL 环境变量进行调试 在尝试 PInvoke 时,我得到以下输出。看起来好像找到了方法,然后就找不到了:
Mono:DllImport 尝试加载:'_Internal'。Mono:搜索“updateResult”。Mono:探测“updateResult”。Mono:探测“updateResult”。Mono:探测“updateResultA”。Mono:探测“updateResultA”。Mono:探测“updateResult”。Mono:探测“updateResult”。Mono:探测“updateResultA”。 'updateResultA'.Mono: DllImport 尝试加载:'_Internal'.Mono: 搜索 'updateResult'.Mono: 探测 'updateResult'.Mono: 探测 'updateResult'.Mono: 探测 'updateResultA'.Mono:探测“updateResultA”.Mono:AOT FOUND AOT 编译代码(包装器托管到本机)Math.MyClass:updateResult (int) 0x3bc8 - 0x3d90 0x3dcb
Mono:DllImport 尝试加载:“__Internal”。Mono:搜索“updateResult”。Mono:探测“updateResult”。Mono:探测“updateResult”。Mono:探测“updateResultA”。Mono:探测“updateResultA”。无法解析 pinvoke 方法“Math.MyClass:updateResult (int)”,请使用 MONO_LOG_LEVEL=debug 重新运行以获取更多信息。
我花了相当长的时间试图弄清楚这一点。从我读到的内容看来这应该是相当微不足道的,但我无法让它工作。任何帮助将不胜感激。
I've embedded some C# code into an iphone objective-c app using monotouch. I'm able to call into the C# code and get a return value, but I am not able to invoke a C function from the C# code using PInvoke. I am attempting to get a trivial example working. It is a simple calculator. The objective c code calls into the C# code to add two integers. The C# code should then call back into the objective-c code and give it the updated value. Below is the C# code that handles the calculation:
public class MyClass
{
static public void Add(int a, int b)
{
updateResult(a + b);
}
[DllImport("__Internal", EntryPoint="updateResult")]
static extern public void updateResult(int result);
}
Here is my code that initializes mono and handles the add method:
@implementation Mono
- (id)init {
self = [super init];
if (self) {
NSBundle *main = [NSBundle mainBundle];
NSString *path = [main bundlePath];
const char *c_path = [path UTF8String];
[main autorelease];
[path autorelease];
chdir (c_path);
setenv ("MONO_PATH", c_path, 1);
setenv ("MONO_XMLSERIALIZER_THS", "no", 1);
setenv ("DYLD_BIND_AT_LAUNCH", "1", 1);
setenv ("MONO_REFLECTION_SERIALIZER", "yes", 1);
#if defined (__arm__)
mono_aot_register_module (mono_aot_module_mscorlib_info);
mono_aot_register_module (mono_aot_module_Math_info);
mono_jit_set_aot_only (TRUE);
#endif
mono_jit_init("MonoTouch");
MonoAssembly *assembly = mono_assembly_open("Math.dll", NULL);
MonoImage *img = mono_assembly_get_image(assembly);
MonoClass *cls = mono_class_from_name(img, "Math", "MyClass");
MonoMethodDesc *methodDesc = mono_method_desc_new("Math.MyClass:Add", TRUE);
_addMethod = mono_method_desc_search_in_class(methodDesc, cls);
}
return self;
}
- (void)addA:(int)a plusB:(int)b {
void *params[] = { &a, &b };
mono_runtime_invoke(_addMethod, NULL, params, NULL);
}
@end
and here is the definition of the updateResults method:
extern void updateResult(int result) {
printf("Got Result");
}
When the updateResults is called from the C# side of things I get the following exception:
Unhandled Exception: System.EntryPointNotFoundException: updateResult
at (wrapper managed-to-native) Math.MyClass:updateResult (int)
at Math.MyClass.Add (Int32 a, Int32 b) [0x00000] in <filename unknown>:0
I can see the symbol in the binary with the following command:
$ nm Calc | grep updateResult
00002b2e t _updateResult
Setting the MONO_LOG_LEVEL environment variable to debug I get the following output when attempting the PInvoke. It looks like it finds the method and then can't find it:
Mono: DllImport attempting to load: '_Internal'.Mono: Searching for 'updateResult'.Mono: Probing 'updateResult'.Mono: Probing 'updateResult'.Mono: Probing 'updateResultA'.Mono: Probing 'updateResultA'.Mono: DllImport attempting to load: '_Internal'.Mono: Searching for 'updateResult'.Mono: Probing 'updateResult'.Mono: Probing 'updateResult'.Mono: Probing 'updateResultA'.Mono: Probing 'updateResultA'.Mono: AOT FOUND AOT compiled code for (wrapper managed-to-native) Math.MyClass:updateResult (int) 0x3bc8 - 0x3d90 0x3dcb
Mono: DllImport attempting to load: '__Internal'.Mono: Searching for 'updateResult'.Mono: Probing 'updateResult'.Mono: Probing 'updateResult'.Mono: Probing 'updateResultA'.Mono: Probing 'updateResultA'.Unable to resolve pinvoke method 'Math.MyClass:updateResult (int)' Re-run with MONO_LOG_LEVEL=debug for more information.
I've spent quite some time trying to figure this out. From what I've read it seems like this should be pretty trivial, but I can't get it to work. Any help would be much appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用选择器会更好吗?
这是 MonoTouch 制造商建议的默认路径。
Would it be better to use Selectors?
That is the default path to follow as suggested by the makers of MonoTouch.
可能有一些原因,但我的第一个猜测是您没有在本机代码中的任何地方使用 C 符号,并且 DCE(死代码消除)传递正在删除它。尝试在 Xcode 项目选项中禁用 DCE。
It could be a few things, but my first guess is that you aren't using the C symbol from anywhere in native code, and the DCE (dead code elimination) pass is removing it. Try disabling DCE in your Xcode project options.
我自己也遇到过这个问题,如果您比较二进制文件的 objdump -T 和 objdump -t ,
您会发现缺少“D”标志,因此将 -rdynamic 添加到链接器选项中。
I've had this problem myself, if you compare an objdump -T and objdump -t of your binary,
you'll find that the "D" flag is missing, so add a -rdynamic to your linker options.