【问题标题】:Passing char*and struct in C# to c++ DLL, all variables pass successfully except one将C#中的char*和struct传递给c++ DLL,所有变量都成功传递,除了一个
【发布时间】:2011-02-17 02:33:26
【问题描述】:

我已经为一个带有 lib 文件的 C dll 编写了一个 c++ 包装器 dll,现在一切正常,我在 c++ 包装器类中编写的所有函数都按预期工作。

在 C++ dll 中

__declspec(dllexport) long ReadRawDataByTime(char * tagname, long serverhandle, IHU_TIMESTAMP * StartTime, IHU_TIMESTAMP * EndTime, int * number_of_samples, IHU_DATA_SAMPLE **data_values){
        return ihuReadRawDataByTime(serverhandle, tagname, StartTime, EndTime, number_of_samples, data_values);
}

这是我的定义以及我如何在 C# 中调用它

        [DllImport("IHUAPIWrapper.dll")]
        public static extern long ReadRawDataByTime(String tagname, long serverhandle, IHU_TIMESTAMP* StartTime, IHU_TIMESTAMP* EndTime, int* number_of_samples, IHU_DATA_SAMPLE** data_values);
...
                long lRet = ReadRawDataByTime
                (
                    tagname,//the handle returned from the connect
                    serverhandle,           //the single tagname to retrieve 
                    &temp_start_time,   //start time for query
                    &temp_end_time,     //end time for query
                    &number_of_samples, //will be set by API
                    &pSamples           //will be allocated and populated in the user API
                );

其中标记名被定义为一个字符串,其余的是它们相应的结构。

现在,如果我在 C++ dll 中设置调试器,我可以看到所有值都正确传入,serverhandle 符合预期,标记名包含正确的字符串,endTime 具有正确的时间,样本数和 pSamples 符合预期为空白但是当我肯定传入一个有效的结构时,startTime 是“未定义的”。

如果我在调试器中对变量进行虚拟化,它甚至会返回预期的数据,它只是显示它没有正确传递变量。

我做了一些实验并交换了变量的顺序,因此首先传递了服务器句柄,然后传递了标记名,如果这样做,所有变量都是正确的,除了标记名现在是“未定义”

我传递破坏下一个变量的字符串的方式有问题吗?我是否需要指定一些特殊的调用约定,而目前其他一切都可以正常工作只是侥幸?

任何帮助将不胜感激。 :)

编辑:这是调试器的屏幕截图,以显示我对传递的所有变量的意思,除了一个。

【问题讨论】:

    标签: c# c++ dll interop dllimport


    【解决方案1】:

    这里有很多危险信号。它不起作用,因为您没有指定 CallingConvention.Cdecl。 long 参数在 C# 端是 int。这将解决您最初的问题,现在一切都应该正确传递。当指针导致 AccessViolation 时开始另一个问题。

    【讨论】:

    • 谢谢,我具体在哪里指定?
    • 另外很奇怪的是它们是整数,因为在结构中它们被指定为 long public struct IHU_TIMESTAMP { public long Seconds; // 自 1970 年 1 月 1 日以来的秒数 public long Subseconds; // 纳秒,一秒的小数部分 // 一秒内 10 亿纳秒 // 除以 100 万得到毫秒。 }
    • [DllImport("IHUAPIWrapper.dll", CallingConvention = CallingConvention.Cdecl)]
    • “自 1970 年 1 月 1 日以来的秒数”值应存储在 time_t 中。取决于宏值,它是 32 位还是 64 位。但只要这适用于 MSVC 编译器,那么 long 就是 32 位。如果这个声明是为 GCC 编译器编写的,那么 long 是 64 位的。可爱的混乱,不是吗。
    • 补充说,重新编译但我仍然得到'StartTime'作为未定义的值,还有更多线索吗?我无法重新编译 API,所以我坚持将其保留很长时间,但我知道他们使用的是 32 位。
    【解决方案2】:

    您是否将 DLL 编译为 unicode?​​p>

    无论如何,我认为您需要在传递字符串之前将其转换为字节数组

    【讨论】:

    • 我不确定,在哪里可以查看?
    【解决方案3】:

    发现问题,问题是在 Visual Studio 中的 C++ 中,long 长度为 4 个字节,在 C# 中它们为 8 个字节长,字符也是 unicode 和 2 个字节长,而在 C++ 中为 1 个字节,这意味着我的结构大小在这两个是为什么参数没有正确传递,也是为什么我因为指针增加太多而导致访问冲突。

    为大家的帮助干杯,现在一切正常

    如果有人感兴趣,我最后也是这样做的

    [DllImport("IHUAPIWrapper.dll",CallingConvention = CallingConvention.Cdecl)]
    public static extern int ReadRawDataByTime(string tagname, int serverhandle, ref IHU_TIMESTAMP StartTime, ref IHU_TIMESTAMP EndTime, out IntPtr number_of_samples, out IntPtr data_values);
    
    IntPtr thisPtr = new IntPtr(pSamples_ptr.ToInt32() + (sizeof(IHU_DATA_SAMPLE) * loop));
    IHU_DATA_SAMPLE data_sample = (IHU_DATA_SAMPLE)Marshal.PtrToStructure(thisPtr, typeof(IHU_DATA_SAMPLE));
    

    【讨论】:

    • 另一件事。我可以直接在 C# 中直接引用非托管 DLL。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多