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 #define WIN32_LEAN_AND_MEAN
23 
24 #ifdef _MSC_VER
25 #pragma warning(disable:4668 4917) // disable warnings for system headers
26 #endif
27 
28 #include <windows.h>
29 #include <windowsx.h>
30 #include <shellapi.h>
31 #include <shlobj.h>
32 #include <tchar.h>
33 
34 #include <stdio.h>
35 
36 #define elementsof(buf) (sizeof(buf) / sizeof(buf[0]))
37 
38 enum PathResult
39 {
40     PATHRESULT_OK,
41     PATHRESULT_API_NOT_SUPPORTED,
42     PATHRESULT_EXE_NOT_FOUND
43 };
44 
45 const int MAXCMDLINELEN = 32768;
46 
47 static TCHAR       g_szSTInstallationPath[MAX_PATH] = TEXT("");
48 static TCHAR       g_szOperatingSystem[256]         = TEXT("");
49 
50 static const TCHAR g_szSTExecutable[256]            = TEXT("stclient.exe");
51 
52 //***************************************************************************
53 
RegReadValue(HKEY hBaseKey,LPCTSTR lpSubKey,LPCTSTR lpValueName,LPVOID lpData,DWORD cbData)54 LONG RegReadValue( HKEY hBaseKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPVOID lpData, DWORD cbData )
55 {
56 	HKEY	hKey = NULL;
57 	LONG	lResult( 0 );
58 
59 	lResult = RegOpenKeyEx( hBaseKey, lpSubKey, 0, KEY_QUERY_VALUE, &hKey );
60 
61 	if ( ERROR_SUCCESS == lResult )
62 	{
63 		lResult = RegQueryValueEx( hKey, lpValueName, NULL, NULL, (LPBYTE)lpData, &cbData );
64 		RegCloseKey( hKey );
65 	}
66 
67 	return lResult;
68 }
69 
70 //***************************************************************************
71 
GetCommandArgs(int * pArgc)72 static LPTSTR *GetCommandArgs( int *pArgc )
73 {
74 #ifdef UNICODE
75 	return CommandLineToArgvW( GetCommandLineW(), pArgc );
76 #else
77 	*pArgc = __argc;
78 	return __argv;
79 #endif
80 }
81 
82 //***************************************************************************
83 
IsSupportedPlatform()84 static bool IsSupportedPlatform()
85 {
86     OSVERSIONINFO aOsVersion;
87 
88     ZeroMemory( &aOsVersion, sizeof( OSVERSIONINFO ));
89     aOsVersion.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
90 
91     // Try to determine OS version
92     if ( GetVersionEx( &aOsVersion ))
93     {
94         switch ( aOsVersion.dwPlatformId )
95         {
96             case VER_PLATFORM_WIN32_NT:     // Windows NT based
97                 return true;
98 
99             case VER_PLATFORM_WIN32_WINDOWS: // Windows Me/98/95.
100             case VER_PLATFORM_WIN32s:        // Win32s
101                 return false;
102 
103             default:
104                 return false;
105         }
106     }
107 
108     return false;
109 }
110 
111 //***************************************************************************
112 
GetOperatingSystemString()113 static LPCTSTR GetOperatingSystemString()
114 {
115     OSVERSIONINFO aOsVersion;
116 
117     ZeroMemory( &aOsVersion, sizeof( OSVERSIONINFO ));
118     aOsVersion.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
119 
120     _tcscpy( g_szOperatingSystem, TEXT( "Microsoft Windows" ));
121 
122     // Try to determine OS version
123     if ( GetVersionEx( &aOsVersion ))
124     {
125         switch ( aOsVersion.dwPlatformId )
126         {
127             // Test for the Windows NT product family.
128             case VER_PLATFORM_WIN32_NT:
129             {
130                 if ( aOsVersion.dwMajorVersion == 3 )
131                 {
132                     _tcscat( g_szOperatingSystem, TEXT( " NT 3." ));
133                     if ( aOsVersion.dwMinorVersion == 0 )
134                         _tcscat( g_szOperatingSystem, TEXT( "0" ));
135                     else if ( aOsVersion.dwMinorVersion == 5 )
136                         _tcscat( g_szOperatingSystem, TEXT( "5" ));
137                     else if ( aOsVersion.dwMinorVersion == 51 )
138                         _tcscat( g_szOperatingSystem, TEXT( "51" ));
139                 }
140                 else if ( aOsVersion.dwMajorVersion == 4 )
141                     _tcscat( g_szOperatingSystem, TEXT( " NT 4.0" ));
142                 else if ( aOsVersion.dwMajorVersion == 5 )
143                 {
144                     if ( aOsVersion.dwMinorVersion == 0 )
145                         _tcscat( g_szOperatingSystem, TEXT( " 2000" ));
146                     else if ( aOsVersion.dwMinorVersion == 1 )
147                         _tcscat( g_szOperatingSystem, TEXT( " XP" ));
148                     else if ( aOsVersion.dwMinorVersion == 2 )
149                         _tcscat( g_szOperatingSystem, TEXT( " Server 2003" ));
150                 }
151                 else if ( aOsVersion.dwMajorVersion == 6 )
152                 {
153                     if ( aOsVersion.dwMinorVersion == 0 )
154                         _tcscat( g_szOperatingSystem, " Vista" );
155                 }
156             }
157             break;
158 
159             // Test for the Windows Me/98/95.
160             case VER_PLATFORM_WIN32_WINDOWS:
161             {
162                 if ( aOsVersion.dwMinorVersion == 0 )
163                   _tcscat( g_szOperatingSystem, TEXT( " 95" ));
164                 else if ( aOsVersion.dwMinorVersion == 10 )
165                   _tcscat( g_szOperatingSystem, TEXT( " 98" ));
166                 else if ( aOsVersion.dwMinorVersion == 90 )
167                   _tcscat( g_szOperatingSystem, TEXT( " Me" ));
168             }
169             break;
170         }
171     }
172 
173     return g_szOperatingSystem;
174 }
175 
176 //***************************************************************************
177 
FileExists(LPCTSTR lpPathToFile)178 static bool FileExists( LPCTSTR lpPathToFile )
179 {
180     bool            bResult = false;
181     HANDLE          hFind;
182     WIN32_FIND_DATA FindFileData;
183 
184     hFind = FindFirstFile( lpPathToFile, &FindFileData );
185 
186     if ( hFind != INVALID_HANDLE_VALUE )
187     {
188         FindClose( hFind );
189         bResult = true;
190     }
191 
192     return bResult;
193 }
194 
195 //***************************************************************************
196 
GetProgramFilesFolder(LPTSTR strPath)197 static bool GetProgramFilesFolder( LPTSTR strPath )
198 {
199     bool      bRet = false;
200     HINSTANCE hLibrary;
201 
202     if (( hLibrary = LoadLibrary( "shell32.dll" )) != NULL )
203     {
204         BOOL (WINAPI *pSHGetSpecialFolderPathA)( HWND, LPSTR, int, BOOL );
205 
206         pSHGetSpecialFolderPathA = (BOOL (WINAPI *)(HWND, LPSTR, int, BOOL))GetProcAddress( hLibrary, "SHGetSpecialFolderPathA" );
207 
208         if ( pSHGetSpecialFolderPathA )
209         {
210             if ( pSHGetSpecialFolderPathA( NULL, strPath, CSIDL_PROGRAM_FILES, TRUE ))
211                 bRet = true;
212         }
213     }
214 
215     FreeLibrary( hLibrary );
216 
217     return ( bRet );
218 }
219 
220 //***************************************************************************
221 
RetrieveExecutablePath(LPTSTR szExecutablePath)222 static PathResult RetrieveExecutablePath( LPTSTR szExecutablePath )
223 {
224     PathResult eRet = PATHRESULT_API_NOT_SUPPORTED;
225     TCHAR szProgramFilesFolder[MAX_PATH];
226 
227     if ( GetProgramFilesFolder( szProgramFilesFolder ))
228     {
229         size_t nLen = _tcslen( szProgramFilesFolder );
230         if ( nLen > 0 )
231         {
232             _tcscpy( szExecutablePath, szProgramFilesFolder );
233             if ( szProgramFilesFolder[nLen-1] != '\\' )
234                 _tcscat( szExecutablePath, TEXT( "\\" ));
235             _tcscat( szExecutablePath, TEXT( "Sun\\servicetag\\" ));
236             _tcscat( szExecutablePath, g_szSTExecutable );
237             eRet = FileExists( szExecutablePath ) ? PATHRESULT_OK : PATHRESULT_EXE_NOT_FOUND;
238         }
239     }
240 
241     return eRet;
242 }
243 
244 //***************************************************************************
245 
SafeCopy(LPTSTR lpTarget,LPCSTR lpSource,size_t nMaxLen)246 static void SafeCopy( LPTSTR lpTarget, LPCSTR lpSource, size_t nMaxLen )
247 {
248     size_t nLen  = _tcslen( lpSource );
249     size_t nCopy = ( nLen < size_t( nMaxLen-1 )) ? nLen : nMaxLen-1;
250     _tcsncpy( lpTarget, lpSource, nMaxLen-1 );
251     *(lpTarget+nCopy) = 0;
252 }
253 
254 //***************************************************************************
255 
_tWinMain(HINSTANCE,HINSTANCE,LPTSTR,int)256 int WINAPI _tWinMain( HINSTANCE /*hInstance*/, HINSTANCE, LPTSTR, int )
257 {
258     const DWORD ERR_NO_RECORDS_FOUND = 225;
259     const DWORD ERR_DUP_RECORD       = 226;
260 
261     DWORD dwExitCode = (DWORD)1;
262 
263     int     nArgs  = 0;
264     LPTSTR* lpArgs = GetCommandArgs( &nArgs );
265 
266     if ( !IsSupportedPlatform() )
267     {
268         // Return 0 for a successful run on not supported platforms
269         // We don't want that the Office tries to start us forever.
270         return 0;
271     }
272 
273     if ( nArgs >= 11 )
274     {
275         TCHAR szTargetURN[1024]         = {0};
276         TCHAR szProductName[1024]       = {0};
277         TCHAR szProductVersion[1024]    = {0};
278         TCHAR szParentProductName[1024] = {0};
279         TCHAR szProductSource[1024]     = {0};
280         TCHAR szInstanceURN[1024]       = {0};
281 
282 //      -i)  INSTANCE_URN="$2"; shift;;
283 //      -t)  TARGET_URN="$2"; shift;;
284 //	    -p)  PRODUCT_NAME="$2"; shift;;
285 //	    -e)  PRODUCT_VERSION="$2"; shift;;
286 //	    -P)  PARENT_PRODUCT_NAME="$2"; shift;;
287 //	    -S)  PRODUCT_SOURCE="$2"; shift;;
288 //	    "usage: $0 [-i <instance urn>] -p <product name> -e <product version> -t <urn> -S <source> -P <parent product name>"
289 
290         int i = 1;
291         while ( i < nArgs )
292         {
293             LPTSTR lpArg = lpArgs[i];
294             if ( _tcslen( lpArg ) >= 2 )
295             {
296                 if ( lpArg[0] == '-' )
297                 {
298                     switch ( lpArg[1] )
299                     {
300                         case 'i':
301                         {
302                             if ( i < nArgs )
303                                 ++i;
304                             SafeCopy( szInstanceURN, lpArgs[i], elementsof( szInstanceURN ));
305                             break;
306                         }
307 
308                         case 't':
309                         {
310                             if ( i < nArgs )
311                                 ++i;
312                             SafeCopy( szTargetURN, lpArgs[i], elementsof( szTargetURN ));
313                             break;
314                         }
315                         case 'p':
316                         {
317                             if ( i < nArgs )
318                                 ++i;
319                             SafeCopy( szProductName, lpArgs[i], elementsof( szProductName ));
320                             break;
321                         }
322                         case 'e':
323                         {
324                             if ( i < nArgs )
325                                 ++i;
326                             SafeCopy( szProductVersion, lpArgs[i], elementsof( szProductVersion ));
327                             break;
328                         }
329                         case 'P':
330                         {
331                             if ( i < nArgs )
332                                 ++i;
333                             SafeCopy( szParentProductName, lpArgs[i], elementsof( szParentProductName ));
334                             break;
335                         }
336                         case 'S':
337                         {
338                             if ( i < nArgs )
339                                 ++i;
340                             SafeCopy( szProductSource, lpArgs[i], elementsof( szProductSource ));
341                             break;
342                         }
343 
344                         default:
345                             break;
346                     } // switch
347                 }
348             }
349 
350             ++i;
351         }
352 
353         if ( RetrieveExecutablePath( g_szSTInstallationPath ) == PATHRESULT_OK )
354         {
355             BOOL bSuccess = TRUE;
356             BOOL bProcessStarted = FALSE;
357 
358             STARTUPINFO         aStartupInfo;
359             PROCESS_INFORMATION	aProcessInfo;
360             LPTSTR              lpCommandLine = 0;
361 
362             ZeroMemory( &aStartupInfo, sizeof( aStartupInfo ));
363             aStartupInfo.cb = sizeof( aStartupInfo );
364             ZeroMemory( &aProcessInfo, sizeof( aProcessInfo ));
365 
366             if ( _tcslen( szInstanceURN ) == 0 )
367             {
368                 // TEST=`${STCLIENT} -f -t ${TARGET_URN}`
369                 lpCommandLine = new TCHAR[MAXCMDLINELEN];
370 
371                 _tcscpy( lpCommandLine, TEXT( "\"" ));
372                 _tcscat( lpCommandLine, g_szSTInstallationPath );
373                 _tcscat( lpCommandLine, TEXT( "\"" ));
374                 _tcscat( lpCommandLine, TEXT( " -f" ));
375                 _tcscat( lpCommandLine, TEXT( " -t "));
376                 _tcscat( lpCommandLine, TEXT( "\"" ));
377                 _tcscat( lpCommandLine, szTargetURN );
378                 _tcscat( lpCommandLine, TEXT( "\"" ));
379 
380 	            bSuccess = CreateProcess(
381                                    NULL,
382 		                           lpCommandLine,
383 		                           NULL,
384 		                           NULL,
385 		                           TRUE,
386 		                           CREATE_NO_WINDOW,
387 		                           NULL,
388 		                           NULL,
389 		                           &aStartupInfo,
390 		                           &aProcessInfo );
391 
392                 bProcessStarted = TRUE;
393 
394                 // wait until process ends to receive exit code
395                 WaitForSingleObject( aProcessInfo.hProcess, INFINITE );
396 
397                 delete []lpCommandLine;
398             }
399 
400             if ( bSuccess )
401             {
402                 DWORD dwSTClientExitCode( ERR_NO_RECORDS_FOUND );
403 			    if ( bProcessStarted )
404                 {
405                     GetExitCodeProcess( aProcessInfo.hProcess, &dwSTClientExitCode );
406                     dwSTClientExitCode &= 0x000000ff;
407 
408 			        CloseHandle( aProcessInfo.hProcess );
409 			        CloseHandle( aProcessInfo.hThread );
410                 }
411 
412                 if ( dwSTClientExitCode == ERR_NO_RECORDS_FOUND )
413                 {
414                     // output=`${STCLIENT} -a [-i "${INSTANCE_URN}"] -p "${PRODUCT_NAME}" -e "${PRODUCT_VERSION}" -t "${TARGET_URN}" -S "${PRODUCT_SOURCE}" -P "${PARENT_PRODUCT_NAME}" -m "Sun Microsystems, Inc." -A ${uname} -z global`
415                     lpCommandLine = new TCHAR[MAXCMDLINELEN];
416 
417                     _tcscpy( lpCommandLine, TEXT( "\"" ));
418                     _tcscat( lpCommandLine, g_szSTInstallationPath );
419                     _tcscat( lpCommandLine, TEXT( "\"" ));
420                     _tcscat( lpCommandLine, TEXT( " -a" ));
421                     if ( _tcslen( szInstanceURN ) > 0 )
422                     {
423                         _tcscat( lpCommandLine, TEXT( " -i " ));
424                         _tcscat( lpCommandLine, TEXT( "\"" ));
425                         _tcscat( lpCommandLine, szInstanceURN );
426                         _tcscat( lpCommandLine, TEXT( "\"" ));
427                     }
428                     _tcscat( lpCommandLine, TEXT( " -p " ));
429                     _tcscat( lpCommandLine, TEXT( "\"" ));
430                     _tcscat( lpCommandLine, szProductName );
431                     _tcscat( lpCommandLine, TEXT( "\"" ));
432                     _tcscat( lpCommandLine, TEXT( " -e " ));
433                     _tcscat( lpCommandLine, TEXT( "\"" ));
434                     _tcscat( lpCommandLine, szProductVersion );
435                     _tcscat( lpCommandLine, TEXT( "\"" ));
436                     _tcscat( lpCommandLine, TEXT( " -t " ));
437                     _tcscat( lpCommandLine, TEXT( "\"" ));
438                     _tcscat( lpCommandLine, szTargetURN );
439                     _tcscat( lpCommandLine, TEXT( "\"" ));
440                     _tcscat( lpCommandLine, TEXT( " -S " ));
441                     _tcscat( lpCommandLine, TEXT( "\"" ));
442                     _tcscat( lpCommandLine, szProductSource );
443                     _tcscat( lpCommandLine, TEXT( "\"" ));
444                     _tcscat( lpCommandLine, TEXT( " -P " ));
445                     _tcscat( lpCommandLine, TEXT( "\"" ));
446                     _tcscat( lpCommandLine, szParentProductName );
447                     _tcscat( lpCommandLine, TEXT( "\"" ));
448                     _tcscat( lpCommandLine, TEXT( " -m \"Sun Microsystems, Inc.\"" ));
449                     _tcscat( lpCommandLine, TEXT( " -A " ));
450                     _tcscat( lpCommandLine, TEXT( "\"" ));
451                     _tcscat( lpCommandLine, GetOperatingSystemString() );
452                     _tcscat( lpCommandLine, TEXT( "\"" ));
453                     _tcscat( lpCommandLine, TEXT( " -z global" ));
454 
455                     ZeroMemory( &aStartupInfo, sizeof( aStartupInfo ));
456 	                aStartupInfo.cb = sizeof(aStartupInfo);
457                     ZeroMemory( &aProcessInfo, sizeof( aProcessInfo ));
458 
459                     bSuccess = CreateProcess(
460                                        NULL,
461 		                               lpCommandLine,
462 		                               NULL,
463 		                               NULL,
464 		                               TRUE,
465 		                               CREATE_NO_WINDOW,
466 		                               NULL,
467 		                               NULL,
468 		                               &aStartupInfo,
469 		                               &aProcessInfo );
470 
471                     delete []lpCommandLine;
472 
473                     // wait until process ends to receive exit code
474                     WaitForSingleObject( aProcessInfo.hProcess, INFINITE );
475 
476                     dwSTClientExitCode = 0;
477 			        GetExitCodeProcess( aProcessInfo.hProcess, &dwSTClientExitCode );
478                     dwSTClientExitCode &= 0x000000ff;
479 
480                     CloseHandle( aProcessInfo.hProcess );
481 			        CloseHandle( aProcessInfo.hThread );
482 
483                     if ( !bSuccess )
484                         dwExitCode = 1; // couldn't start stclient process
485                     else
486                     {
487                         if ( _tcslen( szInstanceURN ) > 0 )
488                         {
489                             // don't register again if we registered in a previous run
490                             // or we called stclient successfully.
491                             if (( dwSTClientExitCode == ERR_DUP_RECORD ) ||
492                                 ( dwSTClientExitCode == 0 ))
493                                 dwExitCode = 0;
494                             else
495                                 dwExitCode = 1; // other errors
496                         }
497                         else
498                             dwExitCode = ( dwSTClientExitCode == 0 ) ? 0 : 1;
499                     }
500                 }
501                 else if ( dwSTClientExitCode == 0 )
502                     dwExitCode = 0; // already registered
503                 else
504                     dwExitCode = 1; // other errors
505             }
506             else
507                 dwExitCode = 1; // couldn't start stclient
508         }
509         else
510             dwExitCode = 1; // no executable found
511     }
512     else
513         dwExitCode = 0; // wrong number of arguments
514 
515     return dwExitCode;
516 }
517