Visual Studio 2017 Visual C++ による ATL デスクトップアプリの作成

#はじめに
ATL を使ってもデスクトップアプリを作成できます。本来は COM サーバを作成するための機能ですが、COM インターフェースを実装しなければ、普通のデスクトップアプリになります。

#プロジェクトの作成
「新しいプロジェクト」ダイアログで「ATL プロジェクト」を選び OK ボタンをクリックします。

![VCProj_ATLServer.png](https://qiita-image-store.s3.amazonaws.com/0/62802/dedd1e0a-b14c-64f2-7bdc-18ddbe8944fd.png)
Fig.1 新しいプロジェクト


Fig.2 のようなダイアログが開くので、「アプリケーションの種類」を「実行可能ファイル (.exe)」を選んで OK ボタンをクリックします。

ソリューションエクスプローラに新しいプロジェクトが追加されます。


![VCProj_ATLServer2.png](https://qiita-image-store.s3.amazonaws.com/0/62802/702d3732-1da3-c2d3-9b1e-37bbd7d80bb4.png)
Fig.2 ATL プロジェクト

#画面の作成
プロジェクトを選択して、コンテキストメニュー「追加」/「新しい項目」を実行する。ATL の項目から「ATL ダイアログ」を選択して「追加」ボタンをクリックします。

![ATLServer2_Dialog.png](https://qiita-image-store.s3.amazonaws.com/0/62802/2ebb554d-ae0e-8d2a-c9ea-a76579ec79ac.png)
Fig.3 新しい項目の追加

Fig.4 のようなダイアログが開くので、「短い名前」を入力します。これはダイアログのクラス名やファイル名の元になります。

![ATLServer2_Dialog2.png](https://qiita-image-store.s3.amazonaws.com/0/62802/00eab40c-3602-15df-af48-06c134d5652a.png)
Fig.4 名前の設定

プロジェクトのリソースビューで、ツリーを展開して Dialog の中の "IDD_..." をダブルクリックしてダイアログのデザイン画面を開きます。

ここで、必要なコントロールをダイアログに貼り付けてデザインを行います。

![ATLServer2_Dialog3.png](https://qiita-image-store.s3.amazonaws.com/0/62802/1dedf386-b09c-9f73-f71f-fe6e8ddf6ef1.png)
Fig.5 ダイアログのデザイン

##Visual Studio のバグ(?) 対応
ビルドを行うと、次のようなエラーが発生することがあるが、これは Visual Studio のバグでリソースファイル名に余分な空白が含まれているためである。

> RC2135 file not found: xxxxxx.tlb

リソースファイルをコードで開き、エラーメッセージの xxxxxx (ファイル名の拡張子を除いた部分) を検索して、余分な空白を手動で削除します。それから、ビルドしなおし、エラーが消えることを確認します。


実行するとダイアログの OK ボタンとキャンセルボタンをクリックするとエラーが発生します。これは、このダイアログがモーダルでないにも関わらず、モーダルダイアログとして閉じるようになっているためです。

ダイアログのヘッダーファイル (この例では Server2Dlg.h) を開いて、コードの最後の方にある OK ボタンとキャンセルボタンのハンドラを修正します。これは "EndDialog(wID)" をコメントアウトし、代わりに "DestroyWindow()"を追加します。


##_tWinMain へのコード追加
デフォルトだと、ダイアログを作成して表示するコードがないので、これを追加しないと何も表示されません。次のコードは、ATLServer2.cpp のコード例です。

```C++
// ATLServer2.cpp : WinMain の実装

#include "stdafx.h"
#include "resource.h"
#include "ATLServer2_i.h"
#include "Server2Dlg.h"  // 追加

using namespace ATL;

class CATLServer2Module : public ATL::CAtlExeModuleT< CATLServer2Module >
{
public :
	DECLARE_LIBID(LIBID_ATLServer2Lib)
	DECLARE_REGISTRY_APPID_RESOURCEID(IDR_ATLSERVER2, "{b0f20685-a805-41b9-b28b-ab076b2375d6}")
};

CATLServer2Module _AtlModule;

//  Window メイン
extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/,
								LPTSTR /*lpCmdLine*/, int nShowCmd)
{
	// ダイアログを表示するためのコード
	MSG msg;
	CServer2Dlg dlg;
	dlg.Create(NULL);
	dlg.ShowWindow(nShowCmd);

	while (GetMessage(&msg, 0, 0, 0))
		DispatchMessage(&msg);
	// ここまで
	return _AtlModule.WinMain(nShowCmd);
}
```

次の画像は、このサンプルプログラムの実行例です。コントロールは Static (Label 相当) だけ貼り付けてあります。

![AxServer1.png](https://qiita-image-store.s3.amazonaws.com/0/62802/8e765206-55c2-20bf-9457-310e243787ae.png)
Fig.6 このサンプルの実行例

#COM インターフェースの実装
COM インターフェースを実装すれば、COM サーバとして動作するはずです。

ソリューションエクスプローラでこのプロジェクトを選択し、コンテキストメニューの「追加」から「新しい項目の追加」ダイアログを開き、 「ATL シンプルオブジェクト」を選んで「追加」ボタンをクリックします。

![ATLServer2_SimpleObject.png](https://qiita-image-store.s3.amazonaws.com/0/62802/121bf517-e822-5a6c-5c8e-20e4759d46c5.png)
Fig.7 新しい項目の追加

COM DLL の場合と同じ要領で、プロパティやメソッドを実装します。コード編集が終わったら、ビルドを行います。エラーがなくなったらできあがった exe ファイルと tlb ファイルを適切なフォルダへコピーして、レジストリに登録します。

レジストリ登録は regsvr32 でなく、自分自身で行います。コマンドプロンプトを管理者モードで起動し、スイッチ /RegServer を付けて実行することで登録が行われます。下に例を示します。

> C:\> AxServer1.exe /RegServer


(参考) /UnRegServer を付けて実行すると登録が解除されます。


実際に COM インターフェースを実装して、テストしてみたところ起動が非常に遅かったです。メソッドの呼び出しもうまくいきませんでした。もしかしたら、COM DLL の場合と異なりマーシャリングを手動で行わないといけないのかもしれません。(別プロセスのため)