| #include "installOS.h" | |
| #include <windows.h> | |
| #include <commctrl.h> | |
| #include <process.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <errno.h> | |
| #define INSTALL_ICON 401 | |
| /* Global Variables */ | |
| _TCHAR dirSeparator = _T('\\'); | |
| _TCHAR pathSeparator = _T(';'); | |
| _TCHAR* consoleVM = _T("java.exe"); | |
| _TCHAR* defaultVM = _T("javaw.exe"); | |
| _TCHAR* shippedVMDir = _T("jre\\bin\\"); | |
| /* Define the window system arguments for the Java VM. */ | |
| static _TCHAR* argVM[] = { NULL }; | |
| /* Define local variables for the main window. */ | |
| static HWND topWindow = 0; | |
| static WNDPROC oldProc; | |
| /* Define local variables for running the JVM and detecting its exit. */ | |
| static int jvmProcess = 0; | |
| static int jvmExitCode = 0; | |
| static int jvmExitTimeout = 100; | |
| static int jvmExitTimerId = 99; | |
| /* Define local variables for handling the splash window and its image. */ | |
| static int splashTimerId = 88, inputTimerId = 89; | |
| static HWND label = NULL, progress = NULL; | |
| static COLORREF foreground = 0; | |
| static RECT progressRect = {0, 0, 0, 0}, messageRect = {0, 0, 0, 0}; | |
| static int value = 0, maximum = 100; | |
| /* Local functions */ | |
| static void CALLBACK detectJvmExit( HWND hwnd, UINT uMsg, UINT id, DWORD dwTime ); | |
| static HBITMAP loadSplashImage(_TCHAR *baseDir, _TCHAR *fileName); | |
| static void CALLBACK splashTimeout( HWND hwnd, UINT uMsg, UINT id, DWORD dwTime ); | |
| static LRESULT WINAPI WndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); | |
| /* Display a Message */ | |
| void displayMessage( _TCHAR* message ) | |
| { | |
| MessageBox( topWindow, message, officialName, MB_OK ); | |
| } | |
| /* Initialize Window System | |
| * | |
| * Create a pop window to display the bitmap image. | |
| * | |
| * Return the window handle as the data for the splash command. | |
| * | |
| */ | |
| void initWindowSystem( int* pArgc, _TCHAR* argv[], int showSplash ) | |
| { | |
| /* Create a window that has no decorations. */ | |
| InitCommonControls(); | |
| topWindow = CreateWindowEx (0, | |
| _T("STATIC"), | |
| officialName, | |
| SS_BITMAP | WS_POPUP, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| NULL, | |
| NULL, | |
| GetModuleHandle (NULL), | |
| NULL); | |
| SetClassLong(topWindow, GCL_HICON, (LONG)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(INSTALL_ICON))); | |
| oldProc = (WNDPROC) GetWindowLong (topWindow, GWL_WNDPROC); | |
| SetWindowLong (topWindow, GWL_WNDPROC, (LONG) WndProc); | |
| } | |
| static void readRect(_TCHAR *str, RECT *rect) { | |
| int x, y, width, height; | |
| _TCHAR *temp = str, *comma; | |
| comma = _tcschr(temp, _T(',')); | |
| if (comma == NULL) return; | |
| comma[0] = 0; | |
| x = _ttoi(temp); | |
| temp = comma + 1; | |
| comma = _tcschr(temp, _T(',')); | |
| if (comma == NULL) return; | |
| comma[0] = 0; | |
| y = _ttoi(temp); | |
| temp = comma + 1; | |
| comma = _tcschr(temp, _T(',')); | |
| if (comma == NULL) return; | |
| comma[0] = 0; | |
| width = _ttoi(temp); | |
| temp = comma + 1; | |
| height = _ttoi(temp); | |
| rect->left = x; | |
| rect->top = y; | |
| rect->right = x + width; | |
| rect->bottom = y + height; | |
| } | |
| static void readColor(_TCHAR *str, COLORREF *color) { | |
| int value = _ttoi(str); | |
| *color = ((value & 0xFF0000) >> 16) | (value & 0xFF00) | ((value & 0xFF) << 16); | |
| } | |
| static void readInput() { | |
| int available; | |
| FILE *fd = stdin; | |
| #ifdef _UNICODE | |
| WCHAR *buffer1 = NULL; | |
| #endif | |
| char *buffer = NULL; | |
| _TCHAR *equals = NULL, *end, *line; | |
| HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); | |
| available = GetFileSize (hStdin, NULL) - SetFilePointer (hStdin, 0, NULL, FILE_CURRENT); | |
| if (available <= 0) return; | |
| buffer = malloc(available + 1); | |
| if (!ReadFile(hStdin, buffer, available, &available, NULL)) { | |
| return; | |
| } | |
| if (available <= 0) { | |
| free(buffer); | |
| return; | |
| } | |
| buffer[available] = 0; | |
| #ifdef _UNICODE | |
| { | |
| buffer1 = malloc((available + 1) * sizeof(TCHAR)); | |
| available = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR)buffer, available, (LPWSTR)buffer1, available); | |
| buffer1[available] = 0; | |
| line = buffer1; | |
| } | |
| #else | |
| line = buffer; | |
| #endif | |
| while (line != NULL) { | |
| end = _tcschr(line, _T('\n')); | |
| equals = _tcschr(line, _T('=')); | |
| if (end != NULL) end[0] = 0; | |
| if (equals != NULL) { | |
| _TCHAR *str = (_TCHAR *)equals + 1; | |
| equals[0] = 0; | |
| if (_tcscmp(line, _T("maximum")) == 0) { | |
| maximum = _ttoi(str); | |
| if (progress) { | |
| SendMessage (progress, PBM_SETRANGE32, 0, maximum); | |
| } | |
| } else if (_tcscmp(line, _T("value")) == 0) { | |
| value = _ttoi(str); | |
| if (progress) { | |
| SendMessage (progress, PBM_SETPOS, value, 0); | |
| } | |
| } else if (_tcscmp(line, _T("progressRect")) == 0) { | |
| readRect(str, &progressRect); | |
| if (progress) { | |
| int flags = SWP_NOZORDER | SWP_DRAWFRAME | SWP_NOACTIVATE; | |
| SetWindowPos (progress, 0, progressRect.left, progressRect.top, progressRect.right - progressRect.left, progressRect.bottom - progressRect.top, flags); | |
| } | |
| } else if (_tcscmp(line, _T("messageRect")) == 0) { | |
| readRect(str, &messageRect); | |
| if (label) { | |
| int flags = SWP_NOZORDER | SWP_DRAWFRAME | SWP_NOACTIVATE; | |
| SetWindowPos (label, 0, messageRect.left, messageRect.top, messageRect.right - messageRect.left, messageRect.bottom - messageRect.top, flags); | |
| } | |
| } else if (_tcscmp(line, _T("foreground")) == 0) { | |
| readColor(str, &foreground); | |
| if (label) { | |
| RECT rect; | |
| GetWindowRect (label, &rect); | |
| MapWindowPoints (0, topWindow, (POINT *)&rect, 2); | |
| InvalidateRect (topWindow, &rect, 1); | |
| } | |
| } else if (_tcscmp(line, _T("message")) == 0) { | |
| if (label) { | |
| RECT rect; | |
| SetWindowText (label, str); | |
| GetWindowRect (label, &rect); | |
| MapWindowPoints (0, topWindow, (POINT *)&rect, 2); | |
| InvalidateRect (topWindow, &rect, 1); | |
| } | |
| } | |
| } | |
| if (end != NULL) line = end + 1; | |
| else line = NULL; | |
| } | |
| free(buffer); | |
| #ifdef _UNICODE | |
| if (buffer1 != NULL) free(buffer1); | |
| #endif | |
| } | |
| static void CALLBACK timerProc( HWND hwnd, UINT uMsg, UINT id, DWORD dwTime ) { | |
| readInput(); | |
| if ( isEndSplash() ) | |
| { | |
| /* Kill the timer. */ | |
| KillTimer( topWindow, splashTimerId ); | |
| ShowWindow( topWindow, SW_HIDE ); | |
| } | |
| } | |
| /* Show the Splash Window | |
| * | |
| * Open the bitmap, insert into the splash window and display it. | |
| * | |
| */ | |
| int showSplash( _TCHAR* timeoutString, _TCHAR* featureImage ) | |
| { | |
| int timeout = 0; | |
| RECT rect; | |
| HBITMAP hBitmap = 0; | |
| HDC hDC; | |
| int depth; | |
| int x, y; | |
| int width, height; | |
| MSG msg; | |
| int q = 0; | |
| /* Determine the splash timeout value (in seconds). */ | |
| if (timeoutString != NULL && _tcslen( timeoutString ) > 0) | |
| { | |
| _stscanf( timeoutString, _T("%d"), &timeout ); | |
| } | |
| /* Load the bitmap for the feature. */ | |
| hDC = GetDC( NULL); | |
| depth = GetDeviceCaps( hDC, BITSPIXEL ) * GetDeviceCaps( hDC, PLANES); | |
| ReleaseDC(NULL, hDC); | |
| if (featureImage != NULL) | |
| hBitmap = LoadImage(NULL, featureImage, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); | |
| /* If the bitmap could not be found, return an error. */ | |
| if (hBitmap == 0) | |
| return ERROR_FILE_NOT_FOUND; | |
| /* Load the bitmap into the splash popup window. */ | |
| SendMessage( topWindow, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hBitmap ); | |
| progress = CreateWindowEx (0, _T("msctls_progress32"), | |
| _T(""), | |
| WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| topWindow, | |
| NULL, | |
| GetModuleHandle (NULL), | |
| NULL); | |
| label = CreateWindowEx (0, _T("STATIC"), | |
| _T(""), | |
| WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| topWindow, | |
| NULL, | |
| GetModuleHandle (NULL), | |
| NULL); | |
| SendMessage (label, WM_SETFONT, (WPARAM)GetStockObject (DEFAULT_GUI_FONT), (LPARAM)1); | |
| /* Centre the splash window and display it. */ | |
| GetWindowRect (topWindow, &rect); | |
| width = GetSystemMetrics (SM_CXSCREEN); | |
| height = GetSystemMetrics (SM_CYSCREEN); | |
| x = (width - (rect.right - rect.left)) / 2; | |
| y = (height - (rect.bottom - rect.top)) / 2; | |
| SetWindowPos (topWindow, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); | |
| ShowWindow( topWindow, SW_SHOW ); | |
| BringWindowToTop( topWindow ); | |
| readInput(); | |
| SetTimer( topWindow, inputTimerId, 50, timerProc ); | |
| /* If a timeout for the splash window was given */ | |
| if (timeout != 0) | |
| { | |
| /* Add a timeout (in milliseconds) to bring down the splash screen. */ | |
| SetTimer( topWindow, splashTimerId, (timeout * 1000), splashTimeout ); | |
| } | |
| while (GetMessage( &msg, NULL, 0, 0 ) && q < 20) | |
| { | |
| TranslateMessage( &msg ); | |
| DispatchMessage( &msg ); | |
| q++; | |
| } | |
| /* Process messages until the splash window is closed or process is terminated. */ | |
| /* | |
| while (GetMessage( &msg, NULL, 0, 0 )) | |
| { | |
| TranslateMessage( &msg ); | |
| DispatchMessage( &msg ); | |
| } | |
| */ | |
| return 0; | |
| } | |
| /* Get the window system specific VM args */ | |
| _TCHAR** getArgVM( _TCHAR *vm ) | |
| { | |
| return argVM; | |
| } | |
| /* Start the Java VM | |
| * | |
| * This method is called to start the Java virtual machine and to wait until it | |
| * terminates. The function returns the exit code from the JVM. | |
| */ | |
| int startJavaVM( _TCHAR* args[] ) | |
| { | |
| MSG msg; | |
| int index, length; | |
| _TCHAR *commandLine, *ch, *space; | |
| /* | |
| * Build the command line. Any argument with spaces must be in | |
| * double quotes in the command line. | |
| */ | |
| length = 0; | |
| for (index = 0; args[index] != NULL; index++) | |
| { | |
| /* String length plus space character */ | |
| length += _tcslen( args[ index ] ) + 1; | |
| /* Quotes */ | |
| if (_tcschr( args[ index ], _T(' ') ) != NULL) length += 2; | |
| } | |
| commandLine = ch = malloc ( (length + 1) * sizeof(_TCHAR) ); | |
| for (index = 0; args[index] != NULL; index++) | |
| { | |
| space = _tcschr( args[ index ], _T(' ')); | |
| if (space != NULL) *ch++ = _T('\"'); | |
| _tcscpy( ch, args[index] ); | |
| ch += _tcslen( args[index] ); | |
| if (space != NULL) *ch++ = _T('\"'); | |
| *ch++ = _T(' '); | |
| } | |
| *ch = _T('\0'); | |
| /* | |
| * Start the Java virtual machine. Use CreateProcess() instead of spawnv() | |
| * otherwise the arguments cannot be freed since spawnv() segments fault. | |
| */ | |
| { | |
| STARTUPINFO si; | |
| PROCESS_INFORMATION pi; | |
| GetStartupInfo(&si); | |
| if (CreateProcess(NULL, commandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { | |
| CloseHandle( pi.hThread ); | |
| jvmProcess = (int)pi.hProcess; | |
| } | |
| } | |
| free( commandLine ); | |
| /* If the child process (JVM) would not start */ | |
| if (jvmProcess == -1) | |
| { | |
| /* Return the error number. */ | |
| jvmExitCode = errno; | |
| jvmProcess = 0; | |
| } | |
| /* else */ | |
| else | |
| { | |
| /* Set a timer to detect JVM process termination. */ | |
| SetTimer( topWindow, jvmExitTimerId, jvmExitTimeout, detectJvmExit ); | |
| /* Process messages until the JVM terminates. | |
| This launcher process must continue to process events until the JVM exits | |
| or else Windows 2K will hang if the desktop properties (e.g., background) are | |
| changed by the user. Windows does a SendMessage() to every top level window | |
| process, which blocks the caller until the process responds. */ | |
| while (jvmProcess != 0) | |
| { | |
| GetMessage( &msg, NULL, 0, 0 ); | |
| TranslateMessage( &msg ); | |
| DispatchMessage( &msg ); | |
| } | |
| /* Kill the timer. */ | |
| KillTimer( topWindow, jvmExitTimerId ); | |
| } | |
| /* Return the exit code from the JVM. */ | |
| return jvmExitCode; | |
| } | |
| /* Local functions */ | |
| /* Detect JVM Process Termination */ | |
| static void CALLBACK detectJvmExit( HWND hwnd, UINT uMsg, UINT id, DWORD dwTime ) | |
| { | |
| DWORD exitCode; | |
| /* If the JVM process has terminated */ | |
| if (!GetExitCodeProcess( (HANDLE)jvmProcess, &exitCode ) || | |
| exitCode != STILL_ACTIVE) | |
| { | |
| /* Save the JVM exit code. This should cause the loop in startJavaVM() to exit. */ | |
| jvmExitCode = exitCode; | |
| jvmProcess = 0; | |
| } | |
| } | |
| /* Splash Timeout */ | |
| static void CALLBACK splashTimeout( HWND hwnd, UINT uMsg, UINT id, DWORD dwTime ) | |
| { | |
| /* Kill the timer. */ | |
| KillTimer( topWindow, id ); | |
| PostMessage( topWindow, WM_QUIT, 0, 0 ); | |
| } | |
| /* Window Procedure for the Spash window. | |
| * | |
| * A special WndProc is needed to return the proper vlaue for WM_NCHITTEST. | |
| * It must also detect the message from the splash window process. | |
| */ | |
| static LRESULT WINAPI WndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) | |
| { | |
| switch (uMsg) | |
| { | |
| case WM_NCHITTEST: return HTCLIENT; | |
| case WM_CLOSE: | |
| PostQuitMessage( 0 ); | |
| break; | |
| case WM_CTLCOLORSTATIC: | |
| if ((HWND)lParam == label) { | |
| SetTextColor((HDC)wParam, foreground); | |
| SetBkMode((HDC)wParam, TRANSPARENT); | |
| return (LRESULT)GetStockObject (NULL_BRUSH); | |
| } | |
| break; | |
| } | |
| return CallWindowProc (oldProc, hwnd, uMsg, wParam, lParam); | |
| } | |
| _TCHAR* getTempPath() | |
| { | |
| _TCHAR* buffer = malloc(MAX_PATH*sizeof(_TCHAR)); | |
| _TCHAR* tmp; | |
| GetTempPath(MAX_PATH,buffer); | |
| tmp = _ttempnam(buffer,_T_INSTALL("_RITMP")); | |
| _tcscpy(buffer,tmp); | |
| _tcscat(buffer,_T_INSTALL("\\")); | |
| free(tmp); | |
| return buffer; | |
| } |