如何在c#中调用此c函数(解组返回结构)? [英] How do I call this c function in c# (unmarshalling return struct)?
问题描述
我想使用c#互操作从用c编写的dll调用函数.我有头文件. 看看这个:
I want to use c# interop to call a function from a dll written in c. I have the header files. Take a look at this:
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的函数,它就可以正常工作...
How do I call ctm_begin_customer_transaction from c#. The const char * mapps well to string, but despite various attempts (looking at stackoverflow and other sites), I fail to marshal the return structure. If I define the function to return IntPtr it works ok...
编辑 我将返回类型更改为IntPtr并使用: CTMBeginTransactionResult结构=(CTMBeginTransactionResult)Marshal.PtrToStructure(ptr,typeof(CTMBeginTransactionResult)); 但是会抛出AccessViolationException
Edit I changed the return type to IntPtr and use: CTMBeginTransactionResult structure = (CTMBeginTransactionResult)Marshal.PtrToStructure(ptr, typeof(CTMBeginTransactionResult)); but it throws 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.枚举在哪里?它是下一个字节吗?
stringData == "70e3589b-2de0-4d1e-978d-55e22225be95\0\"\0\0\a\0\0\b\b?" at this point. The "70e3589b-2de0-4d1e-978d-55e22225be95" is the szTransactionID from the struct. Where is the Enum? Is it the next byte?
推荐答案
我讨厌回答我自己的问题,但是我找到了封送最终结构的解决方案.该结构的长度为8个字节(char *为4个字节,enum为4个字节).编组字符串不能自动工作,但以下工作有效:
I hate to answer my own question, but I found the solution to marshal the resulting struct. The struct is 8 bytes long (4 bytes for the char * and 4 bytes for enum). Marshalling the string does not work automatically, but the following works:
// Native (unmanaged)
public enum CTMBeginTransactionError
{
CTM_BEGIN_TRX_SUCCESS = 0,
CTM_BEGIN_TRX_ERROR_ALREADY_IN_PROGRESS,
CTM_BEGIN_TRX_ERROR_NOT_CONNECTED
};
// Native (unmanaged)
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
internal struct CTMBeginTransactionResult
{
public IntPtr szTransactionID;
public CTMBeginTransactionError error;
};
// Managed wrapper around native struct
public class BeginTransactionResult
{
public string TransactionID;
public CTMBeginTransactionError Error;
internal BeginTransactionResult(CTMBeginTransactionResult nativeStruct)
{
// Manually marshal the string
if (nativeStruct.szTransactionID == IntPtr.Zero) this.TransactionID = "";
else this.TransactionID = Marshal.PtrToStringAnsi(nativeStruct.szTransactionID);
this.Error = nativeStruct.error;
}
}
[DllImport("libctmclient-0.dll")]
internal static extern CTMBeginTransactionResult ctm_begin_customer_transaction(string ptr);
public static BeginTransactionResult BeginCustomerTransaction(string transactionId)
{
CTMBeginTransactionResult nativeResult = Transactions.ctm_begin_customer_transaction(transactionId);
return new BeginTransactionResult(nativeResult);
}
该代码有效,但是如果调用非托管代码导致内存泄漏,我仍然需要调查.
The code works, but I still need to investigate, if calling the unmanaged code results in memory leaks.
这篇关于如何在c#中调用此c函数(解组返回结构)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!