[Win32] [C++] 独自のコントロールパネル アプリケーションを作る

IP アドレスの設定ををするときに、[ファイルを名を指定して実行] から ncpa.cpl を実行して、ネットワーク接続の一覧を開いている人は多いかと思います。%systemroot%\system32 フォルダには control.exe というプログラムがあり、こいつがコントロールパネルの正体なわけですが、cpl ファイルは control.exe に読み込まれるファイルなんだろう、と適当に考えていました。

しかし、偶々 cpl ファイルについて書かれたウェブサイトを見て、これが DLL ということを知りました。独自ダイアログボックスを持つ適当なコントロールパネル アプリケーション (「日付と時刻」など) を実行し、タスク マネージャーからプロセスを見てみると、rundll32.exe が動いています。ncpa.cpl は独自のダイアログボックスを持たず、シェルに統合されているようなので、explorer.exe からロードされます。

とりあえず作ってみようということで、簡単なコントロールパネル アプリケーションを作ってみました。MSDN にサンプルがあったので、それをもっとシンプルに書き換えました。これで十分動きます。リソースは、IDI_ICON1 というアイコンと IDD_DIALOG1 というダイアログを追加しただけです。

http://msdn.microsoft.com/en-us/library/ms914264.aspx

//
// main.cpp
//

#include <Windows.h>
#include <Cpl.h>
#include <strsafe.h>

#include "resource.h"

#define DLLEXPORT __declspec(dllexport)
#define DLLIMPORT __declspec(dllimport)

HINSTANCE g_hDll= NULL;

const WCHAR g_CplTitle[]= L"MyCPL";
const WCHAR g_CplInfo[]= L"Hello";

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
    switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
        g_hDll= hModule;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

INT_PTR CALLBACK DlgProc(HWND hWnd, UINT msg, WPARAM w, LPARAM l) {
    switch ( msg ) {
    case WM_INITDIALOG:
        return TRUE;
        break;
    case WM_COMMAND:
        if ( w==IDOK || w==IDCANCEL ) {
            EndDialog(hWnd, w);
        }
        break;
    }
    return 0;
}

LONG CALLBACK CPlApplet(HWND hwndCPL, UINT message, LPARAM lParam1, LPARAM lParam2) {
    switch (message) {
    case CPL_INIT:
        // Perform global initializations, especially memory
        // allocations, here.
        // Return 1 for success or 0 for failure.
        // Control Panel does not load if failure is returned.

        return 1;

    case CPL_GETCOUNT:
        // The number of actions supported by this Control
        // Panel application.

        return 1;

    case CPL_NEWINQUIRE:
        // This message is sent once for each dialog box, as
        // determined by the value returned from CPL_GETCOUNT.
        // lParam1 is the 0-based index of the dialog box.
        // lParam2 is a pointer to the NEWCPLINFO structure.

        if ( lParam2 ) {
            NEWCPLINFO *pNewCpl= (NEWCPLINFO*)lParam2;
            pNewCpl->dwSize = sizeof(NEWCPLINFO);
            pNewCpl->dwFlags = 0;
            pNewCpl->dwHelpContext = 0;
            pNewCpl->lData = 0; // user-defined

            // The large icon for this application. Do not free this
            // HICON; it is freed by the Control Panel infrastructure.

            pNewCpl->hIcon = LoadIcon(g_hDll, MAKEINTRESOURCE(IDI_ICON1));
           
            StringCbCopy(
              pNewCpl->szName, sizeof(pNewCpl->szName), g_CplTitle);
            StringCbCopy(
              pNewCpl->szInfo, sizeof(pNewCpl->szInfo), g_CplInfo);
            pNewCpl->szHelpFile[0]= 0;

            return 0;
        }
        return 1;  // Nonzero value means CPlApplet failed.

    case CPL_DBLCLK:
        // The user has double-clicked the icon for the
        // dialog box in lParam1 (zero-based).

        DialogBox(g_hDll, MAKEINTRESOURCE(IDD_DIALOG1), hwndCPL, DlgProc);
        return 0;

    case CPL_STOP: // Called once for each dialog box. Used for cleanup.
    case CPL_EXIT: // Called only once for the application. Used for cleanup.
    default:
        return 0;
    }

    return 1;  // CPlApplet failed. (norun)
}

エクスポートする関数は一つだけですが、定義ファイルでエクスポート。序数はつけてもつけなくても OK。

;
; mycpl.def
;

LIBRARY mycpl
EXPORTS
    CPlApplet    @100

ビルドすると DLL ファイルができるので、拡張子を cpl に変更して system32 フォルダに放り込んでおけば、次回起動時にコントロールパネルに表示されます。

image

ダブルクリックするとダイアログが開きます。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。