공통 3가지 API 이야기: VCL에서 WinAPI, COM&ShellAPI, WinRT 활용하기
2019.09.18 15:30
아래 내용은 마르코칸투가 직접 진행했던 온라인 세미나의 내용을 간략하게 정리한 글 입니다.
보다 자세한 내용은 다음 링크를 참고하시기 바랍니다.
윈도우 API의 흐름
운영체제에서 제공해왔던 다양한 API들을 시간 흐름에 따라 정리하자면 다음과 같습니다:
중요한 점은 위와 같은 세가지 유형 - API, COM, WinRT - 은 모두 C/C++로 작성되었으며 라이브러리에서 네이티브로 컴파일된다는 것입니다. 이는 곧 델파이와 같은 네이티브 컴파일 언어가 API들과 직접적으로 연결될 수 있음을 의미합니다. 마샬링(marshaling) 과정이 필요가 없죠.
전통적인 윈도우 API 활용하기
윈도우 API 호출은 이미 델파이에서 제공하는 변환된 해더의 함수들이 있어 굉장히 간단합니다. 그리고 여러 방법으로 호출할 수 있습니다.
예를 들어, MessageBox를 호출한다고 하면, Winapi.Windows 유닛에는 아래와 같이 선언되어 있습니다:
function MessageBox(hWnd: HWND; lpText, lpCaption: LPCWSTR; uType: UINT): Integer; stdcall;
그리고, 그것은 시스템 DLL의 외부 함수로 선언됩니다.
function MessageBox; external user32 name 'MessageBoxW';
user32는 다음과 같이 선언:
const user32 = 'user32.dll';
일반적인 함수를 호출할 때 처럼 바로 호출할 수도 있습니다:
procedure TFormCallAPI.btnStandardClick(Sender: TObject);begin
MessageBox (0, 'Some text here', 'Caption', MB_OK);
end;
이렇게 하면, 프로그램이 시작되고 라이브러리가 로드되는 순간에 DLL의 익스포트 테이블 항목과 일치하는 임포트 테이블에 항목이 생성됩니다. 즉, 실행과 동시에 연결(linking)되는 것입니다. 실행하고자 하는 시점에 라이브러리를 로드하고 기능에 바인딩할 수도 있습니다.
이 때는 다음과 같은 선행 절차가 필요합니다:
type TMessageBoxCall = function (hWnd: HWND; lpText, lpCaption: PWideChar; uType: UINT): Integer; stdcall;
그리고 다음의 코드를 작성하면 됩니다:
로딩을 지연시킬 수도 있습니다. 이 경우 선언 후 딜레이 키워드를 사용해야 합니다.
예를 들어, 최신 API들을 추가하면,
function WindowFromPhysicalPoint; external user32 name 'WindowFromPhysicalPoint' delayed;
코드를 작성할 때, 변경할 필요없이 표준 호출 방법대로 작성하면 됩니다.
if CheckWin32Version (6, 0) then
hwnd1 := WindowFromPhysicalPoint (aPoint);
전체 데모는 다음 링크를 참고하세요:
COM & Shell 인터페이스 활용하기
COM을 활용하는 것은 수준급의 영역이지만, 델파이에서는 매우 간단합니다. COM이 예전만큼 많이 사용되지 않더라도, 여전히 윈도우 Shell과 데스크탑을 활용하는 분야에서는 가장 기본적인 방식입니다.
Winapi.ShellObj 유닛을 열면 윈도우 Shell 용 수많은 COM 인터페이스 선언들을 확인할 수 있습니다. 그 중 일부는 아래를 통해서도 확인할 수 있습니다 - 유닛 인터페이스 부분은 무료 14,000줄이네요!
데모 소스코드를 통해 Shell API를 심층적으로 다룰 수 있는 컴포넌트인 TJumpList 활용 방법을 알아볼 수 있습니다.
WinRT 활용하기
WinRT는 네이티브 라이브러리로, COM과 비교자면 시스템과 메모리 관리 모델 유형은 다릅니다. 하지만 바이너리 인터페이스 (그리고 VTable) 모델을 공유하고 있습니다. 그래서 WinRT 인터페이스는 델파이 인터페이스와 자연스럽게 맵핑할 수 있습니다.
WinRT 인터페이스는 델파이 선언에 맵핑하면 다음과 같은 형태로 보여집니다:
이 시스템은 인스턴스를 생성하는데 사용되는 IToastNotificationFactory를 정의하고 있으며, 고유한 문자열을 표시해줍니다 - 레지스트리와 GUID들 사용을 대체 - 일명 'Windows.UI.Notification.ToastNotification'입니다. 델파이는 간편하게 사용할 수 있는 클래스 TToastNotification을 다음과 같이 활용할 수 있습니다:
윈도우 10에서 알림을 표시하는데 필요한 핵심 코드입니다. 데모는 다음 링크를 참고하세요 (낮은 레벨의 WinRT API 버전과 사용하기 쉬운 컴포넌트 기반 예제 모두 제공):
- https://github.com/marcocantu/DelphiSessions/tree/master/Win10Session/WinRTDirect
- https://github.com/marcocantu/DelphiSessions/tree/master/Win10Session/Windows%2010%20Notifications
결론
보다 많은 정보는 아래 정리한 링크를 통해 확인할 수 있습니다. 위의 내용 뿐 아니라 VCL에서 핵심 API을 지속 확장 지원하는 방법을 설명한 데모도 확인할 수 있습니다.
- 온라인 세미나 다시보기: https://community.idera.com/developer-tools/b/blog/posts/windows-10-modernize-webinar-series#replays
- 원문 (마르코 칸투 블로그 - 영문): https://community.idera.com/developer-tools/b/blog/posts/a-tale-of-3-apis-vcl-integration-with-winapi-com-shellapi-winrt