C#_DllImport 사용법 및 경로 문제

24392 단어
DllImport는 System입니다.Runtime.InteropServices 네임스페이스의 속성 클래스로, 관리되지 않는 DLL에서 내보낸 함수에 필요한 호출 정보를 제공합니다.DllImport 속성은 메서드에 적용되며 엔트리 포인트를 포함하는 dll의 이름을 최소한 입력해야 합니다.DllImport의 정의는 다음과 같습니다.
[AttributeUsage(AttributeTargets.Method)]
  public class 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 {…} }
  }

 
사용 예:
[DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section,string key,string val,string filePath);

이상은 ini 파일을 쓰기 위한 win32api입니다.이 방식으로 Win32API의 데이터 형식을 호출합니다: DWORD=int 또는 uint, BOOL=bool, 상수=enum, 구조=struct입니다.
DllImport는 순서에 따라 자동으로 찾는 곳: 1. exe가 있는 디렉터리 2, System32 디렉터리 3, 환경 변수 디렉터리 때문에 인용된 DLL을 이 세 디렉터리로 복사하면 경로를 쓰지 않거나 이렇게 할 수 있다.MapPath(.\bin\*.dll) 웹의 경우 응용 프로그램에서 발견된 경우 [DllImport(@ "C:\OJ\Bin\Judge.dll")]를 사용하여 DLL의 절대 경로를 지정하면 제대로 마운트할 수 있습니다.이 문제는 제3자 비위탁 관리 DLL 구성 요소를 사용할 때 가장 자주 나타난다. 나도 마찬가지로 이때 발생한 문제이다. Asp.Net Team의 공식 해결 방안은 다음과 같습니다. 우선 어떤 구성 요소를 인용했는지, 그것이 위탁 관리이고, 어떤 것이 비위탁 관리인지 확인해야 합니다.위탁 관리는 매우 쉽다. 직접 사용되는 것은 인용이 필요하고 간접적으로 사용하는 것은 bin 디렉터리에 복사해야 한다.위탁 관리가 아닌 처리는 비교적 번거롭다.실제로, 당신은 bin으로 복사하는 데 아무런 도움이 되지 않습니다. 왜냐하면 CLR은 파일을 임시 디렉터리로 복사한 다음에 웹을 실행합니다. 그러나 CLR은 위탁 관리 파일만 복사합니다. 이것은 우리가 위탁 관리가 아닌 dll을 bin에 놓았는데도 모듈을 불러올 수 없다는 것을 알려주는 이유입니다.구체적인 방법은 다음과 같다. 1. 우선 우리는 서버에 아무데나 새 디렉터리를 만든다. 만약에 C:\DLL 2이고 환경 변수에Path 변수에 이 디렉터리 3을 추가한다. 마지막으로 모든 비위탁 관리 파일을 C:\DLL로 복사한다.4. 또는 더 시원스럽게 DLL을 시스템32 디렉터리에 두는 것은 스스로 배치할 수 있는 응용 프로그램에 대한 해결책이 아니다. 그러나 만약에 우리가 가상 공간을 사용한다면 PATH 변수를 등록하거나 우리의 DLL을 시스템32 디렉터리에 복사할 수 없다.동시에 우리는 반드시 우리의 Dll의 물리적 경로를 알지 못한다.DllImport 안에는 문자열 상수만 사용할 수 있고 Server는 사용할 수 없습니다.MapPath(@ "~/Bin/Judge.dll")로 물리적 경로를 결정합니다. ASP.NET에서 DllImport를 사용하려면 먼저 "using System.Runtime.Interop Services;"그러나 나는 이런'비위탁 관리 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의 함수를 얻었습니다.우리는 먼저 Server를 사용할 수 있다.MapPath (@ "~/Bin/Judge. dll") 에서 DLL의 물리적 경로를 찾은 다음 LoadLibrary로 불러오고, 마지막으로 GetProcAddress로 사용할 함수 주소를 가져옵니다.
다음 사용자 정의 클래스 코드는 LoadLibrary 마운트 및 함수 호출을 완료합니다.
public class 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);
  private IntPtr hLib;

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

다음 코드를 호출합니다
public delegate int Compile(String command, StringBuilder inf);//  
DllInvoke dll = new DllInvoke(Server.MapPath(@"~/Bin/Judge.dll"));
Compile compile = (Compile)dll.Invoke("Compile", typeof(Compile));
StringBuilder inf;
compile(@“gcc a.c -o a.exe“,inf); // DLL Compile

여러분은 실제 업무에서 C#를 공부할 때 왜 우리는 이미 존재하는 기능(예를 들어 Windows의 일부 기능, C++에서 이미 작성한 방법)을 위해 코드를 다시 작성해야 합니까? C# 원래 존재했던 기능들을 직접 사용할 수 있는 방법이 있습니까?정답은 긍정적이며 C#의 DllImport를 통해 이러한 기능을 직접 호출할 수 있습니다.DllImport가 있는 이름 공간 using System.Runtime.InteropServices;MSDN에서 DllImportAttribute에 대한 설명은 다음과 같습니다. 이 속성을 방법에 적용할 수 있습니다.DllImportAttribute 속성은 관리되지 않는 DLL에서 내보낸 함수를 호출하는 데 필요한 정보를 제공합니다.최소 요구 사항으로 엔트리 포인트가 포함된 DLL의 이름을 제공해야 합니다.DllImport 속성은 다음과 같이 정의됩니다.
namespace System.Runtime.InteropServices 
{
  [AttributeUsage(AttributeTargets.Method)]
  public class DllImportAttribute: System.Attribute
  {
   public DllImportAttribute(string dllName) {...}
   public CallingConvention CallingConvention;
   public CharSet CharSet;
   public string EntryPoint;
   public bool ExactSpelling;
   public bool PreserveSig;
   public bool SetLastError;
   public string Value { get {...} }
  }
}

 
설명: 1. DllImport는 메소드 선언에만 배치할 수 있습니다.2. DllImport에는 단일 위치 매개 변수가 있습니다. 가져오는 방법의 dll 이름을 포함하는 dllName 매개 변수를 지정합니다.3. DllImport에는 다섯 개의 명명 파라미터가 있다. 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, 그것은 일회성 속성 클래스입니다.5, 또한 DllImport 속성으로 수식하는 방법에는 extern 수식자가 있어야 한다.
DllImport 사용법:
DllImport("MyDllImport.dll")]
private static extern int mySum(int a,int b);

첫째, C# 프로그램 설계에서 Win32 라이브러리에서 자주 사용하는 대응 유형을 사용한다. 1. DWORD는 4바이트의 정수이기 때문에 우리는 int나 uint를 C#의 대응 유형으로 사용할 수 있다.2. bool 유형은 BOOL에 해당합니다.예제 1: Beep() API를 호출하여 사운드를 내는 Beep()은kernel32.lib에 정의된 MSDN에 정의된 Beep에는 다음과 같은 원형이 있습니다.
 BOOL Beep(DWORD dwFreq, //      
DWORD dwDuration // );

C#를 사용하여 다음 원형을 작성합니다.
[DllImport("kernel32.dll")] 
public static extern bool Beep(int frequency, int duration);

예 2: 열거 유형과 상수 MessageBeep()은user32.lib에 정의된 MSDN에 정의된 MessageBeep에는 다음과 같은 원형이 있습니다.
BOOL MessageBeep(UINT uType //     
);

C#로 프로토타입 작성:
public enum BeepType
{
  SimpleBeep = -1,
  IconAsterisk = 0x00000040,
  IconExclamation = 0x00000030,
  IconHand = 0x00000010,
  IconQuestion = 0x00000020,
  Ok = 0x00000000,
}

 
uType 파라미터는 실제적으로 한 그룹의 미리 정의된 상수를 받아들인다. uType 파라미터에 대해 enum 유형을 사용하는 것은 이치에 맞다.
[DllImport("user32.dll")]
public static extern bool MessageBeep(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 
{
  byte ACLineStatus;
  byte batteryFlag;
  byte batteryLifePercent;
  byte reserved1;
  int batteryLifeTime;
  int batteryFullLifeTime;
}

이렇게 하면 C# 프로토타입을 쉽게 작성할 수 있습니다.
[DllImport("kernel32.dll")] 
public static extern bool GetSystemPowerStatus(ref SystemPowerStatus systemPowerStatus);

이 원형에서 우리는'ref'로 구조 값을 전달하는 것이 아니라 구조 바늘을 전달하는 것을 가리킨다.이것은 지침을 통해 전달되는 구조를 처리하는 일반적인 방법이다.이 함수는 잘 작동하지만 ACLineStatus 및 batteryFlag 필드를 enum으로 정의하는 것이 좋습니다.
enum ACLineStatus: byte 
{
    Offline = 0,
    Online = 1,
    Unknown = 255,
}

enum BatteryFlag: byte
{
    High = 1,
    Low = 2,
    Critical = 4,
    Charging = 8,
    NoSystemBattery = 128,
    Unknown = 255,
}

구조의 필드는 일부 바이트이기 때문에, 이enum의 기본 형식으로 byte를 사용합니다. 예 4: 문자열 처리 DLL이 int 형식으로 되돌아오기
[DllImport(“MyDLL.dll")] 
// int
public static extern int mySum (int a1,int b1);
//DLL
extern “C” __declspec(dllexport) int WINAPI mySum(int a2,int b2)
{
//a2 b2 a1 b1
//a2=..
//b2=...
return a+b;
}

// int
public static 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* 유형
[DllImport(“MyDLL.dll")] 
//
public static extern int mySum (string astr1,string bstr1);
//DLL
extern “C” __declspec(dllexport) int WINAPI mySum(char * astr2,char * bstr2)
{
// astr2 bstr 2 ,astr1 bstr1
return a+b;
}

 
DLL 콜백 함수
 
[DllImport(“MyDLL.dll")]
//
public static extern int mySum (StringBuilder abuf, StringBuilder bbuf );
//DLL
extern “C” __declspec(dllexport) int WINAPI mySum(char * astr,char * bstr)
{
// char *  astr bstr -->abuf, bbuf
return a+b;
}

2C#에서 C++ 코드 호출
BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)
using System;
using System.Runtime.InteropServices;
public delegate bool CallBack(int hwnd, int lParam); //
public class 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("Window handle is ");
Console.WriteLine(hwnd); return true;
}
}

 
DLL 전송 패브릭
BOOL PtInRect(const RECT *lprc, POINT pt);

using 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;
}
Class XXXX {
[DllImport("User32.dll")]
public static extern bool PtInRect(ref Rect r, Point p);
}

좋은 웹페이지 즐겨찾기