我需要在我的C#应用程序中使用Delphi 7中的DLL(硬件ID提取器)。
此DLL导出的函数是:
导出的功能:
// CPU
function GetCPUSpeed: Double;
function CPUFamily: ShortString; { Get cpu identifier from the windows registry }
function GetCpuTheoreticSpeed: Integer; { Get cpu speed (in MHz) }
function IsCPUIDAvailable: Boolean; Register;
function GetCPUID (CpuCore: byte): ShortString;
Function GetCPUVendor: ShortString;
// RAM
function MemoryStatus (MemType: Integer): cardinal; { in Bytes }
function MemoryStatus_MB (MemType: Integer): ShortString; { in MB }
// HDD
function GetPartitionID (Partition : PChar): ShortString; { Get the ID of the specified patition. Example of parameter: 'C:' }
function GetIDESerialNumber(DriveNumber: Byte ): PChar; { DriveNr is from 0 to 4 }
我知道(显然)Delphi中的字符串不是以null结尾并且是字节(ASCII)。但我不知道如何将这些Delphi字符串映射到C#。
感谢。
答案 0 :(得分:6)
以下是如何在C#中声明GetCPUSpeed函数的示例:
class Program
{
[DllImport("the_name_of_the_delphi_library.dll")]
public static extern double GetCPUSpeed();
static void Main(string[] args)
{
double cpuSpeed = GetCPUSpeed();
Console.WriteLine("CPU speed: {0}", cpuSpeed);
}
}
您可以尝试其他声明:
[DllImport("the_name_of_the_delphi_library.dll")]
public static extern string CPUFamily();
[DllImport("the_name_of_the_delphi_library.dll")]
public static extern int GetCpuTheoreticSpeed();
[DllImport("the_name_of_the_delphi_library.dll")]
public static extern bool IsCPUIDAvailable();
[DllImport("the_name_of_the_delphi_library.dll")]
public static extern string GetCPUID(byte cpuCore);
[DllImport("the_name_of_the_delphi_library.dll")]
public static extern string GetCPUVendor();
[DllImport("the_name_of_the_delphi_library.dll")]
public static extern uint MemoryStatus(int memType);
[DllImport("the_name_of_the_delphi_library.dll")]
public static extern string MemoryStatus_MB(int memType);
[DllImport("the_name_of_the_delphi_library.dll")]
public static extern string GetPartitionID(char partition);
[DllImport("the_name_of_the_delphi_library.dll")]
public static extern string GetIDESerialNumber(byte driveNumber);
答案 1 :(得分:6)
问题来自您设计导出功能的方式。 DLL(除其他外)是一种提供代码的机制,它可以从以不同编程语言编写的应用程序(或其他DLL)中使用。
看一下Windows API,有很多函数返回文本。不幸的是,这是以很多不同的方式完成的,Windows API没有真正的标准。但是,我很确定你不会找到一个以你的方式返回“字符串”(Pascal或C(空终止)字符串)的函数。原因很简单:这会使不同的模块使用不同的编程语言变得非常困难甚至不可能。你的DLL会为字符串分配内存,一旦调用者完成字符串,就需要释放内存。因此,两个模块都需要共享这片内存的管理器。 C#程序如何使用你的DLL,看到他们使用完全不同的内存管理器?
从DLL获取字符串值的习惯方法是使用预分配的缓冲区和参数中的缓冲区长度调用函数,让函数用字符串内容填充该缓冲区,并让函数结果表示成功或失败。例如,传递大小不足的缓冲区将是失败的一个原因。不同的Windows API函数以不同的方式处理这个问题,最简单的方法可能是用常量定义最大字符串长度,例如类似于MAX_PATH
。
要解决您的问题,您应该使用一个知道如何从C#调用的Windows API函数,并在缓冲区中返回一个字符串结果,作为示例。在此示例之后为导出的函数建模,并且应该很容易从C#程序中调用它们。
修改强>
我记得前段时间我曾见过类似的问题(How to import a function from a DLL made in Delphi?),现在看来我发现它也属于你了。
您之后写道,您没有该DLL的源代码,因此更改导出的函数是不可能的。你可以做的是在Delphi中创建一个包装DLL(或COM对象),调用原始HardwareIDExtractor.dll
并在其上提供一个理智的API。这样你就可以同时提供导出函数的AnsiChar和WideChar版本。
如果你想减少混乱(两个必要的DLL而不是一个),你也可以将原始的HardwareIDExtractor.dll
作为资源放入你的包装DLL中,如本博文中所述:Using DLLs stored as Resources in Delphi programs < / p>
答案 2 :(得分:2)
如果你有D7 dll的来源,你可以改变导出的功能来制作 ShortString函数返回PChar。您可以创建调用原始函数的新函数并进行类型转换 - 这是最简单的路径。如果您遵循此路径,则对Integer和Cardinal类型执行相同操作(分别将它们转换为LongInt和LongWord)。 下面的一些代码(我想像豪斯拉登先生这样的法师有一个更优雅的方法,但这有效:-))
var
SInput: ShortString;
POutput: PAnsiChar;
Tam: Integer;
pt: Pointer;
begin
SInput := 'Alphabet'; //ShortString
pt := @SInput[1]; // Points to the first char of the string;
Tam := (Length(SInput))+1; // Size the string
POutput := StrAlloc(tam); // Allocate;
CopyMemory(POutput,pt,tam); // Do the copy
POutput[tam-1] := #0; // Put the null to finish
MessageBox(0, POutput, 'Algo', MB_ICONWARNING or MB_OK);
StrDispose(POutput);
end;
这是有效的,因为内部ShortString是Char的数组[0..255]。我手边没有D2009来查看SizeOf(char)是否必须更改为SizeOf(AnsiChar)。 BUT 原理是一样的:分配PAnsiChar,将指针指向ShortString的第一个char,然后复制(在这种情况下,我已完成CopyMemory)到PAnsiChar。并将null放在其位置。
或者您可以使用mghie's方式创建包装并在那里进行转换。