【问题标题】:Call C DLL function from C# - convert char parameter to string从 C# 调用 C DLL 函数 - 将 char 参数转换为字符串
【发布时间】:2010-11-16 16:36:32
【问题描述】:

我正在尝试从我的 C# 应用程序中调用用 C 编写的 DLL 中的方法。以下是我实现调用的方式:

--> C方法签名:(来自第三方公司)

Int16 SSEXPORT SS_Initialize(Uint16 ServerIds[], Uint16 ServerQty, const char PTR *Binding, const char PTR *LogPath, Uint16 LogDays, Int16 LogLevel,
Uint16 MaxThreads, Uint16 ThreadTTL, Int16 (CALLBACK *ProcessMessage)(Uint16, const char PTR *, Uint32, char PTR **, Uint32 PTR *, Int16 PTR *));

--> C 类型定义:

#ifndef _CSISERVERTYPES_ #define _CSISERVERTYPES_ #如果定义(OS_NT) #define CALLBACK __stdcall #define SSEXPORT __stdcall #define PTR typedef char Int8; typedef 无符号字符 Uint8; typedef 短 Int16; typedef 无符号短 Uint16; typedef long Int32; typedef unsigned long Uint32; typedef unsigned char 字节; typedef 无符号短字; typedef unsigned long Dword; typedef 短布尔值; #万一 typedef Int16 (CALLBACK *PM_Function) (Uint16,const char PTR *,Uint32,char PTR **,Uint32 PTR *,Int16 PTR *); #define SS_OK 0 #define SS_NOT_INIT -1 #define SS_PROC_ERR -2 #define SS_ERR_TCP_SRV -3 #define SS_ERR_OUT_MEM -4 #ifndef 空 #define NULL 0 #万一 #万一

--> C# DLL 方法声明:

[DllImport("CSITCPServer.dll", SetLastError = true)]
    static extern Int16 SS_Initialize(
        UInt16[] ServerIds,
        UInt16 ServerQty,
        ref string Binding,
        ref string LogPath,
        UInt16 LogDays,
        Int16 LogLevel,
        UInt16 MaxThreads,
        UInt16 ThreadTTL,
        ProcessMessageCallback callback);

方法调用:

public static void Call_SS_Initialize()
    {   
        Int16 ret;
        UInt16[] serverIds = new UInt16[] { 2020, 2021 };
        string binding = "";
        string logPath = "";

        try
        {
            ret = SS_Initialize(
                serverIds,
                Convert.ToUInt16(serverIds.ToList().Count),
                ref binding,
                ref logPath,
                10,
                0,
                256,
                300,
                ProcessMessage);

            Console.WriteLine("Call_SS_Initialize() -> Result of SS_Initialize:  {0}", ret.ToString());
        }
        catch (Exception ex)
        {
            Int32 err = Marshal.GetLastWin32Error();
            throw new Win32Exception(err);
            //throw;
        }
    }

然后我得到 Win32Exception: 1008 - 尝试引用不存在的令牌

我知道问题一定出在非托管 (C) 和托管 (C#) 代码之间的 CHAR 到 STRING 转换中。如果我修改 BindingLogPath 参数以键入 SByte,它不会给出任何错误。但由于该方法需要一个文本(字符串),我不知道如何将文本传递给该方法,因为它需要一个 SByte 变量...

我知道我可能必须使用 MarshalAs 之类的东西,但我尝试了几个选项,但都没有成功。

谁能告诉我我做错了什么??

非常感谢!!


这里是回调定义:

 public delegate Int16 ProcessMessageCallback(
        UInt16 ServerId,
        [MarshalAs(UnmanagedType.LPStr)] ref string RequestMsg,
        UInt32 RequestSize,
        [MarshalAs(UnmanagedType.LPStr)] ref string ResponseMsg,
        ref UInt32 ResponseSize,
        ref Int16 AppErrCode);

问题是 C DLL 方法需要一个“REF”参数。对 SS_Initialize 的调用将执行附加到 ProcessMessage 回调函数。在这个函数中,我需要能够从 SS_Initialize 获取修改后的参数(参考)...

您能否建议您认为代码的结构应该如何?

谢谢!!

【问题讨论】:

    标签: c# c string dll char


    【解决方案1】:

    对于编组字符串,您不传递ref string,只需传递string。此外,您应该用 [MarshalAs( UnmanagedType.LPStr)] 装饰每个字符串,以表明您正在传递包含 ascii 字符的字符串并且它以 null 结尾。
    编辑:您能否也给出此回调过程的定义,因为您可能会犯类似的错误。

    【讨论】:

      【解决方案2】:

      Binding 和 LogPath 不需要使用 ref;它们是 const char* 并且不会改变。

      回调中的 ResponseMessage 将返回一个字符串数组,(char **) 而不仅仅是单个字符串。响应大小可能会指示数组的深度。改用 [MarshalAs(UnamangedType.LPArray, ArraySubType=UnmanagedType.LPStr)] string[]。

      【讨论】:

        【解决方案3】:

        感谢 RavadreR Ubben,你们的帮助相得益彰!

        最后,一切都是为了正确控制参数中的 REF 子句和使用 MarshalAs 标签。 C部分中的“const char *”参数实际上不需要REF标签。我还使用 [MarshalAs(UnmanagedType.LPStr)] 作为字符串参数。就是这样!

        ps:Stackoverflow.com 太棒了!通过搜索,我已经在这里找到了很多其他问题的答案。这是我的第一篇文章,我对这篇文章的快速回复感到惊讶。祝贺所有员工团队和成员! ;)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-07-28
          • 2018-09-02
          • 1970-01-01
          • 1970-01-01
          • 2012-01-16
          • 2018-03-27
          • 2013-05-13
          相关资源
          最近更新 更多