(順番)
最近DllImportを使用したところ、ほとんどのコンテンツがインターネット上のBaiduからのものであることがわかり、MSDNから収集しました。次に、コンテンツを要約して共有します。
実際の作業でC#を研究するとき、次のように尋ねることができます。既存の関数(Windowsの一部の関数、C ++で既に記述されているメソッドなど)のコードを書き直す必要があるのはなぜですか。C#を直接記述する方法はありますか?すでに存在するこれらの関数を使用しますか?答えは「はい」です。C#のDllImportを介してこれらの関数を直接呼び出すことができます。
DllImportはSystem.Runtime.InteropServices名前空間の下の属性クラスであるため、ASP.NETでDllImportを使用する場合は、最初に「System.Runtime.InteropServices;を使用する」必要があります。その機能は、アンマネージDLLから派生した関数を呼び出すために必要な情報を提供することです。DllImport属性はメソッドに適用され、少なくともエントリポイントを含むdllの名前が必要です。 DllImport属性定義
次のように:
名前空間System.Runtime.InteropServices
{{
[AttributeUsage(AttributeTargets.Method)]
パブリッククラスDllImportAttribute:System.Attribute
{{
public DllImportAttribute(string dllName){...} //ポジショニングパラメータはdllNameですpublic CallingConvention CallingConvention; //エントリポイントの呼び出し規約public CharSet CharSet; //エントリポイントで使用される文字接続public string EntryPoint; //エントリポイント名public bool ExactSpelling; //スペルが指定されたエントリポイントと完全に同じである必要があるかどうかにかかわらず、デフォルトはfalseです。public bool PreserveSig; //メソッドのシグネチャは保持または変換されますかpublic bool SetLastError; // FindLastErrorメソッドの戻り値はここに格納されますpublic string Value {get {...}}
}
}
説明:
1. DllImportは、メソッド宣言にのみ配置できます。
2. DllImportには、単一のポジショニングパラメーターがあります。インポートされたメソッドのdll名を含むdllNameパラメーターを指定します。
3. DllImportには、5つの名前付きパラメーターがあります。
a。CallingConventionパラメータは、エントリポイントの呼び出し規約を示します。CallingConventionが指定されていない場合、デフォルト値のCallingConvention.Winapiが使用されます。
b。CharSetパラメーターは、エントリポイントで使用される文字セットを指定します。CharSetが指定されていない場合、デフォルト値のCharSet.Autoが使用されます。
c。EntryPointパラメータは、dll内のエントリポイントの名前を示します。EntryPointが指定されていない場合は、メソッド自体の名前が使用されます。
d。ExactSpellingパラメータは、EntryPointが指定されたエントリポイントのスペルと正確に一致する必要があるかどうかを示します。ExactSpellingが指定されていない場合、デフォルト値のfalseが使用されます。
e。PreserveSigパラメーターは、メソッドのシグネチャが保持されるか変換されるかを示します。シグニチャが変換されると、HRESULT戻り値を持つシグニチャと、戻り値を持つretvalという名前の追加の出力パラメータに変換されます。PreserveSigが指定されていない場合、デフォルト値のtrueが使用されます。
f。SetLastErrorパラメータは、メソッドがWin32の「最後のエラー」を保持するかどうかを示します。SetLastErrorが指定されていない場合、デフォルト値のfalseが使用されます。
4.これは1回限りの属性クラスです。
5. DllImport属性で変更されたメソッドには、extern修飾子が必要です。
DllImportの使用例(iniファイルの書き込みに使用されるwin32api):
DllImport( "kernel32")
private static extern long WritePrivateProfileString(string section、string key、string val、string filePath);
このメソッドを使用してWinAPIを呼び出すデータ型は、DWORD = intまたはuint、BOOL = bool、事前定義された定数= enum、structure = structに対応します。
DllImportパスの問題:
DllImportは、次の順序で場所を自動的に検索します。
1.exeが配置されているディレクトリ
2.System32ディレクトリ
3.環境変数ディレクトリ
したがって、参照されるDLLをこれらの3つのディレクトリにコピーするだけで、パスを書き込む必要はありません。
Webだけでなく、アプリケーションでも
その後、[DllImport(@ "C:\ OJ \ Bin \ Judge.dll")]を使用してDLLの絶対パスを指定すると、正常にロードできることがわかりました。
この問題は、サードパーティのアンマネージDLLコンポーネントを使用している場合に最も頻繁に発生します。現時点では、鉱山も問題です。Asp.Netチームの公式ソリューションは次のとおりです。
まず、参照するコンポーネント、管理されているコンポーネント、管理されていないコンポーネントを確認する必要があります。管理されているコンポーネントは扱いやすく、直接使用されるコンポーネントは引用符で囲み、間接的に使用されるコンポーネントはbinディレクトリにコピーする必要があります。面倒。実際、CLRはファイルを一時ディレクトリにコピーしてから、そこでWebを実行し、CLRは管理対象ファイルのみをコピーするため、binにコピーしても役に立ちません。そのため、管理対象外のdllを明確に配置します。それでも、モジュールをbinの下にロードできないというプロンプトが表示されます。
具体的なアプローチは次のとおりです。
まず、C:\ DLLの場合、サーバー上に新しいディレクトリを作成する場所を見つけることができます。
次に、環境変数で、このディレクトリをPath変数に追加します。
最後に、管理されていないすべてのファイルをC:\ DLLにコピーするか、DLLをsystem32ディレクトリに配置します。
単独でデプロイできるアプリケーションの場合、このような優れたソリューションは解決策ではありません。ただし、仮想空間を使用している場合、PATH変数を登録したり、独自のDLLをsystem32ディレクトリにコピーしたりすることはできません。同時に、DLLの物理的なパスを必ずしも知っているとは限りません。
DllImportで使用できるのは文字列定数のみであり、Server.MapPath(@ "〜/ Bin / Judge.dll")を使用して物理パスを決定することはできません。
DllImportの読み込み速度が遅い問題:
ただし、これを「アンマネージDLL」と呼ぶのは非常に遅いことがわかりました。おそらく、私の方法ではリモート認証が必要なためですが、遅すぎます。多くの研究の結果、私はついに完璧な解決策を思いつきました。
最初に使用します
[DllImport( "kernel32.dll")]
private extern static IntPtr LoadLibrary(String path);
[DllImport( "kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr lib、String funcName);
[DllImport( "kernel32.dll")]
private extern static bool FreeLibrary(IntPtr lib);
LoadLibrary関数とGetProcAddress関数のアドレスがそれぞれ取得され、DLL内の関数がこれら2つの関数を介して取得されます。
最初にServer.MapPath(@ "〜/ Bin / Judge.dll")を使用してDLLの物理パスを取得し、次にLoadLibraryを使用してロードし、最後にGetProcAddressを使用して使用する関数のアドレスを取得します。
次のカスタムクラスコードは、LoadLibraryの読み込みと関数呼び出しを完了します。
パブリッククラスDllInvoke
{{
[DllImport( "kernel32.dll")]
private extern static IntPtr LoadLibrary(String path);
[DllImport( "kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr lib、String funcName);
[DllImport( "kernel32.dll")]
private extern static bool FreeLibrary(IntPtr lib);
プライベートIntPtrhLib;
public DllInvoke(String DLLPath)
{{
hLib = LoadLibrary(DLLPath);
}
〜DllInvoke()
{{
FreeLibrary(hLib);
}
//実行する関数をデリゲートに変換します
public Delegate Invoke(String APIName、Type t)
{{
IntPtr api = GetProcAddress(hLib、APIName);
return(Delegate)Marshal.GetDelegateForFunctionPointer(api、t);
}
}
次のコードは呼び出しを行います
パブリックデリゲートintCompile(String command、StringBuilder inf); //编译
DllInvoke dll = new DllInvoke(Server.MapPath(@ "〜/ Bin / Judge.dll"));
コンパイルコンパイル=(Compile)dll.Invoke( "Compile"、typeof(Compile));
StringBuilder inf;
compile(@ "gcc ac -o a.exe"、inf); //これは私のDLLで定義されたコンパイル関数を呼び出すためのものです
DllImportの使用例:
Win32 C#プログラミングで使用されるライブラリは、対応するタイプを使用しました 。
1. DWORDは4バイト整数であるため、C#の対応する型としてintまたはuintを使用できます。
2.ブール型はBOOLに対応します。
例1:Beep()APIを呼び出して音を出す
Beep()はkernel32.libで定義されています。MSDNで定義されているように、Beepには次のプロトタイプがあります。
BOOL Beep(DWORD dwFreq、//音の周波数
DWORD dwDuration //サウンドの持続時間);
次のプロトタイプをC#で記述します。
[DllImport( "kernel32.dll")]
public static extern bool Beep(intfrequency、intduration);
例2:列挙型と定数
MessageBeep()はuser32.libで定義されています。MSDNで定義されているように、MessageBeepには次のプロトタイプがあります。
BOOL MessageBeep(UINT uType //サウンドタイプ
);
プロトタイプをC#で記述します。
パブリック列挙型BeepType
{{
SimpleBeep = -1
IconAsterisk = 0x00000040、
IconExclamation = 0x00000030、
IconHand = 0x00000010、
IconQuestion = 0x00000020、
OK = 0x00000000、
}
uTypeパラメーターは、実際には事前定義された定数のセットを受け入れます。uTypeパラメーターには、列挙型を使用するのが理にかなっています。
[DllImport( "user32.dll")]
public static extern boolMessageBeep(BeepType beepType);
例3:処理構造
ラップトップのバッテリーの状態を判断する必要がある場合があります。Win32は、この目的のために電源管理関数を提供します。MSDNを検索して、GetSystemPowerStatus()関数を見つけてください。
BOOL GetSystemPowerStatus(LPSYSTEM_POWER_STATUS lpSystemPowerStatus);
この関数には、まだ扱っていない構造体へのポインタが含まれています。構造を処理するには、C#で構造を定義する必要があります。アンマネージドの定義から始めます。
typedef struct _SYSTEM_POWER_STATUS {
BYTE ACLineStatus;
BYTE BatteryFlag;
BYTE BatteryLifePercent;
BYTE Reserved1;
DWORD BatteryLifeTime;
DWORD BatteryFullLifeTime;
} SYSTEM_POWER_STATUS、* LPSYSTEM_POWER_STATUS;
次に、CタイプをC#タイプに置き換えて、C#バージョンを取得します。
struct SystemPowerStatus
{{
バイトACLineStatus;
バイトbatteryFlag;
バイトbatteryLifePercent;
バイトreserved1;
int BatteryLifeTime;
int BatteryFullLifeTime;
}
このようにして、C#プロトタイプを簡単に作成できます。
[DllImport( "kernel32.dll")]
public static extern bool GetSystemPowerStatus(ref SystemPowerStatus systemPowerStatus);
このプロトタイプでは、「ref」を使用して、構造体の値の代わりに構造体のポインターが渡されることを示します。これは、ポインタによって渡された構造を処理する一般的な方法です。
この関数はうまく機能しますが、ACLineStatusフィールドとbatteryFlagフィールドを列挙型として定義することをお勧めします。
列挙型ACLineStatus:バイト
{{
オフライン= 0、
オンライン= 1、
不明= 255、
}
列挙型BatteryFlag:バイト
{{
高= 1、
低= 2、
クリティカル= 4、
充電= 8、
NoSystemBattery = 128、
不明= 255、
}
構造体のフィールドはバイトであるため、列挙型の基本タイプとしてバイトを使用することに注意してください。
C#でC ++コードを呼び出す
int型
[DllImport( "MyDLL.dll")]
public static extern int mySum(int a1、int b1); // int型を返します
extern“ C” __declspec(dllexport)int WINAPI mySum(int a2、int b2)// DLLで宣言
{{
// a2b2はa1b1を変更できません
// a2 =。。
// b2 = .. ..
a + bを返します。
}
//パラメータ転送intタイプpublicstatic extern int mySum(ref int a1、ref int b1); // DLLでextern "C"を宣言します__declspec(dllexport)int WINAPI mySum(int * a2、int * b2){//はい変更a1、b1 * a2 = ... * b2 = ... return a + b;}
DLLはchar * type [DllImport( "MyDLL.dll")]を渡す必要があります //値を渡しますpublic static extern int mySum(string astr1、string bstr1); // DLLでextern "C"を宣言します__declspec(dllexport)int WINAPI mySum(char * astr2、char * bstr2){// astr2bstr 2を変更し、astr1bstr1は変更されませんreturna + b;}
DLLはchar * type [DllImport( "MyDLL.dll")]を送信する必要があります//送信される値public static extern int mySum(StringBuilder abuf、StringBuilder bbuf); // DLLでextern "C"を宣言します__declspec(dllexport )int WINAPI mySum(char * astr、char * bstr){//送信文字* change astr bstr-> abuf、bbufは変更可能return a + b;} DLLコールバック関数BOOLEnumWindows(WNDENUMPROC lpEnumFunc、LPARAM lParam)
usingSystem; System.Runtime.InteropServicesを使用する; publicデリゲートboolCallBack(int hwnd、int lParam); //デリゲート関数タイプを定義します パブリッククラスEnumReportApp {{ [DllImport( "user32")] public static extern int EnumWindows(CallBack x、int y); public static void Main()
{{ CallBack myCallBack = new CallBack(EnumReportApp.Report);
EnumWindows(myCallBack、0); } public static bool Report(int hwnd、int lParam) {{ Console.Write( "ウィンドウハンドルは"); Console.WriteLine(hwnd); trueを返します。 } }
DLLの構造 BOOLPtInRect(const RECT * lprc、POINT pt); System.Runtime.InteropServicesを使用する; [StructLayout(LayoutKind.Sequential)] public struct Point
{public int x; public int y; } [StructLayout(LayoutKind.Explicit)] public struct Rect {[FieldOffset(0)] public int left; [FieldOffset(4)] public int top; [FieldOffset(8)] public int right; [FieldOffset(12)] public int bottom; }クラスXXXX
{[DllImport( "User32.dll")] public static extern bool PtInRect(ref Rect r、Point p); }