2016-06-01 1 views
2

私は、顧客からのAPI記述のDLLとテキストファイルのみを持っています(下記参照)。 DLLに関する詳細はありません。私はDelphiのバージョンなどを知らない。C#コードの文字列[255]型と構造を持つDelphi DLLを使用

私は両方のAPI関数を使用しようとしたが、うまくいかなかった。一般にstring [255](PatientIDとAccessionNo)の最初の2つのパラメータが重要です。そのDLLに文字列を渡す私の試みは、適切な結果を提供しません。私はアプリケーションのGUIでランダムなガベージ値や文字列の一部を参照してください。私はこのサイトのすべての関連する質問を見て、インターネットで検索しましたが、私を助けたものは見つかりませんでした。

  1. OpenStudy機能 - 私はMarshalAsすべての適切な値(以下参照)、のCharSet = CharSet.Ansiと自動で異なる設定を試みました。 管理対象アプリケーションのGUIテキストフィールドにガベージのランダム値が表示されます。

    [DllImport("Lib\\RISInterface.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "Open_Study", ExactSpelling = false)] 
    
    static extern internal int OpenStudy(
    
    // try to use here and for all string fields [MarshalAs(UnmanagedType.AnsiBStr)] , LPStr, LPTStr, LPWStr, BStr, TBStr, HString 
    string PatientID, 
    string AccessionNo, 
    bool CloseCurrentStudy, 
    bool AddToWindow, 
    int SeriesRows, 
    int SeriesCols, 
    int PresentationMode, 
    bool AutoTile, 
    bool AutoLoad, 
    bool RemoteExam); 
    
  2. OpenStudy1機能 - 私は構造を記入して関数を呼び出します。私は通常の文字列としてPatientIDとAccessionNoを参照しますが、PatientIDは最初の文字を紛失し、AccessionNoは最初の2文字を紛失します。 (:、 "12345" を "QWERTY" をしてご覧ください:送信 "werty"、 "345")

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
    public struct TIQStudyAutomation 
    { 
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] 
        public string PatientID; 
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] 
        public string AccessionNo; 
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] 
        public string StudyUID; 
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] 
        public string SeriesUID; 
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] 
        public string InstanceUID; 
        public bool CloseCurrentStudy; 
        public bool AddToWindow; 
        public int SeriesRows; 
        public int SeriesCols; 
        public int PresentationMode; 
        public bool AutoTile; 
        public bool AutoLoad; 
        public bool RemoteExam; 
        public bool LoadFromAllSources; 
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] 
        public string ArchiveName; 
    } 
    
    [DllImport("Lib\\RISInterface.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "Open_Study1", ExactSpelling = false)] 
    
    static extern internal int OpenStudy1(TIQStudyAutomation automationInfo); 
    

================= APIの説明========================

これらの関数宣言は次のとおりです。 Delphiコードとすべての文字列参照はAnsi文字列です。

function Open_Study(PatientID, AccessionNo: PAnsiChar; CloseCurrentStudy, AddToWindow: Boolean; 
    SeriesRows, SeriesCols, PresentationMode: Integer; 
    AutoTile, AutoLoad, RemoteExam: Boolean): Integer; stdcall; 
Return 
    Error Code. 

Remarks 
    The parameters will be packed into a TIQStudyAutomation record and passed to Open_Study1. 

//-------------------------------------------------------------------------------------------------- 

function Open_Study1(AutomationInfo: TIQStudyAutomation): Integer; stdcall; 
Return 
    Error Code. 

Parameters 
    Takes a TIQStudyAutomation record. 

//-------------------------------------------------------------------------------------------------- 


TIQStudyAutomation = record 

    PatientID, AccessionNo, StudyUID, SeriesUID, InstanceUID: STRING[255]; 

    CloseCurrentStudy, AddToWindow: BOOLEAN; 

    SeriesRows, SeriesCols, PresentationMode: Integer; 

    AutoTile, AutoLoad, RemoteExam, LoadFromAllSources : BOOLEAN; ArchiveName: STRING[255]; 

end; 

ヘルプがありますか?

+1

可能重複[DelphiのDLLを使用する方法(PChar型で)C#で](http://stackoverflow.com/questions/5086645/how-to-use-delphi-dllwith-pchar-type-in​​-c-sharp) –

+0

@ZENsanそれよりも多くの方法があります。 'string [255]'はマーシャリングを行います。 –

+0

David、「文字列[255]はマーシャリングを必要とする」という意味を明確にすることはできますか? – valger

答えて

1

レコードを翻訳する必要はありません。これは、Delphiの短い文字列を使用するため、非常に難しいです。代わりにOpen_Studyに電話することができます。 Delphiの宣言は次のとおりです。

function Open_Study(
    PatientID: PAnsiChar; 
    AccessionNo: PAnsiChar; 
    CloseCurrentStudy: Boolean; 
    AddToWindow: Boolean; 
    SeriesRows: Integer; 
    SeriesCols: Integer; 
    PresentationMode: Integer; 
    AutoTile: Boolean; 
    AutoLoad: Boolean; 
    RemoteExam: Boolean 
): Integer; stdcall; 

この翻訳では唯一の真のしわは、Delphi Booleanタイプは、1バイト型であるということです。しかし、C#boolは、Win32タイプBOOLと一致するように、デフォルトで4バイトタイプとしてマーシャリングします。

は、だから私はそうのような機能を翻訳します:

に対処するために、ややトリッキーである string[255]については
[DllImport("Lib\\RISInterface.dll", CallingConvention = CallingConvention.StdCall, 
    CharSet = CharSet.Ansi, EntryPoint = "Open_Study", ExactSpelling = true)] 
static extern internal int OpenStudy(
    string PatientID, 
    string AccessionNo, 
    [MarshalAs(UnmanagedType.U1)] bool CloseCurrentStudy, 
    [MarshalAs(UnmanagedType.U1)] bool AddToWindow, 
    int SeriesRows, 
    int SeriesCols, 
    int PresentationMode, 
    [MarshalAs(UnmanagedType.U1)] bool AutoTile, 
    [MarshalAs(UnmanagedType.U1)] bool AutoLoad, 
    [MarshalAs(UnmanagedType.U1)] bool RemoteExam 
); 

。このタイプのサイズは256です。最初のバイトは文字列の長さで、残りのバイトはペイロードです。このペイロードは、ANSIでエンコードされた8ビット文字の配列です。また、この配列はヌルで終了する必要はありません。

p/invokeフレームワークがこのような型をサポートしていないため、自動的にマーシャリングすることはできません。個人的に私はこのタイプをbyte[]に翻訳すると宣言します。私は[MarshalAs(UnmanagedType.ByValArray, SizeConst=256)]でそれをマーシャリングします。次に、C#ストリングとのマーシャリングにヘルパー関数を記述します。これらは、Encoding.GetStringEncoding.GetBytesへの呼び出しを含み、文字列の長さを適切に処理するよう注意します。

確かに可能ですが、ちょっと乱雑です。したがって、できるだけ避けて、ヘルパー機能Open_Studyを呼び出すことをお勧めします。最終溶液は、以下れる

+0

UnmanagedType.ByValArrayは、構造体フィールドにのみ適用されます。 BTW私はstring [255]構造フィールドの手動変換推奨に従って、それを動作させました。どうもありがとうございました。 – valger

+0

* 'UnmanagedType.ByValArray'は構造体フィールドにのみ適用できます。それが、私がその使用を主張しているところです。 –

0

(構造体宣言、関数宣言と関数は、バイト配列としてDelphiの文字列[255]に文字列を変換する):


public struct TIQStudyAutomation 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] 
    public byte[] PatientID; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] 
    public byte[] AccessionNo; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] 
    public byte[] StudyUID; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] 
    public byte[] SeriesUID; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] 
    public byte[] InstanceUID; 
    [MarshalAs(UnmanagedType.U1)] 
    public bool CloseCurrentStudy; 
    [MarshalAs(UnmanagedType.U1)] 
    public bool AddToWindow; 
    public int SeriesRows; 
    public int SeriesCols; 
    public int PresentationMode; 
    [MarshalAs(UnmanagedType.U1)] 
    public bool AutoTile; 
    [MarshalAs(UnmanagedType.U1)] 
    public bool AutoLoad; 
    [MarshalAs(UnmanagedType.U1)] 
    public bool RemoteExam; 
    [MarshalAs(UnmanagedType.U1)] 
    public bool LoadFromAllSources; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] 
    public byte[] ArchiveName; 
} 
    [DllImport("Lib\\RISInterface.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "Open_Study1", ExactSpelling = false)] 
    static extern internal int OpenStudy1(TIQStudyAutomation automationInfo); 

    private byte[] ConvertToDelphiString255(string input) 
    { 
     var output = new byte[256]; 
     if(String.IsNullOrEmpty(input)) 
     { 
      return output; 
     } 

     var ar = Encoding.ASCII.GetBytes(input); 
     var length = ar.Length > 255 ? 255 : ar.Length; 
     output[0] = (byte)length; 
     for(int i=0; i<length; i++) 
     { 
      output[i+1] = ar[i]; 
     } 
     return output; 
    } 
+0

これは確実に行う必要はありません。高レベル関数を呼び出します。エンコーディングはASCIIではなくANSIでなければなりません。ループ処理ではなく、バイト配列の内容を直接コピーできます。 –

+0

コピー機能でループを置き換えました。ありがとうございます。しかし、私はASCIIの代わりにANSIを使用する方法を理解していません。 ( "ANSI:固定ANSIエンコーディングはありません - 多くのものがありますが、通常" ANSI "とはエンコーディングで取得される"システムのデフォルトロケール/コードページ "を意味し、Windows-1252しかし、他のロケールになる可能性があります。 " - [リンク](http://stackoverflow.com/questions/700187/unicode-utf-ascii-ansi-format-differences)) – valger

+0

それはまさにそれです。 Delphiの型はANSIでエンコードされています。ロケールのデフォルトコードページの使用。 –

関連する問題