将 C# 中的 char* 和 struct 传递给 c++ DLL,除了一个变量外,所有变量都成功传递

发布于 2024-10-17 22:38:33 字数 1821 浏览 1 评论 0原文

我已经为带有 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 是当我明确传递一个有效的结构时,会出现“未定义”。

如果我在调试器中虚拟变量,它甚至会返回预期的数据,它只是看起来没有正确传递变量。

我做了一些实验并交换了变量的顺序,因此首先传递了 serverhandle,然后传递了 tagname,如果我这样做,所有变量都是正确的,除了 tagname 现在为“未定义”,

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

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

编辑:这是调试器的屏幕截图,显示了我对传递的所有变量(除一个之外)的含义。 http://img602.imageshack.us/img602/5281/47739520.jpg

I have written a c++ wrapper dll for a C dll with lib file I have, now everything is partially working, all the functions I have written in the c++ wrapper class work as expected bar one.

Here it is in the 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);
}

and here is my definition and how I call it in 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
                );

where tagname is defined as a string and the rest are their appropriate structs.

Now if I set the debugger in the C++ dll I can see all the values being passed in correctly, serverhandle is as expected, tagname holds the correct string, endTime has the correct time, number of samples and pSamples are blank as expected however startTime is 'undefined' when I am definitely passing in a valid struct.

If I dummy up the variables in the debugger it even returns expected data it just appears it is not passing the variables correctly.

I did some experimentation and swapped the order of the variables so serverhandle was passed first and tagname was passed second, if I do this all the variables are correct except tagname is now 'undefined'

is there something wrong with how I am passing the string that is corrupting the next variable? do I need to specifiy some special calling convention and currently it is just a fluke that everything else works?

Any help would be much appreciated. :)

edit: here is a screenshot of the debugger to show what I mean about all variables being passed except one.
http://img602.imageshack.us/img602/5281/47739520.jpg

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

人疚 2024-10-24 22:38:33

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

Lots of red flags here. It doesn't work because you didn't specify CallingConvention.Cdecl. And the long arguments are int on the C# side. That will take care of your original problem, everything should be passed correctly now. Start another question when the pointers cause an AccessViolation.

小帐篷 2024-10-24 22:38:33

您是否将 DLL 编译为 unicode?

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

Are you compiling your DLL as unicode?

Anyway I think you need to convert your string to a byte array before passing it

笑梦风尘 2024-10-24 22:38:33

发现问题,问题是在 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));

Found the problem, issue is in C++ in visual studio longs are 4 bytes long, in C# they are 8 bytes long, also chars are unicode and 2 bytes long, and 1 byte in C++ this meant my struct sizes were different between the two which is why the parameters didn't pass correctly, also why I got an access violation as the pointers incremented too far.

Cheers for all the help everyone, all works perfectly now

here is how I finally did it as well if anyone is interested

[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));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文