2009-06-18 11 views
2

C#アプリケーションでDelphi 7で作成されたDLL(ハードウェアIDエクストラクタ)を使用する必要があります。C#のDelphi 7でコンパイルされたDLLを使用

この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でその文字列を知って終了し、バイト(ASCII)ですnullではありません。しかし、私はこれらのDelphiの文字列をC#にどのようにマッピングするかについての手がかりはありません。

ありがとうございました。

+1

あなたは間違っていますが、長い文字列*はDelphiでヌルターミネーションされているため、PCharに型キャストしてC文字列のように使用できます。 – mghie

+0

@mghie、いいえ、OPは間違っていません。あなたは長い文字列については正しいですが、コードサンプルは短い文字列を使用します。 –

+0

ジョー、そういうわけで、私は長い文字列を書いたのです。質問には、「Delphiの文字列(文字列)がヌルで終了していないことがわかりました」と述べています。 – mghie

答えて

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); 
6

問題はあなたが設計し道から来ているが、エクスポートされた関数。 DLLは、さまざまなプログラミング言語で書かれたアプリケーション(または他のDLL)から使用できるように、コードを提供するためのメカニズム(とりわけ)です。

Windows APIを見ると、テキストを返す関数がたくさんあります。残念ながら、これは多くの異なる方法で行われ、Windows APIには実際の標準はありません。しかし、あなたがしたやり方で "文字列"(パスカルかC(ヌルで終了する文字列)を返す単一の関数を見つけることはできません)。理由は簡単です:これは、モジュールごとに異なるプログラミング言語を使用することを非常に困難または不可能にします。 DLLは文字列にメモリを割り当て、呼び出し元が文字列で終了するとメモリを解放する必要があります。したがって、両方のモジュールは、このメモリスライスのマネージャを共有する必要があります。どのようにC#プログラムはDLLを使用して、まったく別のメモリマネージャを使用することができますか?

DLLから文字列値を取得する習慣的な方法は、あらかじめ割り当てられたバッファとパラメータのバッファ長で関数を呼び出し、そのバッファに文字列の内容を入力させ、関数の結果が成功または失敗。たとえば、不十分なサイズのバッファを渡すと、障害の原因の1つになります。異なるWindows API関数はこれをさまざまな方法で処理しますが、たとえば、MAX_PATHのような定数を使用して最大文字列長を定義するのが最も簡単です。

問題を解決するには、C#からの呼び出し方法を知っていて、例としてバッファに文字列結果を返すWindows API関数を1つ使用する必要があります。この例の後にエクスポートされた関数をモデル化し、C#プログラムから関数を呼び出すのは簡単です。

編集:私は、私はいくつかの時間前に同様の質問(How to import a function from a DLL made in Delphi?)を見たのだ、と今私が見ていることを私もあなたのようにそれを見つけたことを思い出し

あなたはそのDLLのソースコードを持っていないと書きました。そのため、エクスポートされた関数の変更は問題になりません。あなたができることは、DelphiでラッパーDLL(またはCOMオブジェクト)を作成し、オリジナルのHardwareIDExtractor.dllを呼び出し、その上に正常なAPIを提供することです。これにより、エクスポートされた関数のAnsiCharとWideCharの両方のバージョンを同時に提供することができます。

あなたはこのブログの投稿で説明したように、あなたも、あなたのラッパーDLLにリソースとしてオリジナルHardwareIDExtractor.dllを入れることができます(代わりに1の2つのDLLに必要な)乱雑さを軽減したい場合:Using DLLs stored as Resources in Delphi programs

+0

"あなたは、そのDLLのソースコードを持っていないと書いています。" OPがどこにあるのかわかりません...... Btw、リソースとして格納されているDLLを含むことは本当にクールです。 ;-) –

+0

リンク先の質問では:「私はそのDLLのソースコードを持っていないので、そのDLLに私のCプログラムを適応させなければなりません。 – mghie

2

お持ちの場合D7 dllのソースの場合、エクスポートされた関数を変更して、 ShortString関数がPCharを返すようにすることができます。元のものを呼び出して型キャストを行う新しい関数を作成することができます。これが最も簡単な方法です。このパスに従うならば、Integer型とCardinal型に同じようにします(それぞれLongIntとLongWordにキャストします)。 以下のいくつかのコード(私はミスターHausladenのような魔術師は、よりエレガントなアプローチを持っているが、これは:-)動作することを想像して)

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]であるので、これは動作します。 SizeOf(char)をSizeOf(AnsiChar)に変更する必要があるかどうかを確認するために、D2009は手元にありません。 BUT原則は同じです:PAnsiCharを割り当て、ShortStringの最初のcharへのポインタを取得し、Copy(この場合はCopyMemoryで行った)をPAnsiCharに渡します。そしてその場所にヌルを置く。

または、mghie'sの方法でラッパーを作成し、そこにキャストを行うことができます。

+0

"return PChar" - しかし、PCharはどのようなメモリを指すべきですか? – mghie

+0

上記のコード –

関連する問題