首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对C DLL的C#调用只有部分功能

对C DLL的C#调用只有部分功能
EN

Stack Overflow用户
提问于 2016-02-11 14:12:14
回答 3查看 292关注 0票数 2

我正在从C++/CLR背景中学习C#,方法是在C#中重写一个示例C++/CLR项目。

该项目是一个简单的GUI (使用Visual / Windows窗体),它执行对用C编写的DLL的调用(实际上,在NI LabWindows/CVI中,但这只是带有自定义库的ANSI C)。DLL不是由我编写的,我不能对它执行任何更改,因为它也在其他地方使用。

DLL包含使RFID设备执行某些功能(如读取/写入RFID标签等)的功能。在每个函数中,总是调用执行日志文件写入的另一个函数。如果日志文件不存在,则使用某个标头创建日志文件,然后追加数据。

问题是: C++/CLR项目运行良好。但是,在C# 1中,功能可以工作( RFID标签被正确地写/读等等)。但是没有关于日志文件的任何活动!

DLL导出的声明如下(当然还有更多的声明):

代码语言:javascript
复制
int __declspec(dllexport) __stdcall Magnetfeld_einschalten(char path_Logfile_RFID[300]);

int save_Logdatei(char path_Logdatei[], char Funktion[], char Mitteilung[]);   

save_Logdatei函数是在执行Magnetfeld_einschalten时调用的,如下所示:

代码语言:javascript
复制
save_Logdatei(path_Logfile_RFID, "Magnetfeld_einschalten", "OK");

在C++/CLR项目中,我声明了如下函数:

代码语言:javascript
复制
#ifdef __cplusplus
extern "C" {
#endif
int __declspec(dllexport) __stdcall Magnetfeld_einschalten(char path_Logfile_RFID[300]);
#ifdef __cplusplus
}
#endif

那么,对该函数的简单调用就可以工作了。

C#项目中,声明如下:

代码语言:javascript
复制
[DllImport("MyDLL.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "Magnetfeld_einschalten", CharSet = CharSet.Ansi, ExactSpelling = false)]

private static extern int Magnetfeld_einschalten(string path_Logfile_RFID);

而且,正如我所说的,虽然主要功能正在工作(在本例中,打开了RFID设备的磁场),但日志记录从未完成(因此,对save_Logdatei的内部DLL调用没有正确执行)。

表单构造函数中的相关代码如下:

代码语言:javascript
复制
pathapp = Application.StartupPath;
pathlog = string.Format("{0}\\{1:yyyyMMdd}_RFID_Logdatei.dat", pathapp, DateTime.Now);
    //The naming scheme for the log file.
    //Normally, it's autogenerated when a `save_Logdatei' call is made.

Magnetfeld_einschalten(pathlog);

我遗漏了什么?我已经尝试过在DLL方法声明中使用unsafe --因为save_Logdatei中有一个File指针--但是它并没有产生任何区别。

===================================EDIT==================================

根据David的建议,我试图以一种容易测试的方式重现这个问题。为此,我创建了一个非常简单的动态链接库("test.dll"),我已经从定制的CVI库中完全剥离了它,所以即使没有CVI,它也应该是可复制的。我把它上传到这里了。无论如何,DLL的代码是:

代码语言:javascript
复制
#include <stdio.h>

int __declspec(dllexport) __stdcall Magnetfeld_einschalten(char path_Logfile_RFID[300]);
int save_Logdatei(char path_Logdatei[], char Funktion[], char Mitteilung[]);  

int __declspec(dllexport) __stdcall Magnetfeld_einschalten(char path_Logfile_RFID[300])
{
    save_Logdatei(path_Logfile_RFID, "Opening Magnet Field", "Success");
    return 0;
}

int save_Logdatei(char path_Logdatei[], char Funktion[], char Mitteilung[])
{
    FILE    *fp;                                /* File-Pointer */
    char    line[700];                          /* Zeilenbuffer */
    char    path[700];

    sprintf(path,"%s\\20160212_RFID_Logdatei.dat",path_Logdatei);

    fp = fopen (path, "a");

    sprintf(line, "Just testing");
    sprintf(line,"%s    %s",line, Funktion); 
    sprintf(line,"%s    %s",line, Mitteilung);

    fprintf(fp,"%s\n",line);

    fclose(fp);
    return 0;
}

C#代码也被简化了,我添加到标准表单项目中的唯一东西是Button 1(生成的按钮点击可以看到)。守则是:

代码语言:javascript
复制
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace TestDLLCallCSharp
{
    public partial class Form1 : Form
    {
        public int ret;
        public string pathapp;
        public string pathlog;

        [DllImport("test", CallingConvention = CallingConvention.StdCall, EntryPoint = "Magnetfeld_einschalten", CharSet = CharSet.Ansi, ExactSpelling = false)]
        private static extern int Magnetfeld_einschalten(string path_Logfile_RFID);

        public Form1()
        {
            pathapp = @"C:\ProgramData\test";
            pathlog = string.Format("{0}\\20160212_RFID_Logdatei.dat", pathapp);

            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ret = Magnetfeld_einschalten(pathlog);
        }
    }
}

可以看到,我避免了对日志文件使用自动命名方案(通常我使用日期),在dll和C#代码中,日志文件都是"20160212_RFID_Logdatei.dat“。我还避免使用app路径作为放置日志文件的目录,而是选择了一个在ProgramData中创建的名为test的文件夹。

同样,根本没有创建任何文件。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-02-12 11:09:53

这看起来像是调用代码中的一个简单的错误。而不是:

代码语言:javascript
复制
ret = Magnetfeld_einschalten(pathlog);

你的意思是:

代码语言:javascript
复制
ret = Magnetfeld_einschalten(pathapp);

在C#代码中,这两个字符串具有以下值:

代码语言:javascript
复制
pathapp == "C:\ProgramData\\test"
pathlog == "C:\ProgramData\\test\\20160212_RFID_Logdatei.dat"

当您将pathlog传递给非托管代码时,它将执行以下操作:

代码语言:javascript
复制
sprintf(path,"%s\\20160212_RFID_Logdatei.dat",path_Logdatei);

path设置为

代码语言:javascript
复制
path == "C:\\ProgramData\\test\\20160212_RFID_Logdatei.dat\\20160212_RFID_Logdatei.dat"

换句话说,您要将文件名追加到路径两次而不是一次。

票数 3
EN

Stack Overflow用户

发布于 2016-02-11 14:54:17

字符串采用Unicode格式,将其转换为byte[]

代码语言:javascript
复制
Encoding ec = Encoding.GetEncoding(System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ANSICodePage);
byte[] bpathlog = ec.GetBytes(pathlog);

并将参数类型更改为byte[]

代码语言:javascript
复制
[DllImport("MyDLL.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "Magnetfeld_einschalten", CharSet = CharSet.Ansi, ExactSpelling = false)]    
private static extern int Magnetfeld_einschalten(byte[] path_Logfile_RFID);

对我来说很管用

JSh

票数 0
EN

Stack Overflow用户

发布于 2016-02-12 04:24:03

在C#中对P/Invoke进行了广泛的概述,并在平台调用教程- MSDN库中作了介绍。

问题在于您需要传递一个固定的char数组,而不是标准的char*。这是在字符串的默认编组中讨论的。

要点是,您需要从您的char[300]字符串构造一个,并传递该字符串而不是字符串.

对于这种情况,指定了两种方法:

  • 初始化为指定长度的而不是字符串,并使用您的数据(我省略了非必要的参数。): DllImport("MyDLL.dll",ExactSpelling = true)私有静态extern Magnetfeld_einschalten( MarshalAs(UnmanagedType.LPStr) StringBuilder path_Logfile_RFID);<...> StringBuilder sb =新StringBuilder(路径日志,300); 在这种情况下,缓冲区是可修改的。
  • 具有所需的格式并手动将字符串转换为: StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi)结构Char300 { MarshalAs(UnmanagedType.ByValTStr,SizeConst=300)字符串s;} DllImport("MyDLL.dll")私有静态表达式Magnetfeld_einschalten(Char300 path_Logfile_RFID);<...> int结果=Magnetfeld_einschalten(新Char300{s=pathlog}); 您可以通过定义显式或隐式强制转换例程来使这变得更加简单。

根据文档的说法,UnmanagedType.ByValTStr只在结构中有效,因此似乎不可能兼得这两个世界的优点。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35341625

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档