OLD | NEW |
| (Empty) |
1 // Copyright 2005-2009 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 // | |
16 // Extension to DECLARE_REGISTRY_RESOURCEID that makes adding stuff to | |
17 // your reg file as simple as using an atl macro map. | |
18 // | |
19 // Adapted from http://thecodeproject.com/atl/RegistryMap.asp | |
20 /* | |
21 * Defines a 'registry' map for adding variables to rgs files. | |
22 * Original Code Copyright 2001-2003 Michael Geddes. All rights reserved. | |
23 * Modified Code Copyright 2005 Google Inc. | |
24 */ | |
25 | |
26 /* use this as your RGS file -- remove or add parameters as you see fit | |
27 // | |
28 // The ATL registrar requires single quotes to be escaped in substitution data | |
29 // enclosed in single quotes in the RGS file. Since the registry map is not | |
30 // aware of which data fields are quoted, to err on the side of caution, all | |
31 // _ATL_REGMAP_ENTRYKeeper constructors escape szData. It is also important to | |
32 // enclose all substitutions in RGS files in single quotes, as shown in the | |
33 // example here: | |
34 | |
35 HKCR | |
36 { | |
37 '%PROGID%.%VERSION%' = s '%DESCRIPTION%' | |
38 { | |
39 CLSID = s '%CLSID%' | |
40 } | |
41 '%PROGID%' = s '%DESCRIPTION%' | |
42 { | |
43 CLSID = s '%CLSID%' | |
44 CurVer = s '%PROGID%.%VERSION%' | |
45 } | |
46 NoRemove CLSID | |
47 { | |
48 ForceRemove '%CLSID%' = s '%DESCRIPTION%' | |
49 { | |
50 ProgID = s '%PROGID%.%VERSION%' | |
51 VersionIndependentProgID = s '%PROGID%' | |
52 ForceRemove 'Programmable' | |
53 InprocServer32 = s '%MODULE%' | |
54 { | |
55 val ThreadingModel = s '%THREADING%' | |
56 } | |
57 'TypeLib' = s '%LIBID%' | |
58 } | |
59 } | |
60 } | |
61 | |
62 */ | |
63 | |
64 #ifndef OMAHA_BASE_ATLREGMAPEX_H__ | |
65 #define OMAHA_BASE_ATLREGMAPEX_H__ | |
66 | |
67 #include <atlbase.h> | |
68 #include <atlconv.h> | |
69 #include <atlstr.h> | |
70 #include "omaha/base/app_util.h" | |
71 #include "omaha/base/error.h" | |
72 #include "omaha/base/path.h" | |
73 #include "omaha/base/statregex.h" | |
74 #include "omaha/base/utils.h" | |
75 | |
76 namespace omaha { | |
77 | |
78 struct _ATL_REGMAP_ENTRYKeeper : public _ATL_REGMAP_ENTRY { | |
79 // Returns a new Olestr that needs to be freed by caller. | |
80 LPCOLESTR NewKeyOlestr(LPCTSTR tstr) { | |
81 CT2COLE olestr(tstr); | |
82 int alloc_length = lstrlen(olestr) + 1; | |
83 LPOLESTR new_olestr = new OLECHAR[alloc_length]; | |
84 if (new_olestr) { | |
85 lstrcpyn(new_olestr, olestr, alloc_length); | |
86 } | |
87 return new_olestr; | |
88 } | |
89 | |
90 // Escapes single quotes and returns a new Olestr that needs to be freed by | |
91 // caller. | |
92 LPCOLESTR NewDataOlestr(LPCTSTR tstr) { | |
93 CT2COLE olestr(tstr); | |
94 | |
95 CStringW escaped_str; | |
96 int alloc_length = lstrlen(olestr) * 2 + 1; | |
97 ATL::CAtlModule::EscapeSingleQuote(CStrBufW(escaped_str, alloc_length), | |
98 alloc_length, | |
99 olestr); | |
100 | |
101 alloc_length = escaped_str.GetLength() + 1; | |
102 LPOLESTR new_escaped_str = new OLECHAR[alloc_length]; | |
103 if (new_escaped_str) { | |
104 lstrcpyn(new_escaped_str, escaped_str, alloc_length); | |
105 } | |
106 return new_escaped_str; | |
107 } | |
108 | |
109 _ATL_REGMAP_ENTRYKeeper() { | |
110 szKey = NULL; | |
111 szData = NULL; | |
112 } | |
113 | |
114 // REGMAP_ENTRY(x, y) | |
115 _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, LPCWSTR data_tstr) { | |
116 szKey = NewKeyOlestr(key_tstr); | |
117 szData = NewDataOlestr(CW2T(data_tstr)); | |
118 } | |
119 | |
120 // REGMAP_ENTRY(x, y) | |
121 _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, LPCSTR data_tstr) { | |
122 szKey = NewKeyOlestr(key_tstr); | |
123 szData = NewDataOlestr(CA2T(data_tstr)); | |
124 } | |
125 | |
126 // REGMAP_MODULE(x) | |
127 explicit _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr) { | |
128 szKey = NewKeyOlestr(key_tstr); | |
129 szData = NewDataOlestr(EnclosePathIfExe(app_util::GetCurrentModulePath())); | |
130 } | |
131 | |
132 // REGMAP_MODULE2(x, modulename) | |
133 _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, | |
134 LPCTSTR module_name_tstr, | |
135 bool /* is_relative_to_current_module */) { | |
136 szKey = NewKeyOlestr(key_tstr); | |
137 szData = NULL; | |
138 | |
139 CStringW full_module_name(app_util::GetCurrentModuleDirectory()); | |
140 full_module_name += _T("\\"); | |
141 full_module_name += module_name_tstr; | |
142 szData = NewDataOlestr(EnclosePathIfExe(full_module_name)); | |
143 } | |
144 | |
145 // REGMAP_EXE_MODULE(x) | |
146 _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, | |
147 bool /* is_current_exe_module */) { | |
148 szKey = NewKeyOlestr(key_tstr); | |
149 szData = NewDataOlestr(EnclosePathIfExe(app_util::GetModulePath(NULL))); | |
150 } | |
151 | |
152 // REGMAP_RESOURCE(x, resid) | |
153 _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, UINT resid, bool /* resource */) { | |
154 szKey = NewKeyOlestr(key_tstr); | |
155 CStringW res_name; | |
156 BOOL success = res_name.LoadString(resid); | |
157 ATLASSERT(success); | |
158 szData = NewDataOlestr(res_name); | |
159 } | |
160 | |
161 // REGMAP_UUID(x, clsid) | |
162 _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, REFGUID guid) { | |
163 szKey = NewKeyOlestr(key_tstr); | |
164 szData = NewDataOlestr(GuidToString(guid)); | |
165 } | |
166 | |
167 ~_ATL_REGMAP_ENTRYKeeper() { | |
168 delete [] szKey; | |
169 delete [] szData; | |
170 } | |
171 | |
172 // This method is mostly the same as the atlmfc_vc80 version of | |
173 // ATL::CAtlModule::UpdateRegistryFromResourceS. The only functional change | |
174 // is that it uses omaha::RegObject instead of ATL::CRegObject. | |
175 static HRESULT UpdateRegistryFromResourceEx( | |
176 UINT nResID, BOOL bRegister, struct _ATL_REGMAP_ENTRY* pMapEntries) { | |
177 RegObject ro; | |
178 HRESULT hr = ro.FinalConstruct(); | |
179 if (FAILED(hr)) { | |
180 return hr; | |
181 } | |
182 | |
183 if (pMapEntries != NULL) { | |
184 while (pMapEntries->szKey != NULL) { | |
185 ASSERT1(NULL != pMapEntries->szData); | |
186 ro.AddReplacement(pMapEntries->szKey, pMapEntries->szData); | |
187 pMapEntries++; | |
188 } | |
189 } | |
190 | |
191 hr = ATL::_pAtlModule->AddCommonRGSReplacements(&ro); | |
192 if (FAILED(hr)) { | |
193 return hr; | |
194 } | |
195 | |
196 USES_CONVERSION_EX; | |
197 TCHAR szModule[MAX_PATH]; | |
198 HINSTANCE hInst = _AtlBaseModule.GetModuleInstance(); | |
199 DWORD dwFLen = ::GetModuleFileName(hInst, szModule, MAX_PATH); | |
200 if (dwFLen == 0) { | |
201 return HRESULTFromLastError(); | |
202 } else if (dwFLen == MAX_PATH) { | |
203 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); | |
204 } | |
205 | |
206 LPOLESTR pszModule = NULL; | |
207 pszModule = T2OLE_EX(szModule, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); | |
208 OLECHAR pszModuleUnquoted[_MAX_PATH * 2]; // NOLINT | |
209 ATL::CAtlModule::EscapeSingleQuote(pszModuleUnquoted, | |
210 _countof(pszModuleUnquoted), | |
211 pszModule); | |
212 | |
213 HRESULT hRes; | |
214 if ((hInst == NULL) || (hInst == GetModuleHandle(NULL))) { | |
215 // If Registering as an EXE, then we quote the resultant path. | |
216 // We don't do it for a DLL, because LoadLibrary fails if the path is | |
217 // quoted | |
218 OLECHAR pszModuleQuote[(_MAX_PATH + _ATL_QUOTES_SPACE) * 2]; // NOLINT | |
219 pszModuleQuote[0] = OLESTR('\"'); | |
220 if (!ocscpy_s(pszModuleQuote + 1, (_MAX_PATH + _ATL_QUOTES_SPACE) * 2 - 1, | |
221 pszModuleUnquoted)) { | |
222 return E_FAIL; | |
223 } | |
224 | |
225 size_t nLen = ocslen(pszModuleQuote); | |
226 pszModuleQuote[nLen] = OLESTR('\"'); | |
227 pszModuleQuote[nLen + 1] = 0; | |
228 | |
229 hRes = ro.AddReplacement(OLESTR("Module"), pszModuleQuote); | |
230 } else { | |
231 hRes = ro.AddReplacement(OLESTR("Module"), pszModuleUnquoted); | |
232 } | |
233 | |
234 if (FAILED(hRes)) { | |
235 return hRes; | |
236 } | |
237 | |
238 hRes = ro.AddReplacement(OLESTR("Module_Raw"), pszModuleUnquoted); | |
239 if (FAILED(hRes)) { | |
240 return hRes; | |
241 } | |
242 | |
243 LPCOLESTR szType = OLESTR("REGISTRY"); | |
244 hr = bRegister ? ro.ResourceRegister(pszModule, nResID, szType) : | |
245 ro.ResourceUnregister(pszModule, nResID, szType); | |
246 return hr; | |
247 } | |
248 }; | |
249 | |
250 // This now supports DECLARE_OLEMISC_STATUS() | |
251 #define BEGIN_REGISTRY_MAP() \ | |
252 __if_exists(_GetMiscStatus) { \ | |
253 static LPCTSTR _GetMiscStatusString() { \ | |
254 static TCHAR misc_string[32] = {0} \ | |
255 if (!misc_string[0]) { \ | |
256 wsprintf(misc_string, _T("%d"), _GetMiscStatus()); \ | |
257 } \ | |
258 \ | |
259 return misc_string; \ | |
260 } \ | |
261 } \ | |
262 \ | |
263 static struct _ATL_REGMAP_ENTRY *_GetRegistryMap() { \ | |
264 static const _ATL_REGMAP_ENTRYKeeper map[] = { \ | |
265 __if_exists(_GetMiscStatusString) { \ | |
266 _ATL_REGMAP_ENTRYKeeper(_T("OLEMISC"), _GetMiscStatusString()), \ | |
267 } \ | |
268 __if_exists(GetAppIdT) { \ | |
269 _ATL_REGMAP_ENTRYKeeper(_T("APPID"), GetAppIdT()), \ | |
270 } \ | |
271 | |
272 #define REGMAP_ENTRY(x, y) _ATL_REGMAP_ENTRYKeeper((x), (y)), | |
273 | |
274 #define REGMAP_RESOURCE(x, resid) _ATL_REGMAP_ENTRYKeeper((x), (resid), true), | |
275 | |
276 #define REGMAP_UUID(x, clsid) _ATL_REGMAP_ENTRYKeeper((x), (clsid)), | |
277 | |
278 // Add in an entry with key x, and value being the current module path. | |
279 // For example, REGMAP_MODULE("foo"), with the current module being | |
280 // "goopdate.dll" will result in the entry: | |
281 // "foo", "{blah}\\Google\\Update\\1.2.71.7\\goopdate.dll" | |
282 #define REGMAP_MODULE(x) _ATL_REGMAP_ENTRYKeeper((x)), | |
283 | |
284 // Add in an entry with key x, and value being modulename, fully qualified with | |
285 // the current module path. For example, REGMAP_MODULE2("foo", "npClick7.dll") | |
286 // with the current module being "goopdate.dll" will result in the entry: | |
287 // "foo", "{blah}\\Google\\Update\\1.2.71.7\\npClick7.dll" | |
288 #define REGMAP_MODULE2(x, modulename) \ | |
289 _ATL_REGMAP_ENTRYKeeper((x), (modulename), true), | |
290 | |
291 // Add in an entry with key x, and value being the currently running EXE's | |
292 // module path. For example, REGMAP_EXE_MODULE("foo"), with the current process | |
293 // being googleupdate.exe will result in the entry: | |
294 // "foo", "{blah}\\Google\\Update\\googleupdate.exe" | |
295 #define REGMAP_EXE_MODULE(x) _ATL_REGMAP_ENTRYKeeper((x), true), | |
296 | |
297 #define END_REGISTRY_MAP() _ATL_REGMAP_ENTRYKeeper() \ | |
298 }; \ | |
299 return (_ATL_REGMAP_ENTRY *)map; /* NOLINT */ \ | |
300 } | |
301 | |
302 #define DECLARE_REGISTRY_RESOURCEID_EX(x) \ | |
303 static HRESULT WINAPI UpdateRegistry(BOOL reg) { \ | |
304 return _ATL_REGMAP_ENTRYKeeper::UpdateRegistryFromResourceEx( \ | |
305 (UINT)(x), (reg), _GetRegistryMap()); \ | |
306 } | |
307 | |
308 #define DECLARE_REGISTRY_APPID_RESOURCEID_EX(resid, appid) \ | |
309 static LPCOLESTR GetAppId() throw() { \ | |
310 static const CStringW app_id(appid); \ | |
311 return app_id; \ | |
312 } \ | |
313 static LPCTSTR GetAppIdT() throw() { \ | |
314 return GetAppId(); \ | |
315 } \ | |
316 static HRESULT WINAPI UpdateRegistryAppId(BOOL reg) throw() { \ | |
317 return _ATL_REGMAP_ENTRYKeeper::UpdateRegistryFromResourceEx( \ | |
318 resid, (reg), _GetRegistryMap()); \ | |
319 } | |
320 // END registry map | |
321 | |
322 } // namespace omaha | |
323 | |
324 #endif // OMAHA_BASE_ATLREGMAPEX_H__ | |
325 | |
OLD | NEW |