1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #ifdef _MSC_VER
25 #pragma warning(push, 1) /* disable warnings within system headers */
26 #endif
27 #define WIN32_LEAN_AND_MEAN
28 #include <windows.h>
29 #include <msiquery.h>
30 #ifdef _MSC_VER
31 #pragma warning(pop)
32 #endif
33
34 #include <malloc.h>
35 #include <string>
36 #include <strsafe.h>
37
38 //----------------------------------------------------------
39 static const CHAR* g_Extensions[] =
40 {
41 ".doc", // Microsoft Word Text [0]
42 ".dot", // Microsoft Word Template
43 ".rtf", // RTF text
44 ".docx", // Office Word 2007 XML document
45 ".docm", // Office Word 2007 XML macro-enabled document
46 ".dotx", // Office Word 2007 XML template
47 ".dotm", // Office Word 2007 XML macro-enabled template
48 ".xlw", // Microsoft Excel
49 ".xls", // Microsoft Excel
50 ".xlt", // Microsoft Excel Template
51 ".xlsx", // Office Excel 2007 XML workbook
52 ".xlsm", // Office Excel 2007 XML macro-enabled workbook
53 ".xltx", // Office Excel 2007 XML template
54 ".xltm", // Office Excel 2007 XML macro-enabled template
55 ".xlsb", // Office Excel 2007 binary workbook (BIFF12)
56 ".ppt", // Microsoft PowerPoint
57 ".pps", // Microsoft PowerPoint
58 ".pot", // Microsoft PowerPoint Template
59 ".pptx", // Office PowerPoint 2007 XML presentation
60 ".pptm", // Office PowerPoint 2007 macro-enabled XML presentation
61 ".potx", // Office PowerPoint 2007 XML template
62 ".potm", // Office PowerPoint 2007 macro-enabled XML template
63 ".ppsx", // Office PowerPoint 2007 XML show
64 0
65 };
66
67 static const int WORD_START = 0;
68 static const int EXCEL_START = 7;
69 static const int POWERPOINT_START = 15;
70 static const int POWERPOINT_END = 23;
71
72 // ".xlam", // Office Excel 2007 XML macro-enabled add-in
73 // ".ppam", // Office PowerPoint 2007 macro-enabled XML add-in
74 // ".ppsm", // Office PowerPoint 2007 macro-enabled XML show
75
76 //----------------------------------------------------------
77 #ifdef DEBUG
OutputDebugStringFormat(LPCSTR pFormat,...)78 inline void OutputDebugStringFormat( LPCSTR pFormat, ... )
79 {
80 CHAR buffer[1024];
81 va_list args;
82
83 va_start( args, pFormat );
84 StringCchVPrintfA( buffer, sizeof(buffer), pFormat, args );
85 OutputDebugStringA( buffer );
86 }
87 #else
OutputDebugStringFormat(LPCSTR,...)88 static inline void OutputDebugStringFormat( LPCSTR, ... )
89 {
90 }
91 #endif
92
93 //----------------------------------------------------------
CheckExtensionInRegistry(LPCSTR lpSubKey)94 static BOOL CheckExtensionInRegistry( LPCSTR lpSubKey )
95 {
96 BOOL bRet = false;
97 HKEY hKey = NULL;
98 LONG lResult = RegOpenKeyExA( HKEY_CLASSES_ROOT, lpSubKey, 0, KEY_QUERY_VALUE, &hKey );
99
100 if ( ERROR_SUCCESS == lResult )
101 {
102 CHAR szBuffer[1024];
103 DWORD nSize = sizeof( szBuffer );
104
105 lResult = RegQueryValueExA( hKey, "", NULL, NULL, (LPBYTE)szBuffer, &nSize );
106 if ( ERROR_SUCCESS == lResult )
107 {
108 szBuffer[nSize] = '\0';
109 OutputDebugStringFormat( "Found value [%s] for key [%s].\n", szBuffer, lpSubKey );
110
111 if ( strncmp( szBuffer, "WordPad.Document.1", 18 ) == 0 )
112 { // We will replace registration for WordPad
113 bRet = true;
114 }
115 else if ( strncmp( szBuffer, "OpenOffice.org.", 15 ) == 0 )
116 { // We will replace registration for our (former) own types, too
117 bRet = true;
118 }
119 else if ( strncmp( szBuffer, "OpenOffice.", 11 ) == 0 )
120 { // We will replace registration for our own types, too
121 bRet = true;
122 }
123 else if ( strncmp( szBuffer, "ooostub.", 8 ) == 0 )
124 { // We will replace registration for ooostub, too
125 bRet = true;
126 }
127 else
128 {
129 OutputDebugStringFormat( " Checking OpenWithList of [%s].\n", lpSubKey );
130 HKEY hSubKey;
131 lResult = RegOpenKeyExA( hKey, "OpenWithList", 0, KEY_ENUMERATE_SUB_KEYS, &hSubKey );
132 if ( ERROR_SUCCESS == lResult )
133 {
134 DWORD nIndex = 0;
135 while ( ERROR_SUCCESS == lResult )
136 {
137 nSize = sizeof( szBuffer );
138 lResult = RegEnumKeyExA( hSubKey, nIndex++, szBuffer, &nSize, NULL, NULL, NULL, NULL );
139 if ( ERROR_SUCCESS == lResult )
140 {
141 OutputDebugStringFormat( " Found value [%s] in OpenWithList of [%s].\n", szBuffer, lpSubKey );
142 if ( strncmp( szBuffer, "WordPad.exe", 11 ) == 0 )
143 { // We will replace registration for WordPad
144 bRet = true;
145 }
146 else if ( nSize > 0 )
147 bRet = false;
148 }
149 }
150 }
151 else
152 {
153 OutputDebugStringFormat( " No OpenWithList found!\n" );
154 }
155 }
156 }
157 else // no default value found -> return TRUE to register for that key
158 bRet = true;
159
160 RegCloseKey( hKey );
161 }
162 else // no key found -> return TRUE to register for that key
163 bRet = true;
164
165 return bRet;
166 }
167
168 //----------------------------------------------------------
DeleteSubKeyTree(HKEY RootKey,LPCSTR lpKey)169 static LONG DeleteSubKeyTree( HKEY RootKey, LPCSTR lpKey )
170 {
171 HKEY hKey;
172 LONG rc = RegOpenKeyExA( RootKey, lpKey, 0, KEY_READ | DELETE, &hKey );
173
174 if (ERROR_SUCCESS == rc)
175 {
176 LPCSTR lpSubKey;
177 DWORD nMaxSubKeyLen;
178
179 rc = RegQueryInfoKeyA( hKey, 0, 0, 0, 0, &nMaxSubKeyLen, 0, 0, 0, 0, 0, 0 );
180 nMaxSubKeyLen++; // space for trailing '\0'
181 lpSubKey = reinterpret_cast<CHAR*>( _alloca( nMaxSubKeyLen*sizeof(CHAR) ) );
182
183 while (ERROR_SUCCESS == rc)
184 {
185 DWORD nLen = nMaxSubKeyLen;
186 rc = RegEnumKeyExA( hKey, 0, (LPSTR)lpSubKey, &nLen, 0, 0, 0, 0); // always index zero
187
188 if ( ERROR_NO_MORE_ITEMS == rc )
189 {
190 rc = RegDeleteKeyA( RootKey, lpKey );
191 if ( rc == ERROR_SUCCESS )
192 OutputDebugStringFormat( "deleted key [%s] from registry.\n", lpKey );
193 else
194 OutputDebugStringFormat( "RegDeleteKeyA %s returned %ld.\n", lpKey, rc );
195 break;
196 }
197 else if ( rc == ERROR_SUCCESS )
198 {
199 rc = DeleteSubKeyTree( hKey, lpSubKey );
200 if ( ERROR_SUCCESS != rc )
201 OutputDebugStringFormat( "RegDeleteKeyA %s returned %ld.\n", lpSubKey, rc );
202 }
203
204 }
205 RegCloseKey(hKey);
206 }
207 else
208 {
209 OutputDebugStringFormat( "RegOpenKeyExA %s returned %ld.\n", lpKey, rc );
210 }
211
212 return rc;
213 }
214
215 //----------------------------------------------------------
RemoveExtensionInRegistry(LPCSTR lpSubKey)216 static BOOL RemoveExtensionInRegistry( LPCSTR lpSubKey )
217 {
218 CHAR szBuffer[4096];
219 DWORD nSize = sizeof( szBuffer );
220 HKEY hKey = NULL;
221 HKEY hSubKey = NULL;
222 LONG lResult = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes", 0, KEY_QUERY_VALUE, &hKey );
223
224 if ( ERROR_SUCCESS == lResult )
225 {
226 lResult = RegOpenKeyExA( hKey, lpSubKey, 0, KEY_QUERY_VALUE, &hSubKey );
227
228 if ( ERROR_SUCCESS == lResult )
229 {
230 DWORD nSubKeys = 1;
231 szBuffer[0] = '\0';
232
233 // we get the value of the default key first and while we are on querying,
234 // we ask for the subkey count, too
235 lResult = RegQueryValueExA( hSubKey, "", NULL, NULL, (LPBYTE)szBuffer, &nSize );
236 if ( ERROR_SUCCESS == lResult )
237 RegQueryInfoKeyA( hSubKey, 0, 0, 0, &nSubKeys, 0, 0, 0, 0, 0, 0, 0 );
238 RegCloseKey( hSubKey );
239
240 // we will remove all key with a default value starting with ooostub but
241 // we have to be careful about MSO keys
242 if ( strncmp( szBuffer, "opendocument.", 13 ) == 0 )
243 {
244 if ( nSubKeys == 0 )
245 {
246 DeleteSubKeyTree( hKey, lpSubKey );
247 }
248 else
249 {
250 lResult = RegOpenKeyExA( hKey, lpSubKey, 0, KEY_SET_VALUE, &hSubKey );
251 if ( ERROR_SUCCESS == lResult )
252 RegDeleteValueA( hSubKey, "" );
253 else
254 OutputDebugStringFormat( "Could not open key %s for deleting: RegOpenKeyEx returned %ld.\n", lpSubKey, lResult );
255 }
256 }
257 }
258
259 RegCloseKey( hKey );
260 }
261
262 return ( ERROR_SUCCESS == lResult );
263 }
264
265 //----------------------------------------------------------
GetMsiProp(MSIHANDLE handle,LPCSTR name,std::string & value)266 bool GetMsiProp( MSIHANDLE handle, LPCSTR name, /*out*/std::string& value )
267 {
268 DWORD sz = 0;
269 LPSTR dummy = "";
270 if (MsiGetPropertyA(handle, name, dummy, &sz) == ERROR_MORE_DATA)
271 {
272 sz++;
273 DWORD nbytes = sz * sizeof(TCHAR);
274 LPSTR buff = reinterpret_cast<LPSTR>(_alloca(nbytes));
275 ZeroMemory(buff, nbytes);
276 MsiGetPropertyA(handle, name, buff, &sz);
277 value = buff;
278 return true;
279 }
280 return false;
281 }
282
283 //----------------------------------------------------------
IsSetMsiProp(MSIHANDLE handle,LPCSTR name)284 bool IsSetMsiProp( MSIHANDLE handle, LPCSTR name )
285 {
286 std::string val;
287 GetMsiProp( handle, name, val );
288 return (val == "1");
289 }
290
291 //----------------------------------------------------------
registerForExtension(MSIHANDLE handle,const int nIndex,bool bRegister)292 static void registerForExtension( MSIHANDLE handle, const int nIndex, bool bRegister )
293 {
294 CHAR sPropName[256];
295 StringCchCopyA( sPropName, 256, "REGISTER_" );
296 StringCchCatA( sPropName, 256, (g_Extensions[nIndex])+1 );
297 CharUpperBuffA( sPropName+9, 4 );
298
299 if ( bRegister ) {
300 MsiSetPropertyA( handle, sPropName, "1" );
301 OutputDebugStringFormat( "Set MSI property %s.\n", sPropName );
302 } else {
303 MsiSetPropertyA( handle, sPropName, "0" );
304 OutputDebugStringFormat( "Unset MSI property %s.\n", sPropName );
305 }
306 }
307
308 //----------------------------------------------------------
registerForExtensions(MSIHANDLE handle,BOOL bRegisterAll)309 static void registerForExtensions( MSIHANDLE handle, BOOL bRegisterAll )
310 { // Check all file extensions
311 int nIndex = 0;
312 while ( g_Extensions[nIndex] != 0 )
313 {
314 BOOL bRegister = bRegisterAll || CheckExtensionInRegistry( g_Extensions[nIndex] );
315 if ( bRegister )
316 registerForExtension( handle, nIndex, true );
317 ++nIndex;
318 }
319 }
320
321 //----------------------------------------------------------
checkSomeExtensionInRegistry(const int nStart,const int nEnd)322 static bool checkSomeExtensionInRegistry( const int nStart, const int nEnd )
323 { // Check all file extensions
324 int nIndex = nStart;
325 bool bFound = false;
326
327 while ( !bFound && ( g_Extensions[nIndex] != 0 ) && ( nIndex < nEnd ) )
328 {
329 bFound = ! CheckExtensionInRegistry( g_Extensions[nIndex] );
330
331 if ( bFound )
332 OutputDebugStringFormat( "Found registration for [%s].\n", g_Extensions[nIndex] );
333
334 ++nIndex;
335 }
336 return bFound;
337 }
338
339 //----------------------------------------------------------
registerSomeExtensions(MSIHANDLE handle,const int nStart,const int nEnd,bool bRegister)340 static void registerSomeExtensions( MSIHANDLE handle, const int nStart, const int nEnd, bool bRegister )
341 { // Check all file extensions
342 int nIndex = nStart;
343
344 while ( ( g_Extensions[nIndex] != 0 ) && ( nIndex < nEnd ) )
345 {
346 registerForExtension( handle, nIndex++, bRegister );
347 }
348 }
349
350 //----------------------------------------------------------
351 //----------------------------------------------------------
352 //----------------------------------------------------------
LookForRegisteredExtensions(MSIHANDLE handle)353 extern "C" UINT __stdcall LookForRegisteredExtensions( MSIHANDLE handle )
354 {
355 OutputDebugStringFormat( "LookForRegisteredExtensions: " );
356
357 INSTALLSTATE current_state;
358 INSTALLSTATE future_state;
359
360 bool bWriterEnabled = false;
361 bool bCalcEnabled = false;
362 bool bImpressEnabled = false;
363 bool bRegisterNone = IsSetMsiProp( handle, "REGISTER_NO_MSO_TYPES" );
364
365 if ( ( ERROR_SUCCESS == MsiGetFeatureState( handle, L"gm_p_Wrt", ¤t_state, &future_state ) ) &&
366 ( (future_state == INSTALLSTATE_LOCAL) || ((current_state == INSTALLSTATE_LOCAL) && (future_state == INSTALLSTATE_UNKNOWN) ) ) )
367 bWriterEnabled = true;
368
369 OutputDebugStringFormat( "LookForRegisteredExtensions: Install state Writer is [%d], will be [%d]", current_state, future_state );
370 if ( bWriterEnabled )
371 OutputDebugStringFormat( "LookForRegisteredExtensions: Writer is enabled" );
372 else
373 OutputDebugStringFormat( "LookForRegisteredExtensions: Writer is NOT enabled" );
374
375 if ( ( ERROR_SUCCESS == MsiGetFeatureState( handle, L"gm_p_Calc", ¤t_state, &future_state ) ) &&
376 ( (future_state == INSTALLSTATE_LOCAL) || ((current_state == INSTALLSTATE_LOCAL) && (future_state == INSTALLSTATE_UNKNOWN) ) ) )
377 bCalcEnabled = true;
378
379 OutputDebugStringFormat( "LookForRegisteredExtensions: Install state Calc is [%d], will be [%d]", current_state, future_state );
380 if ( bCalcEnabled )
381 OutputDebugStringFormat( "LookForRegisteredExtensions: Calc is enabled" );
382 else
383 OutputDebugStringFormat( "LookForRegisteredExtensions: Calc is NOT enabled" );
384
385 if ( ( ERROR_SUCCESS == MsiGetFeatureState( handle, L"gm_p_Impress", ¤t_state, &future_state ) ) &&
386 ( (future_state == INSTALLSTATE_LOCAL) || ((current_state == INSTALLSTATE_LOCAL) && (future_state == INSTALLSTATE_UNKNOWN) ) ) )
387 bImpressEnabled = true;
388
389 OutputDebugStringFormat( "LookForRegisteredExtensions: Install state Impress is [%d], will be [%d]", current_state, future_state );
390 if ( bImpressEnabled )
391 OutputDebugStringFormat( "LookForRegisteredExtensions: Impress is enabled" );
392 else
393 OutputDebugStringFormat( "LookForRegisteredExtensions: Impress is NOT enabled" );
394
395 MsiSetPropertyA( handle, "SELECT_WORD", "" );
396 MsiSetPropertyA( handle, "SELECT_EXCEL", "" );
397 MsiSetPropertyA( handle, "SELECT_POWERPOINT", "" );
398
399 if ( ! bRegisterNone )
400 {
401 if ( IsSetMsiProp( handle, "REGISTER_ALL_MSO_TYPES" ) )
402 {
403 if ( bWriterEnabled )
404 MsiSetPropertyA( handle, "SELECT_WORD", "1" );
405 if ( bCalcEnabled )
406 MsiSetPropertyA( handle, "SELECT_EXCEL", "1" );
407 if ( bImpressEnabled )
408 MsiSetPropertyA( handle, "SELECT_POWERPOINT", "1" );
409 }
410 else
411 {
412 if ( bWriterEnabled && ! checkSomeExtensionInRegistry( WORD_START, EXCEL_START ) )
413 {
414 MsiSetPropertyA( handle, "SELECT_WORD", "1" );
415 OutputDebugStringFormat( "LookForRegisteredExtensions: Register for Microsoft Word" );
416 }
417 if ( bCalcEnabled && ! checkSomeExtensionInRegistry( EXCEL_START, POWERPOINT_START ) )
418 {
419 MsiSetPropertyA( handle, "SELECT_EXCEL", "1" );
420 OutputDebugStringFormat( "LookForRegisteredExtensions: Register for Microsoft Excel" );
421 }
422 if ( bImpressEnabled && ! checkSomeExtensionInRegistry( POWERPOINT_START, POWERPOINT_END ) )
423 {
424 MsiSetPropertyA( handle, "SELECT_POWERPOINT", "1" );
425 OutputDebugStringFormat( "LookForRegisteredExtensions: Register for Microsoft PowerPoint" );
426 }
427 }
428 }
429
430 MsiSetPropertyA( handle, "FILETYPEDIALOGUSED", "1" );
431
432 return ERROR_SUCCESS;
433 }
434
435 //----------------------------------------------------------
RegisterSomeExtensions(MSIHANDLE handle)436 extern "C" UINT __stdcall RegisterSomeExtensions( MSIHANDLE handle )
437 {
438 OutputDebugStringFormat( "RegisterSomeExtensions: " );
439
440 if ( IsSetMsiProp( handle, "SELECT_WORD" ) )
441 {
442 registerSomeExtensions( handle, WORD_START, EXCEL_START, true );
443 MsiSetFeatureState( handle, L"gm_p_Wrt_MSO_Reg", INSTALLSTATE_LOCAL );
444 OutputDebugStringFormat( "RegisterSomeExtensions: Register for Microsoft Word" );
445 }
446 else
447 {
448 registerSomeExtensions( handle, WORD_START, EXCEL_START, false );
449 MsiSetFeatureState( handle, L"gm_p_Wrt_MSO_Reg", INSTALLSTATE_ABSENT );
450 }
451
452 if ( IsSetMsiProp( handle, "SELECT_EXCEL" ) )
453 {
454 registerSomeExtensions( handle, EXCEL_START, POWERPOINT_START, true );
455 MsiSetFeatureState( handle, L"gm_p_Calc_MSO_Reg", INSTALLSTATE_LOCAL );
456 OutputDebugStringFormat( "RegisterSomeExtensions: Register for Microsoft Excel" );
457 }
458 else
459 {
460 registerSomeExtensions( handle, EXCEL_START, POWERPOINT_START, false );
461 MsiSetFeatureState( handle, L"gm_p_Calc_MSO_Reg", INSTALLSTATE_ABSENT );
462 }
463
464 if ( IsSetMsiProp( handle, "SELECT_POWERPOINT" ) )
465 {
466 registerSomeExtensions( handle, POWERPOINT_START, POWERPOINT_END, true );
467 MsiSetFeatureState( handle, L"gm_p_Impress_MSO_Reg", INSTALLSTATE_LOCAL );
468 OutputDebugStringFormat( "RegisterSomeExtensions: Register for Microsoft PowerPoint" );
469 }
470 else
471 {
472 registerSomeExtensions( handle, POWERPOINT_START, POWERPOINT_END, false );
473 MsiSetFeatureState( handle, L"gm_p_Impress_MSO_Reg", INSTALLSTATE_ABSENT );
474 }
475
476 return ERROR_SUCCESS;
477 }
478
479 //----------------------------------------------------------
FindRegisteredExtensions(MSIHANDLE handle)480 extern "C" UINT __stdcall FindRegisteredExtensions( MSIHANDLE handle )
481 {
482 if ( IsSetMsiProp( handle, "FILETYPEDIALOGUSED" ) )
483 {
484 OutputDebugStringFormat( "FindRegisteredExtensions: FILETYPEDIALOGUSED!" );
485 return ERROR_SUCCESS;
486 }
487
488 OutputDebugStringFormat( "FindRegisteredExtensions:" );
489
490 bool bRegisterAll = IsSetMsiProp( handle, "REGISTER_ALL_MSO_TYPES" );
491
492 if ( IsSetMsiProp( handle, "REGISTER_NO_MSO_TYPES" ) )
493 {
494 OutputDebugStringFormat( "FindRegisteredExtensions: Register none!" );
495 return ERROR_SUCCESS;
496 }
497 else if ( bRegisterAll )
498 OutputDebugStringFormat( "FindRegisteredExtensions: Force all on" );
499 else
500 OutputDebugStringFormat( "FindRegisteredExtensions: " );
501
502 // setting the msi properties SELECT_* will force registering for all corresponding
503 // file types
504 if ( IsSetMsiProp( handle, "SELECT_WORD" ) )
505 registerSomeExtensions( handle, WORD_START, EXCEL_START, true );
506 if ( IsSetMsiProp( handle, "SELECT_EXCEL" ) )
507 registerSomeExtensions( handle, EXCEL_START, POWERPOINT_START, true );
508 if ( IsSetMsiProp( handle, "SELECT_POWERPOINT" ) )
509 registerSomeExtensions( handle, POWERPOINT_START, POWERPOINT_END, true );
510
511 registerForExtensions( handle, bRegisterAll );
512
513 return ERROR_SUCCESS;
514 }
515
516 //----------------------------------------------------------
DeleteRegisteredExtensions(MSIHANDLE)517 extern "C" UINT __stdcall DeleteRegisteredExtensions( MSIHANDLE /*handle*/ )
518 {
519 OutputDebugStringFormat( "DeleteRegisteredExtensions\n" );
520
521 // remove all file extensions
522 int nIndex = 0;
523 while ( g_Extensions[nIndex] != 0 )
524 {
525 RemoveExtensionInRegistry( g_Extensions[nIndex] );
526 ++nIndex;
527 }
528
529 return ERROR_SUCCESS;
530 }
531