Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/270.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#调用Delphi的dll文件_C#_Delphi_Dllimport - Fatal编程技术网

C#调用Delphi的dll文件

C#调用Delphi的dll文件,c#,delphi,dllimport,C#,Delphi,Dllimport,最近,我需要在我的C#项目中使用Delphi DLL,我已经搜索了一些答案,但是其他的都失败了。DLL的名称是modelDLL.DLL,它需要另一个DLL文件(我已经将这两个文件放在调试文件夹中) 德尔菲代码 type TCharStr=array[0..599] of char; 使用Delphi调用DLL工作正常(代码如下),但是,我不知道DLL文件中的具体注释。Delphi的相关代码如下: procedure TMainDLLForm.PedBitBtnClick(Sender: TOb

最近,我需要在我的C#项目中使用Delphi DLL,我已经搜索了一些答案,但是其他的都失败了。DLL的名称是modelDLL.DLL,它需要另一个DLL文件(我已经将这两个文件放在调试文件夹中)

德尔菲代码

type
TCharStr=array[0..599] of char;
使用Delphi调用DLL工作正常(代码如下),但是,我不知道DLL文件中的具体注释。Delphi的相关代码如下:

procedure TMainDLLForm.PedBitBtnClick(Sender: TObject);
var
  fileName:TCharStr;
begin

        OpenDataFileDlg.InitialDir:= GetCurrentDir;
        OpenDataFileDlg.Title:='load model file';
        OpenDataFileDlg.Filter := 'model_A[*.mdl]|*.mdl|model_T[*.mdr]|*.mdr';
        if OpenDataFileDlg.Execute then
        begin
           StrPCopy(FileName,OpenDataFileDlg.FileName);
           tmpD:=NIRSAModelForPred(graphyData,dataLength,FileName,targetName);
        end;  
       if compareText(fileExt,'.MDR')=0 then
       begin
         memo1.Lines.Add('model_T: '+ExtractFileName(FileName));
         memo1.Lines.Add(Format('Result: %10s:%0.0f',[targetName,tmpD]));
       end;
       memo1.Lines.Add('--------------');
       memo1.Lines.Add(trim(NIRSAPretreatInfor(FileName)));// calling this function
       memo1.Lines.Add('--------------');
       memo1.Lines.Add(trim(NIRSAModelInfor(FileName)));
end;
我的C#代码如下,这暗示“试图读取或写入受保护的内存。这通常表示其他内存已损坏。”错误

那么,有谁能给我一些建议吗?您的答复将不胜感激

附言: Delphi版本:7.0

导入DLL代码:

    implementation
       function  
NIRSAModelForPred(Data:TGraphyData;dataLength:integer;ModelFileName:TCharStr;var targetName:TCharStr):double;stdcall;external 'modelDLL.dll';
       function  NIRSAModelInfor(ModelFileName:TCharStr):TCharStr;stdCall;external 'modelDLL.dll';
       function  NIRSAPretreatInfor(ModelFileName:TCharStr):TCharStr;stdCall;external 'modelDLL.dll';
现在我已经将
CharSet=CharSet.Auto
更改为
CharSet=CharSet.Ansi
,错误消息再次出现

The call to the PInvoke "NIRSAPre!NIRSAPre.Form1::NIRSAPretreatInfor" function causes the stack to be asymmetric.

最重要的问题(存在多个问题)是Delphi代码使用固定长度的字符数组,这不容易封送。C#marshaler没有与这些内容完全匹配的类型。问题在于,如果Delphi固定长度字符数组是数组的全长,则该数组不能以null结尾

另一个问题是字符集。Delphi 7
char
是一种8位ANSI类型。您可以封送为
CharSet.Auto
,它在Windows 9x以外的平台上是16位UTF-16。我相信你不会在Windows9x上运行

最后一个问题与用作返回值的大型类型的ABI有关。Delphi ABI实现了一个额外的(隐藏的)
var
参数。所以

function NIRSAPretreatInfor(ModelFileName: TCharStr): TCharStr; 
  stdCall; external 'modelDLL.dll';
实际实施如下:

procedure NIRSAPretreatInfor(ModelFileName: TCharStr; var ReturnValue: TCharStr); 
  stdCall; external 'modelDLL.dll';
为了正确封送,您需要手动处理字符串。从一些助手方法开始:

public const int DelphiTCharStrLength = 600;

public static byte[] NewDelphiTCharStr()
{
    return new byte[DelphiTCharStrLength];
}

public static byte[] ToDelphiTCharStr(string value)
{
    byte[] result = NewDelphiTCharStr();
    byte[] bytes = Encoding.Default.GetBytes(value + '\0');
    Buffer.BlockCopy(bytes, 0, result, 0, Math.Min(bytes.Length, DelphiTCharStrLength));
    return result;
}

public static string FromDelphiTCharStr(byte[] value)
{
    int len = Array.IndexOf(value, (byte)0);
    if (len == -1)
        len = DelphiTCharStrLength;
    return Encoding.Default.GetString(value, 0, len);
}
这些处理的是固定长度的Delphi字符数组不需要以null结尾的事实

这一点到位后,p/invoke声明如下:

[DllImport(@"modelDLL.dll", CallingConvention = CallingConvention.StdCall)]
public extern static void NIRSAPretreatInfor(byte[] ModelFileName, byte[] ReturnValue);
可以这样称呼:

byte[] outputBytes = NewDelphiTCharStr();
NIRSAPretreatInfor(ToDelphiTCharStr("foo"), outputBytes);
string output = FromDelphiTCharStr(outputBytes);

我看不出你在哪里导出德尔菲法。查看此链接,它会让您了解您可能想要尝试的内容。你必须在DLL中显示函数描述(特别是调用约定)并指定Delphi版本(是Unicode吗?)谢谢你的回复,我现在不能告诉你DLL中的函数描述(我稍后会发布),Delphi的版本是7。但是DLL的提供者给了我一个简单的函数描述:(使用C):Char nirsapretuinform(Char*ModelFileName);输入参数:Char ModelFileName[600];/模型文件名,扩展名*.mdl 或*.mdr*/返回值:array char str[600],描述内容;字符集不是主要问题。我会写一个答案,希望能解释一下。这确实是一个很好的解决方案,可以解决DLL设计不足的问题。谢谢你的回复。目前,程序可以运行,但是接下来的数据是空的,这意味着
outputBytes
的每个大小都是(byte)0,我不知道是什么造成了这种情况。我刚刚用文件路径(
fileName
)替换了
foo
。我的答案中的代码是有效的。我已经测试过了。您可以通过使用单个函数创建一个测试DLL来测试它。像我一样,向自己证明数据在两个方向上都是正确传递的。很抱歉打扰您。我没有使用另一个DLL对其进行测试,但是,我发现了一个奇怪的现象,原始输入参数
byte[]ModelFileName
包含了一些正确返回的数据(不是全部),我不知道是什么原因造成了这种情况?我认为编码可能会导致这样的结果?只有第一行内容返回,下一行内容应该是中文描述(无法理解的文本没有显示)。另一方面,如果delphi dll接受数组(如double[]),我是否可以使用C#double[,]作为变量来调用此函数(其他类型相同,如int对应的整数)?谢谢你的时间和工作!
byte[] outputBytes = NewDelphiTCharStr();
NIRSAPretreatInfor(ToDelphiTCharStr("foo"), outputBytes);
string output = FromDelphiTCharStr(outputBytes);