CE Setup DLL のソースコード(C++ / MoonClockのソースコードより)
001 // MClockSetup.cpp : DLL アプリケーションのエントリ ポイントを定義します。
002 //
003
004 #include "stdafx.h"
005
006 #include <ce_setup.h>
007 #include "resource.h"
008
009 namespace
010 {
011 HINSTANCE m_hinstModule;
012
013 const LPCTSTR MoonClockKey = _T("Software\\Microsoft\\Today\\Items\\MoonClock");
014 const UINT MessageWaitTime = 7000;
015
016 //////////////////////////////////////////////////////////////////////////////////////////////
017 // 指定アイテムが有効(表示中)か調べる
018 // note:
019 // 引数でレジストリキーを受け取っているのは、将来、MoonClock以外のアイテムの状況を見て処理を
020 // 変えたり出来るようにだ。(例えば、特定のプラグインが有効の場合はインストールしないとか)
021 //////////////////////////////////////////////////////////////////////////////////////////////
022 bool IsItemEnabled(LPCTSTR strKey)
023 {
024 HKEY hKey;
025 bool enabled = false;
026
027 // DWORD値[Enabled]が存在し、その値が0でなければ、有効状態と判定する。
028 if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, strKey, 0, 0, &hKey) == ERROR_SUCCESS)
029 {
030 DWORD value = 0, type, length = sizeof(DWORD);
031 if (::RegQueryValueEx(hKey, _T("Enabled"), 0, &type, reinterpret_cast<BYTE *>(&value), &length) == ERROR_SUCCESS)
032 {
033 enabled = (type == REG_DWORD && length == sizeof(DWORD) && value != 0);
034 }
035
036 ::RegCloseKey(hKey);
037 }
038
039 return enabled;
040 }
041
042
043 //////////////////////////////////////////////////////////////////////////////////////////////
044 // MoonClockを無効化する
045 //////////////////////////////////////////////////////////////////////////////////////////////
046 bool DisableMoonClock(HWND hwndParent)
047 {
048 HKEY hKey;
049 if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, MoonClockKey, 0, 0, &hKey) != ERROR_SUCCESS)
050 {
051 return false;
052 }
053
054 // 1)まず、このプラグインを無効化するように、Enabled=0をレジストリを設定する。
055 DWORD enabled = 0;
056 LONG error = ::RegSetValueEx(hKey, _T("Enabled"), 0, REG_DWORD, reinterpret_cast<BYTE *>(&enabled), sizeof(DWORD));
057 ::RegCloseKey(hKey);
058 if (error != ERROR_SUCCESS)
059 {
060 return false;
061 }
062
063 // 2)それを反映させてToday画面から消去させるために、メッセージをToday画面に送る
064 DWORD msgResult;
065 LRESULT result = ::SendMessageTimeout(::GetDesktopWindow(), WM_SETTINGCHANGE, 0xF2, 0, SMTO_NORMAL, MessageWaitTime, &msgResult);
066
067 return result != 0;
068 }
069
070
071 //////////////////////////////////////////////////////////////////////////////////////////////
072 // MoonClockの設定を削除する
073 //////////////////////////////////////////////////////////////////////////////////////////////
074 void DeleteSettings(HWND hwndParent)
075 {
076 // まずは、MoonClockキーが存在することを確認
077 HKEY hKeyMoonClock;
078 if (::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Zorac\\MoonClock"), 0, 0, &hKeyMoonClock) == ERROR_SUCCESS)
079 {
080 ::RegCloseKey(hKeyMoonClock);
081
082 // ユーザーに、設定を消し去るか、問い合わせる。
083 TCHAR buf[256];
084 ::LoadString(m_hinstModule, IDS_MSG_DELETESETTINGS, buf, sizeof(buf) / sizeof(buf[0]));
085 if (::MessageBox(hwndParent, buf, _T("MoonClock"), MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2) == IDYES)
086 {
087 HKEY hKeyZorac;
088 if (::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Zorac"), 0, 0, &hKeyZorac) == ERROR_SUCCESS)
089 {
090 // Zoracキー配下には、今後作成するアプリのサブキーも置くまとめて予定だ。なので、状況を調べて消すべきものを決める。
091 DWORD nSubKeys, nValues;
092 LONG queryResult = ::RegQueryInfoKey(hKeyZorac, NULL, NULL, NULL, &nSubKeys, NULL, NULL, &nValues, NULL, NULL, NULL, NULL);
093 if (queryResult != ERROR_SUCCESS || nSubKeys > 1 || nValues > 0)
094 {
095 // ここに来るのは、以下のいずれかの場合だ。
096 // 1.Zorac直下の情報が取れなかった(=何があるのかわからない)
097 // 2.Zorac直下にサブキーが複数ある(=MoonClock以外のサブキーがある)
098 // 3.Zorac直下に値がある
099 // この場合は、MoonClockだけを消して、Zoracは残す
100 ::RegDeleteKey(hKeyZorac, _T("MoonClock"));
101 ::RegCloseKey(hKeyZorac);
102 }
103 else
104 {
105 // Zorac直下のサブキーが1つだけ(=MoonClockしかない)なら、Zoracそのものを消す
106 ::RegCloseKey(hKeyZorac);
107 HKEY hKeySoftware;
108 if (::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software"), 0, 0, &hKeySoftware) == ERROR_SUCCESS)
109 {
110 ::RegDeleteKey(hKeySoftware, _T("Zorac"));
111 ::RegCloseKey(hKeySoftware);
112 }
113 }
114 }
115 }
116 }
117 }
118
119 } // namespace
120
121
122 //////////////////////////////////////////////////////////////////////////////////////////////////
123 // DLLエントリポイント
124 //////////////////////////////////////////////////////////////////////////////////////////////////
125 BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
126 {
127 switch (ul_reason_for_call)
128 {
129 case DLL_PROCESS_ATTACH:
130 m_hinstModule = (HINSTANCE)hModule;
131 break;
132 case DLL_THREAD_ATTACH:
133 case DLL_THREAD_DETACH:
134 case DLL_PROCESS_DETACH:
135 break;
136 }
137
138 return TRUE;
139 }
140
141
142 //////////////////////////////////////////////////////////////////////////////////////////////////
143 // インストール前処理(インストーラから呼び出される)
144 //////////////////////////////////////////////////////////////////////////////////////////////////
145 codeINSTALL_INIT Install_Init(HWND hwndParent, BOOL fFirstCall, BOOL fPreviouslyInstalled, LPCTSTR pszInstallDir)
146 {
147 // 既存のバージョンがある場合の呼び出しシーケンスは以下の通り
148 // Install_Init(1回目)→既存バージョンアンインストール→Install_Init(2回目)
149 // ここでは、1回目だけ処理する。
150 if (fFirstCall)
151 {
152 if (IsItemEnabled(MoonClockKey))
153 {
154 // 既にMoonClockがインストールされていて、表示されている場合はここに来る。
155 // この場合は、既存バージョンを削除することになるので、それに備えて、MoonClockを無効化する。
156 // 無効化することで、dllが解放され、削除可能状態となる。
157 // 尚、無効化に失敗した場合は、手動で無効化してからやり直すようにMessageBoxで指示して終了。
158 if (!DisableMoonClock(hwndParent))
159 {
160 TCHAR buf[256];
161 ::LoadString(m_hinstModule, IDS_MSG_DISABLE_MANUALLY, buf, sizeof(buf) / sizeof(buf[0]));
162 ::MessageBox(hwndParent, buf, _T("MoonClock"), MB_OK | MB_ICONASTERISK | MB_DEFBUTTON1);
163 return codeINSTALL_INIT_CANCEL;
164 }
165
166 // 無効化から削除可能状態となるまでには、若干のタイムラグがあるかもしれない。
167 // なので、念のために1秒待って、削除可能状態としてからこの処理を抜ける。
168 // (この後は、『既存のバージョンを消すか?』問い合わせ画面なので、待たなくても大丈夫なはずだが)
169 ::Sleep(1000);
170 }
171 }
172
173 return codeINSTALL_INIT_CONTINUE;
174 }
175
176
177 //////////////////////////////////////////////////////////////////////////////////////////////////
178 // インストール後処理(インストーラから呼び出される)
179 //////////////////////////////////////////////////////////////////////////////////////////////////
180 codeINSTALL_EXIT Install_Exit(HWND hwndParent, LPCTSTR pszInstallDir, WORD cFailedDirs, WORD cFailedFiles, WORD cFailedRegKeys, WORD cFailedRegVals, WORD cFailedShortcuts)
181 {
182 // Note.
183 // 必要に応じて、ここで、動作に必要な追加ファイル等(inifileとか)を作る。
184 // この時点で行う理由は単純明快だ。
185 // 1.既に基本的なインストールは完了している。
186 // 2.この関数では、戻り値として codeINSTALL_EXIT_UNINSTALL を返せる。
187 // 特に、codeINSTALL_EXIT_UNINSTALL を返せることが大きい。
188 // codeINSTALL_EXIT_UNINSTALL を返すと、インストーラが自動的にインストールしたものを削除してくれるからだ。
189 // 例えば、ここで重要なファイルを作ろうとして失敗したら、それの後始末だけして、codeINSTALL_EXIT_UNINSTALL
190 // を返せば、きれいサッパリってわけだ。
191
192
193 if (IsItemEnabled(MoonClockKey))
194 {
195 // MoonClockが正常にインストールされ、Enabled値が0以外であった場合はここに来る。
196 // インストールしたプラグインをToday画面に即時表示させるために、メッセージをToday画面にポストする。
197 ::PostMessage(::GetDesktopWindow(), WM_SETTINGCHANGE, 0xF2, 0);
198 }
199
200 return codeINSTALL_EXIT_DONE;
201 }
202
203
204 //////////////////////////////////////////////////////////////////////////////////////////////////
205 // アンインストール前処理(インストーラから呼び出される)
206 //////////////////////////////////////////////////////////////////////////////////////////////////
207 codeUNINSTALL_INIT Uninstall_Init(HWND hwndParent, LPCTSTR pszInstallDir)
208 {
209 if (IsItemEnabled(MoonClockKey))
210 {
211 // MoonClockが表示されている場合はここに来る。
212 // この後の削除に備えて、MoonClockを無効化する。
213 // 尚、無効化に失敗した場合は、手動で無効化してからやり直すようにMessageBoxで指示して終了。
214 if (!DisableMoonClock(hwndParent))
215 {
216 TCHAR buf[256];
217 ::LoadString(m_hinstModule, IDS_MSG_DISABLE_MANUALLY, buf, sizeof(buf) / sizeof(buf[0]));
218 ::MessageBox(hwndParent, buf, _T("MoonClock"), MB_OK | MB_ICONASTERISK | MB_DEFBUTTON1);
219 return codeUNINSTALL_INIT_CANCEL;
220 }
221
222 // 無効化から削除可能状態となるまでには、若干のタイムラグがあるかもしれない。
223 // なので、念のために1秒待って、削除可能状態としてからこの処理を抜ける。
224 ::Sleep(1000);
225 }
226
227 // 設定値保持レジストリを消すか問い合わせて消す。
228 DeleteSettings(hwndParent);
229
230 return codeUNINSTALL_INIT_CONTINUE;
231 }
232
233
234 //////////////////////////////////////////////////////////////////////////////////////////////////
235 // アンインストール後処理(インストーラから呼び出される)
236 //////////////////////////////////////////////////////////////////////////////////////////////////
237 codeUNINSTALL_EXIT Uninstall_Exit(HWND hwndParent)
238 {
239 return codeUNINSTALL_EXIT_DONE;
240 }