C++ void*参数封送问题:Adobe XMPToolKitSDK调用后propValue无返回
首先明确:C++的void*在.NET中用IntPtr封送是正确的选择,问题大概率出在回调函数的封送约定、P/Invoke声明细节或参数传递逻辑上,以下是具体解决建议:
检查回调函数的封送约定
Adobe XMP SDK默认使用C调用约定(Cdecl),务必确保回调委托声明指定正确的调用约定,否则会出现栈不平衡导致参数传递异常:[UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate void SetClientStringDelegate(IntPtr context, IntPtr value);同时要保证回调函数的参数数量、类型与C端原型严格匹配,比如C端的
SetClientStringProc通常是typedef void (*SetClientStringProc)(void* context, const char* value);,对应C#的签名要完全对齐。修正WXMPMeta_GetProperty_1的P/Invoke声明
如果C端该函数的propValue参数是void**(用于输出指针),C#中应使用out IntPtr而非ref IntPtr——ref要求参数有初始值,而out更符合C双重指针的输出语义,示例声明:[DllImport("XMPCore.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] static extern int WXMPMeta_GetProperty_1(IntPtr self, string schemaNS, string propName, out IntPtr propValue, uint options);避免回调委托被GC回收
回调委托实例如果是局部变量,很可能被.NET GC提前回收,导致调用时出现非法访问。需将委托实例保存为类成员变量,比如:private SetClientStringDelegate _setClientStringDelegate; // 初始化时绑定委托 _setClientStringDelegate = mySetClientString; // 注册回调时传入该委托的IntPtr验证属性值的内存有效性
XMP SDK返回的propValue可能是内部临时内存,函数调用结束后会被释放。如果回调能正确获取值,但propValue后续返回0,可在回调中立即将值复制到托管内存中,比如用Marshal.PtrToStringAnsi(value)将字符串指针转换为C#字符串保存。调试定位问题
可在C#中尝试用Marshal.PtrToStringAnsi(propValue)直接读取指针内容,判断是否为有效字符串;也可借助WinDbg等工具跟踪C++端函数调用,确认propValue指针是否被正确写入。
内容的提问来源于stack exchange,提问作者Ilian Felinto

