c# - 如何在 c# 中调用此 c 函数(解码返回结构)?

标签 c# interop pinvoke unmarshalling

我想使用 c# interop 从用 c 编写的 dll 调用函数。我有头文件。 看看这个:

enum CTMBeginTransactionError {
    CTM_BEGIN_TRX_SUCCESS = 0,
    CTM_BEGIN_TRX_ERROR_ALREADY_IN_PROGRESS,
    CTM_BEGIN_TRX_ERROR_NOT_CONNECTED
};

#pragma pack(push)
#pragma pack(1)
struct CTMBeginTransactionResult {
    char *                        szTransactionID;
    enum CTMBeginTransactionError error;
};

struct CTMBeginTransactionResult ctm_begin_customer_transaction(const char * szTransactionID);

如何从 C# 调用 ctm_begin_customer_transaction。 const char * 很好地映射到字符串,但尽管进行了各种尝试(查看 stackoverflow 和其他站点),但我未能编码返回结构。如果我定义返回 IntPtr 的函数,它就可以正常工作...

编辑 我将返回类型更改为 IntPtr 并使用: CTMBeginTransactionResult 结构 = (CTMBeginTransactionResult)Marshal.PtrToStructure(ptr, typeof(CTMBeginTransactionResult)); 但它抛出 AccessViolationException

我也试过:

IntPtr ptr = Transactions.ctm_begin_customer_transaction("");
int size = 50;
byte[] byteArray = new byte[size];
Marshal.Copy(ptr, byteArray, 0, size);
string stringData = Encoding.ASCII.GetString(byteArray);

stringData == "70e3589b-2de0-4d1e-978d-55e22225be95\0\"\0\0\a\0\0\b\b?"在这一点上。"70e3589b-2de0-4d1e-978d- 55e22225be95"是结构中的 szTransactionID。枚举在哪里?是下一个字节吗?

最佳答案

这个结构中隐藏着一个内存管理问题。谁拥有 C 字符串指针? pinvoke 编码器将始终假设调用者拥有它,因此它将尝试释放该字符串。并将指针传递给 CoTaskMemFree(),与 Marshal.FreeCoTaskMem() 调用的功能相同。这些函数使用 COM 内存分配器,即 Windows 中的通用互操作内存管理器。

这很少有好结果,C 代码通常不会使用该分配器,除非程序员在设计代码时考虑到了互操作性。在这种情况下,他永远不会使用结构作为返回值,当调用者提供缓冲区时,互操作总是不会那么顺利地工作。

所以你不能让编码器执行它的正常职责。您必须将返回值类型声明为 IntPtr,这样它就不会尝试释放字符串。并且您必须使用 Marshal.PtrToStructure() 自行编码它。

然而,这仍然没有回答这个问题,谁拥有字符串?您无法释放字符串缓冲区,您无权访问 C 代码中使用的分配器。您唯一的希望是该字符串实际上并未分配到堆上。这是可能的,C 程序可能正在使用字符串文字。你需要验证这个猜测。在测试程序中调用该函数十亿次。如果那不会使程序爆炸,那么您就很好。如果不是,那么只有 C++/CLI 可以解决您的问题。考虑到字符串的性质,“交易 ID”应该变化很大,我会说你确实有问题。

关于c# - 如何在 c# 中调用此 c 函数(解码返回结构)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15293593/

相关文章:

.net - Delphi : How to call the .Net 4.0 版本的 StrongNameSignatureVerificationEx

c# - Windows Phone 8(仅限 C++)- 可以访问设备制造商吗?

c# - 从 C# 访问 C++ DLL 库

c# - 我没有在 DLLImport 中使用的引用中看到 DLL

c# - 将用户从 Controller 重定向到另一个 View MVC

c# - 解密 web.config 中的 connectionString?

c# - 是否允许在另一个泛型方法中调用泛型方法?

c# - Mac 上 Mono 中的 DllImport 出现 DllNotFoundException : wrong architecture

c# - 从生成的 C 代码创建 dll 库

c# - 数据库中的 View 状态?方便吗?