연습: Windows API 호출(Visual Basic)

Windows API는 Windows 운영 체제의 일부인 DLL(동적 연결 라이브러리)입니다. 동일한 프로시저를 직접 작성하기 어려운 경우 작업을 수행하는 데 사용합니다. 예를 들어 Windows는 밝은 음영과 어두운 음영을 번갈아 가며 애플리케이션의 제목 표시줄을 만들 수 있는 FlashWindowEx라는 함수를 제공합니다.

코드에 Windows API를 사용하면 이미 작성되어 사용할 수 있는 수십 개의 유용한 함수가 포함되어 있으므로 개발 시간을 절약할 수 있다는 장점이 있습니다. 단점은 문제가 발생할 때 Windows API로 작업하거나 해결하기 어려울 수 있다는 것입니다.

Windows API는 상호 운용성의 특별한 범주를 나타냅니다. Windows API는 관리형 코드를 사용하지 않고 기본 제공 형식 라이브러리가 없으며 Visual Studio에서 사용되는 것과 다른 데이터 형식을 사용합니다. 이러한 차이 때문에 그리고 Windows API가 COM 개체가 아니기 때문에 플랫폼 호출 또는 PInvoke를 사용하여 Windows API 및 .NET Framework와의 상호 운용성이 수행됩니다. 플랫폼 호출은 관리형 코드가 DLL에 구현된 비관리형 함수를 호출할 수 있도록 하는 서비스입니다. 자세한 내용은 비관리형 DLL 함수 사용을 참조하세요. Declare 문을 사용하거나 DllImport 특성을 빈 프로시저에 적용하여 Visual Basic에서 PInvoke를 사용할 수 있습니다.

Windows API 호출은 과거에 Visual Basic 프로그래밍의 중요한 부분이었지만 Visual Basic .NET에서는 거의 필요하지 않습니다. 가능하면 Windows API 호출 대신 .NET Framework에서 관리형 코드를 사용하여 작업을 수행해야 합니다. 이 연습에서는 Windows API를 사용해야 하는 상황에 대한 정보를 제공합니다.

참고 항목

일부 Visual Studio 사용자 인터페이스 요소의 경우 다음 지침에 설명된 것과 다른 이름 또는 위치가 시스템에 표시될 수 있습니다. 이러한 요소는 사용하는 Visual Studio 버전 및 설정에 따라 결정됩니다. 자세한 내용은 IDE 개인 설정을 참조하세요.

선언을 사용하여 API 호출

Windows API를 호출하는 가장 일반적인 방법은 Declare 문을 사용하는 것입니다.

DLL 프로시저를 선언하는 방법

  1. 호출할 함수의 이름, 해당 인수, 인수 형식, 반환 값뿐만 아니라 함수를 포함하는 DLL의 이름과 위치를 결정합니다.

    참고 항목

    Windows API에 대한 자세한 내용은 플랫폼 SDK Windows API의 Win32 SDK 설명서를 참조하세요. Windows API에서 사용하는 상수에 대한 자세한 내용은 플랫폼 SDK에 포함된 Windows.h와 같은 헤더 파일을 검사합니다.

  2. 파일 메뉴에서 새로 만들기를 클릭한 다음, 프로젝트를 클릭하여 새 Windows 애플리케이션 프로젝트를 엽니다. 새 프로젝트 대화 상자가 나타납니다.

  3. Visual Basic 프로젝트 템플릿 목록에서 Windows 애플리케이션을 선택합니다. 새 프로젝트가 표시됩니다.

  4. DLL을 사용하려는 클래스 또는 모듈에 다음 Declare 함수를 추가합니다.

    Declare Auto Function MBox Lib "user32.dll" Alias "MessageBox" (
        ByVal hWnd As Integer,
        ByVal txt As String,
        ByVal caption As String,
        ByVal Typ As Integer) As Integer
    

Declare 문의 일부

Declare 문에는 다음과 같은 요소가 포함됩니다.

자동 한정자

Auto 한정자는 공용 언어 런타임 규칙(또는 지정된 경우 별칭 이름)에 따라 메서드 이름을 기반으로 문자열을 변환하도록 런타임에 지시합니다.

라이브러리 및 별칭 키워드

Function 키워드 다음의 이름은 프로그램에서 가져온 함수에 액세스하는 데 사용하는 이름입니다. 이는 호출하는 함수의 실제 이름과 같을 수 있습니다. 또는 유효한 프로시저 이름을 사용한 다음, Alias 키워드를 사용하여 호출하는 함수의 실제 이름을 지정할 수 있습니다.

Lib 키워드를 지정한 다음, 호출하는 함수가 포함된 DLL의 이름과 위치를 지정합니다. Windows 시스템 디렉터리에 있는 파일의 경로를 지정할 필요가 없습니다.

호출하는 함수의 이름이 유효한 Visual Basic 프로시저 이름이 아니거나 애플리케이션의 다른 항목 이름과 충돌하는 경우 Alias 키워드를 사용합니다. Alias는 호출되는 함수의 실제 이름을 나타냅니다.

인수 및 데이터 형식 선언

인수 및 해당 데이터 형식을 선언합니다. Windows에서 사용하는 데이터 형식이 Visual Studio 데이터 형식에 해당하지 않으므로 이 부분은 어려울 수 있습니다. Visual Basic은 마샬링이라는 프로세스인 호환되는 데이터 형식으로 인수를 변환하여 많은 작업을 수행합니다. System.Runtime.InteropServices 네임스페이스에 정의된 MarshalAsAttribute 특성을 사용하여 인수를 마샬링하는 방법을 명시적으로 제어할 수 있습니다.

참고 항목

이전 버전의 Visual Basic에서는 매개 변수 As Any를 선언할 수 있으므로 모든 데이터 형식의 데이터를 사용할 수 있습니다. Visual Basic에서는 모든 Declare 문에 특정 데이터 형식을 사용해야 합니다.

Windows API 상수

일부 인수는 상수의 조합입니다. 예를 들어 이 연습에 표시된 MessageBox API는 메시지 상자가 표시되는 방식을 제어하는 Typ라는 정수 인수를 허용합니다. WinUser.h 파일의 #define 문을 검사하여 이러한 상수의 숫자 값을 확인할 수 있습니다. 숫자 값은 일반적으로 16진수로 표시되므로 계산기를 사용하여 값을 추가하고 10진수로 변환할 수 있습니다. 예를 들어 느낌표 스타일 MB_ICONEXCLAMATION 0x00000030에 대한 상수와 예/아니요 스타일 MB_YESNO 0x00000004에 대한 상수를 결합하려는 경우 숫자를 추가하여 결과로 0x00000034 또는 52라는 10진수를 얻을 수 있습니다. 10진수 결과를 직접 사용할 수 있지만 이러한 값을 애플리케이션에서 상수로 선언하고 Or 연산자를 사용하여 결합하는 것이 좋습니다.

Windows API 호출에 대한 상수 선언
  1. 호출하는 Windows 함수에 대한 설명서를 참조하세요. 사용하는 상수의 이름과 이러한 상수의 숫자 값이 포함된 .h 파일의 이름을 결정합니다.

  2. 메모장과 같은 텍스트 편집기를 사용하여 머리글(.h) 파일의 내용을 보고 사용 중인 상수와 연결된 값을 찾습니다. 예를 들어 MessageBox API는 상수 MB_ICONQUESTION을 사용하여 메시지 상자에 물음표를 표시합니다. MB_ICONQUESTION에 대한 정의는 WinUser.h에 있으며 다음과 같이 표시됩니다.

    #define MB_ICONQUESTION 0x00000020L

  3. 클래스 또는 모듈에 해당하는 Const 문을 추가하여 애플리케이션에서 이러한 상수를 사용할 수 있도록 합니다. 예시:

    Const MB_ICONQUESTION As Integer = &H20
    Const MB_YESNO As Integer = &H4
    Const IDYES As Integer = 6
    Const IDNO As Integer = 7
    
DLL 프로시저를 호출하는 방법
  1. 프로젝트의 시작 양식에 이름이 Button1인 단추를 추가한 다음, 두 번 클릭하여 해당 코드를 봅니다. 단추의 이벤트 처리기가 표시됩니다.

  2. 추가한 단추에 대한 Click 이벤트 처리기에 코드를 추가하여 프로시저를 호출하고 적절한 인수를 제공합니다.

    Private Sub Button1_Click(ByVal sender As System.Object,
        ByVal e As System.EventArgs) Handles Button1.Click
    
        ' Stores the return value.
        Dim RetVal As Integer
        RetVal = MBox(0, "Declare DLL Test", "Windows API MessageBox",
            MB_ICONQUESTION Or MB_YESNO)
    
        ' Check the return value.
        If RetVal = IDYES Then
            MsgBox("You chose Yes")
        Else
            MsgBox("You chose No")
        End If
    End Sub
    
  3. F5 키를 눌러 프로젝트를 실행합니다. 메시지 상자는 아니요 응답 단추와 함께 표시됩니다. 둘 중 하나를 클릭합니다.

데이터 마샬링

Visual Basic은 Windows API 호출에 대한 매개 변수 및 반환 값의 데이터 형식을 자동으로 변환하지만, MarshalAs 특성을 사용하여 API에서 예상하는 비관리형 데이터 형식을 명시적으로 지정할 수 있습니다. interop 마샬링에 대한 자세한 내용은 interop 마샬링을 참조하세요.

API 호출에서 Declare 및 MarshalA를 사용하는 방법
  1. 호출할 함수의 이름과 인수, 데이터 형식, 반환 값을 결정합니다.

  2. MarshalAs 특성에 대한 액세스를 간소화하려면 다음 예제와 같이 클래스 또는 모듈의 코드 맨 위에 Imports 문을 추가합니다.

    Imports System.Runtime.InteropServices
    
  3. 가져온 함수의 함수 프로토타입을 사용 중인 클래스 또는 모듈에 추가하고 매개 변수 또는 반환 값에 MarshalAs 특성을 적용합니다. 다음 예제에서는 형식 void*을 예상하는 API 호출이 AsAny와 같이 마샬링됩니다.

    Declare Sub SetData Lib "..\LIB\UnmgdLib.dll" (
        ByVal x As Short,
        <MarshalAsAttribute(UnmanagedType.AsAny)>
            ByVal o As Object)
    

DllImport를 사용하는 API 호출

DllImport 특성은 형식 라이브러리 없이 DLL에서 함수를 호출하는 두 번째 방법을 제공합니다. DllImportDeclare 문을 사용하는 것과 거의 동일하지만 함수가 호출되는 방식을 보다 세세하게 제어할 수 있습니다.

호출이 공유(정적이라고도 함) 메서드를 참조하는 한 대부분의 Windows API 호출에서 DllImport를 사용할 수 있습니다. 클래스의 인스턴스가 필요한 메서드는 사용할 수 없습니다. Declare 문과 달리 DllImport 호출은 MarshalAs 특성을 사용할 수 없습니다.

DllImport 특성을 사용하여 Windows API를 호출하는 방법

  1. 파일 메뉴에서 새로 만들기를 클릭한 다음, 프로젝트를 클릭하여 새 Windows 애플리케이션 프로젝트를 엽니다. 새 프로젝트 대화 상자가 나타납니다.

  2. Visual Basic 프로젝트 템플릿 목록에서 Windows 애플리케이션을 선택합니다. 새 프로젝트가 표시됩니다.

  3. 시작 양식에 이름이 Button2인 단추를 추가합니다.

  4. 양식의 코드 보기를 열려면 Button2를 두 번 클릭합니다.

  5. DllImport에 대한 액세스를 간소화하려면 시작 양식 클래스에 대한 코드 맨 위에 Imports 문을 추가합니다.

    Imports System.Runtime.InteropServices
    
  6. 양식의 End Class 문 앞에 빈 함수를 선언하고 함수 MoveFile의 이름을 지정합니다.

  7. 함수 선언에 Public 한정자 및 Shared 한정자를 적용하고 Windows API 함수에서 사용하는 인수에 따라 MoveFile에 대한 매개 변수를 설정합니다.

    Public Shared Function MoveFile(
        ByVal src As String,
        ByVal dst As String) As Boolean
        ' Leave the body of the function empty.
    End Function
    

    함수에는 유효한 프로시저 이름이 있을 수 있습니다. DllImport 특성은 DLL의 이름을 지정합니다. 이는 또한 매개 변수 및 반환 값에 대한 상호 운용성 마샬링도 처리하므로 API에서 사용하는 데이터 형식과 유사한 Visual Studio 데이터 형식을 선택할 수 있습니다.

  8. 빈 함수에 DllImport 특성을 적용합니다. 첫 번째 매개 변수는 호출하는 함수를 포함하는 DLL의 이름과 위치입니다. Windows 시스템 디렉터리에 있는 파일의 경로를 지정할 필요가 없습니다. 두 번째 매개 변수는 Windows API에서 함수의 이름을 지정하는 명명된 인수입니다. 이 예제에서 DllImport 특성은 강제로 MoveFile에 대한 호출을 KERNEL32.DLL의 MoveFileW로 전달합니다. MoveFileW 메서드는 경로 src에서 경로 dst로 파일을 복사합니다.

    <DllImport("KERNEL32.DLL", EntryPoint:="MoveFileW", SetLastError:=True,
        CharSet:=CharSet.Unicode, ExactSpelling:=True,
        CallingConvention:=CallingConvention.StdCall)>
    Public Shared Function MoveFile(
        ByVal src As String,
        ByVal dst As String) As Boolean
        ' Leave the body of the function empty.
    End Function
    
  9. Button2_Click 이벤트 처리기에 함수를 호출하는 코드를 추가합니다.

    Private Sub Button2_Click(ByVal sender As System.Object,
        ByVal e As System.EventArgs) Handles Button2.Click
    
        Dim RetVal As Boolean = MoveFile("c:\tmp\Test.txt", "c:\Test.txt")
        If RetVal = True Then
            MsgBox("The file was moved successfully.")
        Else
            MsgBox("The file could not be moved.")
        End If
    End Sub
    
  10. Test.txt라는 파일을 만들고 하드 드라이브의 C:\Tmp 디렉터리에 배치합니다. 필요한 경우 Tmp 디렉터리를 만듭니다.

  11. F5 키를 눌러 애플리케이션을 시작합니다. 기본 양식이 나타납니다.

  12. Button2를 클릭합니다. 파일을 이동할 수 있으면 “파일이 성공적으로 이동되었습니다.”라는 메시지가 표시됩니다.

참고 항목