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 }