Windows API プログラミング

Microsoft Windowsは、C言語C++から呼び出すことができるWindows APIを提供している。Windows APIを呼び出すことにより、Microsoft Windowsが持つ機能をプログラミング言語から利用することができる。

ライブラリ

Windowsの.libファイルには、静的ライブラリとインポートライブラリの2種類の形式がある。静的ライブラリは、必要に応じて取り込まれるコードが入っていて、Linux における.aファイルに似ている。インポートライブラリは、特定の識別子が不正ではなく、DLLがロードされた時点で存在することを保証するためだけに使われる。

Windowsのバージョン情報を取得する

Win16 API GetVersion または Win32 API GetVersionEx でWindowsのバージョン情報を取得することができる。

Windowsのバージョンメジャーバージョン番号マイナーバージョン番号
Windows 3.131
Windows NT 3.535
Windows 9540
Windows NT 4.040
Windows 9841
Windows 98 SE (Second Edition)41
Windows Me (Millennium Edition)49
Windows 200050
32ビット版 Windows XP 各エディション51
Windows Server 200352
Windows XP x64 Edition52
Windows Vista60
Windows Server 200860
Windows 761

アプリケーションのバージョン情報を取得する

バージョン情報をメモリ上のプロセスから直接取得することはできません。アプリケーションのバージョン情報を取得するには,モジュールのファイルに含まれるリソースから取得します。この手順について,以下に示します。

  1. Windows API GetModuleFileNameを用いて,モジュールハンドルからモジュールのファイル名を取得する。
  2. Windows API GetFileVersionInfoSizeを用いて,ファイルからバージョン情報リソース を取得できるか判定する。
  3. Windows API GetFileVersionInfoを用いて,ファイルに関するバージョン情報リソースを取得する。
  4. Windows API VerQueryValueを用いて,バージョン情報リソースから選択したバージョン情報を取得する。
アプリケーションのバージョン情報を取得する
Figure 1. アプリケーションのバージョン情報を取得する

ドラッグ&ドロップ

ファイルのドロップの許可

アプリケーションでファイルのドロップを行えるようにするには,あらかじめファイルのドロップの受け入れ許可をしておきます。これは,Windows API の DragAcceptFiles にて行います。

アプリケーションに対してファイルのドラッグ&ドロップを行うと,ウィンドウメッセージWM_DROPFILESが通知されます。このときのwParamの値はドロップ構造体のハンドルです。

hDrop = (HANDLE)wParam;

ドロップされたファイル名の取得

ドロップされたファイルのパス名を取得するには Windows API DragQueryFileを用います。その引数として,ドロップ構造体のハンドル(ウィンドウメッセージWM_DROPFILES通知時のwParamの値)を必要とします。

ドロップされた位置の取得

ドロップされた位置を取得するには,Windows API DragQueryPointを用います。その引数として,ドロップ構造体のハンドル(ウィンドウメッセージWM_DROPFILES通知時のwParamの値)を必要とします。

ファイル名転送用のバッファ解放

ドロップされたファイルのファイル名転送用のバッファを解放するには,Windows API DragFinishを用います。その引数として,ドロップ構造体のハンドル(ウィンドウメッセージWM_DROPFILES通知時のwParamの値)を必要とします。

WM_DROPFILESクラッカー

WINDOWSX.Hで定義されているWM_DROPFILESクラッカーに関する定義を以下に示します。

関数のプロトタイプ

void Cls_OnDropFiles(HWND hwnd, HDROP hdrop);

HANDLE_WM_*マクロ

#define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) ((fn)((hwnd), (HDROP)(wParam)), 0L)

メッセージ転送マクロ

#define FORWARD_WM_DROPFILES(hwnd, hdrop, fn) (void)(fn)((hwnd), WM_DROPFILES, (WPARAM)(HDROP)(hdrop), 0L)

共有セクション

16ビットWindowsでは,DLLは自分のデータセグメントを持っています。 このデータセグメントは,DLLが必要とするすべての静的変数,グローバル変数とDLL自身のプライベートローカルヒープを収めています。DLL関数を呼び出したプロセスがどれであっても,DLLは自分のローカルヒープを使えるため,DLLローカルヒープは複数のプロセス間でのデータ共有を簡単に実現するための手段として利用できました。

しかし,Win32のDLLには,ローカルヒープが与えられません。また,DLLによって割り当てられたグローバル変数,静的変数もDLLの複数のマッピングの間では共有されません。このため,DLLの複数インスタンス間で共有するデータは,共有セクションに配置します。

Sharedという新しい独自セクションを作成して、初期化済みデータ変数をこのセクションに配置する例を次に示します。

#pragma data_seg("Shared")
TCHAR gszSystemDir[SIZE_WORK_BUF] = "";
#pragma data_seg()

そして,リンカに対して,変数を共有するセクション名をリンカのオプションスイッチで指定します。

/SECTION:<名前>,<属性>

/SECTIONのあと,:で区切って属性を変更するセクションの名前を指定します。属性として指定できるのはR(Read),W(Write),S(Shared),E(Execute)であり,複数指定できます。

Sharedセクションを読み書き可能な共有セクションとして指定する例を次に示します。

/SECTION:Shared,RWS

フォルダ内のファイルを検索する

Visual C/C++でフォルダ内のファイルを検索するには、3通りの方法がある。

  1. C言語のランタイム関数(_findfirst, _findnext, _findclose)を使う。
  2. Win32 API(FindFirstFile, FindNextFile, FindClose)を使う。
  3. MFC(CFileFind)を使う。

DestroyWindow

ウィンドウの破棄に必要な様々な終了処理を行う。そしてWM_DESTROYとWM_NCDESTROYメッセージをウィンドウに送る。

DragAcceptFiles

DragAcceptFiles関数は、ウィンドウがドロップしたファイルを受け入れるかどうかを登録する関数である。

VOID DragAcceptFiles(
    HWND hWnd,
    BOOL fAccept
);

パラメータの説明

hWnd
ドロップされたファイルを受け入れるかどうかを登録するウィンドウを指定する。
fAccept
hWndパラメータで指定されたウィンドウが、ファイルのドロップを受け入れるかどうかを指定します。ドロップされたファイルを受け入れる場合はTRUE、受け入れない場合はFALSEを指定します。

戻り値

この関数は値を返さない。

備考

fAcceptパラメータをTRUEに設定してDragAcceptFilesを呼び出したアプリケーションは、ファイルマネージャからのWM_DROPFILESメッセージを処理することができると認識されています。

DragFinish

DragFinish関数は、Windowsがアプリケーションにファイル名を転送するために確保したメモリを解放する。

VOID DragFinish(
    HDROP hDrop
);

パラメータの説明

hDrop
ドロップされたファイルを記述する構造体を識別する。このハンドルは、WM_DROPFILES メッセージの wParam パラメータから取得される。

戻り値

この関数は値を返さない。

DragQueryFile

DragQueryFile関数は、ドロップしたファイルのファイル名を取得する関数である。

UINT DragQueryFile(
    HDROP hDrop,
    UINT iFile,
    LPTSTR lpszFile,
    UINT cch
);

パラメータの説明

hDrop
ドロップしたファイルのファイル名を含む構造体を特定する。
iFile
問い合わせを行うファイルのインデックスを指定する。iFile パラメータの値が 0xFFFFFF の場合、DragQueryFile はドロップされたファイルのカウントを返します。iFileパラメータの値が0からドロップされたファイルの総数の間の場合、DragQueryFileは対応する値のファイル名をlpszFileパラメータが指すバッファにコピーします。
lpszFile
この関数が戻ったときに,ドロップされたファイルのファイル名を受け取るためのバッファを指す。このファイル名は、ヌル文字で終端する文字列である。このパラメータがNULLの場合、DragQueryFileはバッファの必要なサイズ(文字数)を返します。/dd>
cch
lpszFileバッファーのサイズを文字数で指定します。

戻り値

この関数がファイル名をバッファにコピーする場合、戻り値はコピーされた文字数であり、終端のNULL文字は含まれない。

インデックス値が 0xFFFFFF の場合は、ドロップしたファイルの数を返す。

インデックス値が0からドロップされたファイルの総数の間で、lpszFileバッファアドレスがNULLの場合、戻り値はバッファの必要サイズ(文字数)です(終端NULL文字は含まれません)。

DragQueryPoint

DragQueryPoint関数は、ファイルがドロップされたときのマウスポインタの位置を取得する関数である。

BOOL DragQueryPoint(
    HDROP hDrop,
    LPPOINT lppt
);

パラメータの説明

hDrop
ドロップされたファイルを記述する構造を特定する。
lppt
ファイルがドロップされたときのマウスポインタの座標でこの関数が埋める POINT 構造体を指します。

戻り値

ドロップがウィンドウのクライアント領域で発生した場合、戻り値は TRUE であり、そうでない場合は FALSE である。

DragQueryPoint関数は、ユーザーがマウスの左ボタンを離したときのマウスポインタの座標でPOINT構造体を埋める。座標が返されるウィンドウは、WM_DROPFILESメッセージを受信したウィンドウである。

GetFileVersionInfo

ファイルバージョン情報の取得。

BOOL GetFileVersionInfo(LPTSTR pFileName, DWORD dwHandle, DWORD dwLen, LPVOID lpData);

パラメータ

pFileName
ファイル名が格納されている領域を指すポインタを指定する。
dwHandle
ファイルバージョン情報を識別する。このパラメータには,GetFileVersionInfoSize関数が返すハンドルを指定するか,NULLを指定する。dwHandleパラメータがNULLのときは,GetFileVersionInfo関数がファイル中のバージョン情報を検索する。
dwLen
lpDataパラメータにより識別されるバッファのサイズをバイト単位で指定する。GetFileVersionInfoSize関数は,ファイルバージョン情報の保持に必要なバッファサイズを返す。バッファが小さすぎるときは,ファイルバージョン情報の大きさがバッファのサイズまで切りつめられる。
lpData
ファイルバージョン情報を受け取る領域を指すポインタを指定する。このパラメータは,後のVerQueryValue関数呼び出しのときに使われる。

戻り値

関数が正常に終了した場合は,0以外の値を返す。それ以外の場合は0を返し,ファイルが存在しないか,またはdwHandleパラメータが無効であることを示す。

GetFileVersionInfoSize

バージョン情報を取得できるか判定する。

DWORD GetFileVersionInfoSize(LPTSTR pFileName, LPDWORD lpdwHandle);

パラメータ

pFileName
ファイル名が格納されている領域をを指すポインタを指定する。
lpdwHandle
32ビット値を指すポインタ。GetFileVersionInfoSizeを実行することにより,このパラメータにはファイルバージョン情報を識別するハンドルが格納される。このハンドルはGetFileVersionInfo関数で使われる。

戻り値

関数が正常に終了した場合は,バージョン情報の保持に必要なバッファサイズをバイト単位で返す。ファイルやバージョン情報が見付からなかった場合,またはMS-DOSエラーが発生した場合は,NULLを返す。

GetModuleFileName

モジュールがロードされる実行可能ファイルの完全パスとファイル名を取得する。

DWORD GetModuleFileName(HMODULE hModule, LPTSTR pFileName, DWORD dwSize);

パラメータの説明

hModule
モジュールハンドルを指定する。
pFileName
ファイル名を受け取る領域を指すポインタを指定する。
dwSize
コピーするバイトの最大数値を,終端のNULLも含めて指定する。dwSizeよりも長いファイル名は切り捨てられる。

戻り値

関数が正常に終了した場合,戻り値は指定されたバッファにコピーされた文字列の長さをバイト単位で示す。それ以外の場合,0を返す。

GetPrivateProfileInt

.iniファイル(初期化ファイル)からInt値を読み込む。

UINT GetPrivateProfileInt(
    LPCTSTR lpAppName,
    LPCTSTR lpKeyName,
    INT     nDefault,
    LPCTSTR lpFileName
);
lpAppName
セクションの名前
lpKeyName
キーの名前
nDefault
デフォルト値。指定したキーが見つからなかったら、この値が戻り値に返る。
lpFileName
初期化ファイルのファイル名

戻り値

指定したキーに対応する値

GetPrivateProfileString

.iniファイル(初期化ファイル)からString値を読み込む。

[section]
key=value
key=value
[section]
key=value
DWORD GetPrivateProfileString(
    LPCTSTR lpAppName,
    LPCTSTR lpKeyName,
    LPCTSTR lpDefault,
    LPTSTR  lpReturnedString,
    DWORD   nSize,
    LPCTSTR lpFileName
);
lpAppName
セクションの名前
lpKeyName
キーの名前
lpDefault
デフォルト値。指定したキーが見つからなかったら、この値がlpReturnedStringに格納される。
lpReturnedString
指定したキーに対応する文字列を格納する領域
nSize
lpReturnedStringバッファのサイズ
lpFileName
初期化ファイルのファイル名

戻り値

バッファに格納された文字数

GetVersionEx

現在実行中のオペレーティングシステムのバージョンに関する拡張情報を取得する。

BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInformation);

パラメータの説明

lpVersionInformation
OSVERSIONINFO構造体へのポインタを指定する。

戻り値

成功したらTRUE、失敗したら FALSEを返す。

PostQuitMessage

PostQuitMessage()はWM_QUITメッセージをポストする。WM_QUITメッセージを受け取ると、GetMessage()はFALSEを返して、メッセージループが終了する。

通常、WM_DESTROYメッセージ対する応答としてPostQuitMessage関数を使う。

VerQueryValue

バージョン情報値の問い合わせを行う。

BOOL VerQueryValue(const LPVOID pBlock, LPTSTR lpSubBlock, LPVIOD *lplpBuffer, PUINT puLen);

パラメータの説明

pBlock
バッファを指すポインタ。バッファには,GetFileVersionInfoが返すバージョン情報リソースを指定する。
lpSubBlock
取得するバージョン情報の値を指定する,0で終わる文字列を指すポインタ。
lplpBuffer
バッファを指すポインタ。バッファには,バージョン情報値を指すポインタが格納される。
puLen
バッファを指すポインタ。バッファには,バージョン情報値の長さがバイト単位で格納される。

戻り値

指定されたブロックが存在してバージョン情報が利用できる場合は,0以外の値を返す。puLenが0の場合は,指定されたバージョン情報名に対する値を使用することができない。指定された名前が存在しない場合またはpBlockが指すリソースが無効の場合には0返す。

WritePrivateProfileString

.iniファイル(初期化ファイル)に値を書き込む。

BOOL WritePrivateProfileString(
    LPCTSTR lpAppName,
    LPCTSTR lpKeyName,
    LPCTSTR lpString,
    LPCTSTR lpFileName
);
lpAppName
セクションの名前
lpKeyName
キーの名前
lpString
指定したキーに設定する値
lpFileName
初期化ファイルのファイル名

戻り値

成功したら0以外、失敗したら0が返る。失敗した場合、GetLastErrorで情報を得ることができる。

OSVERSIONINFO

OSVERSIONINFOはOSのバージョン情報が格納されている構造体である。

構造

typedef struct _OSVERSIONINFO{
  DWORD dwOSVersionInfoSize;
  DWORD dwMajorVersion;
  DWORD dwMinorVersion;
  DWORD dwBuildNumber;
  DWORD dwPlatformId;
  TCHAR szCSDVersion[128];
} OSVERSIONINFO;

メンバの説明

dwOSVersionInfoSize
GetVersionEx関数を呼び出す前に,sizeof(OSVERSIONINFO)をセットしておかなければならない。
dwMajorVersion
ホストシステムのメジャーバージョン番号。
dwMinorVersion
ホストシステムのマイナーバージョン番号。
dwBuildNumber
カレントシステムのビルド番号。
dwPlatformId
カレントシステムがサポートするプラットフォームを識別する。
szCSDVersion
インストールされているオペレーティングシステムについての詳細な情報を提供するテキスト。

POINT

POINT構造体は、点のx座標とy座標を定義する。

typedef struct tagPOINT { // pt
    LONG x;
    LONG y;
} POINT;

メンバの説明

x
点のx座標を指定する。
y
点のy座標を指定する。

WM_CLOSE

DefWindowProc() がWM_CLOSEウィンドウメッセージを受け取ると、DestroyWindow() を呼び出す。

WM_ENDSESSION

OSのシャットダウンで閉じられようとしている。

パラメータ 説明
wParam 0:セッションが終了していないとき(WM_QUERYSESSIONでFALSEが返されたととき)
1:セッションが終了するとき
lParam 0:シャットダウンしようとしているとき
1:ログオフしようとしているとき

WM_QUERYSESSION

システムがシャットダウンしようとする際、WM_QUERYSESSIONメッセージがトップレベルウィンドウに対して送られてくる。 ここで、アプリケーションが終了できる状態であればTRUEを返す。そうでなければFALSEを返す。

WM_QUERYSESSIONメッセージに対してすべてのアプリケーションがTRUEを返した場合、システムはシャットダウンできる状態にあるとみなしてシャットダウンを続行する。 システムはすべてのトップレベルウィンドウに対してWM_ENDSESSIONメッセージを送信し、シャットダウンを会することを知らせる。 アプリケーションではこのメッセージを受信した時点で終了処理を行わなければならない。

WM_SYSCOMMAND

m.WParam.ToInto32() == SC_CLOSE

×ボタン、コントロールメニューの「閉じる」、コントロールボックスのダブルクリック、Alt + F4 などにより閉じられようとしている。

DefWindowProc() がこれを受け取ると、ウィンドウプロシージャにWM_CLOSEを送る。

.NETプログラミング

マネージドC

マネージドCプログラムを記述する場合、特別な手続きは必要ない。

#include <stdio.h>

void main()
{
  printf("Hello world!");
}

ただし、C言語の標準ライブラリはマネージド・コードではない。したがって、C言語プログラムから標準ライブラリを呼び出した場合、マネージド・コードからアンマネージド・コードを呼び出すことになる。

マネージド・コードからアンマネージド・コードのライブラリを呼び出す

マネージド・コードからアンマネージド・コードのライブラリを呼び出すには、PInvoke (Platform Invocation) と呼ばれるサービスを利用する。PInvokeサービスを使用してアンマネージド・コードのライブラリを呼び出すには、System.Runtime.InteropServices.DllImport属性を使用して、呼び出す関数を宣言する。

[System.Runtime.InteropServices.DllImport("ライブラリ名")]
関数の宣言

あらかじめSystem.Runtime.InteropServicesネームスペースの使用を宣言しておけば、名前空間を明示的に修飾しなくともよい。

using System.Runtime.InteropServices;
.
.
.
[DllImport("ライブラリ名")]
関数の宣言

Win32 APIのライブラリ user32.dll はアンマネージド・コードである。マネージドC++プログラムからWin32 API (MessageBoxA) を呼び出す例を示す。

using System;

class HelloWorld {
  [System.Runtime.InteropServices.DllImport("user32.dll")]
  public static extern int
  MessageBoxA(int hWnd, String lpText, String lpCaption, uint uType);

  static void Main() {
      MessageBoxA(0, "Hello World!", "sample", 0);
  }
}

または

using System;
using System.Runtime.InteropServices;

class HelloWorld {
  [DllImport("user32.dll")]
  public static extern int
  MessageBoxA(int hWnd, String lpText, String lpCaption, uint uType);

  static void Main() {
      MessageBoxA(0, "Hello World!", "sample", 0);
  }
}