如何在c#中调用此c函数(解组返回结构)? [英] How do I call this c function in c# (unmarshalling return struct)?

查看:144
本文介绍了如何在c#中调用此c函数(解组返回结构)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆