/* * update.cpp -- Windows Update for DirectInput Device Configurations and Images * * History: * 4-22-00 qzheng First version * */ #include #include #include #include #include #include #include #include "cpanel.h" extern HINSTANCE ghInstance; extern PJOY pAssigned[MAX_ASSIGNED]; // List of assigned devices extern short iItem; extern IDirectInputJoyConfig *pDIJoyConfig; static TCHAR tszFtpAgent[] = TEXT("Game Control Panel"); static TCHAR tszUpdateSite[] = TEXT("ftp.microsoft.com"); //???? static TCHAR tszUpdateSiteUser[] = TEXT("anonymous"); static TCHAR tszUpdateSitePass[] = TEXT("anonymous@microsoft.com"); static TCHAR tszFormatRundll9x[] = TEXT("rundll.exe setupx.dll,InstallHinfSection DefaultInstall 4 "); static TCHAR tszFormatRundllNT[] = TEXT("\\system32\\rundll32.exe syssetup.dll,SetupInfObjectInstallAction DefaultInstall 4 "); static TCHAR tszUpdateInf[] = TEXT("dimapins.inf"); // Global variable holding destination directory. static HINTERNET hOpen, hConnect; static DWORD dwType = FTP_TRANSFER_TYPE_BINARY; static TCHAR tszTargetPath[MAX_PATH]; static BOOL Open(TCHAR *tszHost, TCHAR *tszUser, TCHAR *tszPass); static BOOL Close(HINTERNET hConnect); static BOOL ErrorOut( DWORD dError, TCHAR *szCallFunc); static BOOL lcd(TCHAR *tszDir); static BOOL rcd(TCHAR *tszDir); static void GetCurDeviceType(HWND hDlg, TCHAR *tszDeviceType); static void ExtractCabinet(PTSTR pszCabFile); static void ApplyUpdateInf( void ); /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: Update // // PURPOSE: Update device configuration files and image if there are new // ones on Windows Update Server. // /////////////////////////////////////////////////////////////////////////////// void Update(HWND hDlg, int nAccess, TCHAR *tszProxy) { TCHAR tszWinDir[STR_LEN_64]; TCHAR tszLocalIni[MAX_PATH]; TCHAR tszTempDir[MAX_PATH]; TCHAR tszRemoteIni[MAX_PATH]; TCHAR tszDeviceType[MAX_PATH]; TCHAR tszDeviceCabFile[MAX_PATH]; TCHAR tszBuf[MAX_PATH]; OFSTRUCT ofs; HANDLE hIniFile; FILETIME ftLocalTime, ftRemoteTime, ftCT, ftLAT; TCHAR tszUpdateSiteDir[STR_LEN_32]; TCHAR tszUpdateIniFile[STR_LEN_32]; TCHAR tszLastUpdate[STR_LEN_32]; BOOL fLocalIniExist; // nAccess: 1 - don't use proxy, default // 2 - use proxy switch (nAccess) { case 1: // No proxy specified. Open WININET.DLL w/ local access if ( !(hOpen = InternetOpen( tszFtpAgent, LOCAL_INTERNET_ACCESS , NULL, 0, 0) ) ) { ErrorOut( GetLastError(), TEXT("InternetOpen")); return ; } break; case 2: // Specified proxy, Open WININET.DLL w/ Proxy if ( !(hOpen = InternetOpen( tszFtpAgent, CERN_PROXY_INTERNET_ACCESS, tszProxy, NULL, 0) ) ) { ErrorOut( GetLastError(), TEXT("InternetOpen")); return ; } break; default: return; } if ( !Open(tszUpdateSite, tszUpdateSiteUser, tszUpdateSitePass) ){ Error((short)IDS_UPDATE_NOTCONNECTED_TITLE, (short)IDS_UPDATE_NOTCONNECTED); return; } LoadString(ghInstance, IDS_UPDATE_SITEDIR, tszUpdateSiteDir, sizeof(tszUpdateSiteDir) ); LoadString(ghInstance, IDS_UPDATE_INI, tszUpdateIniFile, sizeof(tszUpdateIniFile) ); LoadString(ghInstance, IDS_UPDATE_LASTUPDATED, tszLastUpdate, sizeof(tszLastUpdate) ); GetCurDeviceType( hDlg, tszDeviceType ); // The following codes are to get last modified time of the local Ini file ($windir\dinputup.ini). GetWindowsDirectory( tszWinDir, sizeof(tszWinDir) ); lstrcpy( tszLocalIni, tszWinDir ); lstrcat( tszLocalIni, TEXT("\\") ); lstrcat( tszLocalIni, tszUpdateIniFile ); hIniFile = CreateFile(tszLocalIni, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if( hIniFile != INVALID_HANDLE_VALUE ) { GetFileTime( hIniFile, &ftCT, &ftLAT, &ftLocalTime ); CloseHandle(hIniFile); fLocalIniExist = TRUE; } else { //the local dinputup.ini doesn't exist. fLocalIniExist = FALSE; ErrorOut(GetLastError(), TEXT("CreateFile(dinputup.ini) fails or file doesn't exist")); } // wsprintf( tszBuf, TEXT("%lx,%lx"), ftLWT.dwHighDateTime, ftLWT.dwLowDateTime ); // lstrcpy( tszDeviceType, TEXT("VID_046D&PID_C207")); // WritePrivateProfileString( tszDeviceType, tszLastUpdate, tszBuf, tszUpdateIniFile); // The following codes are to get last modified time of the remote Ini file // on Windows Update server. GetTempPath( sizeof(tszTempDir), tszTempDir ); lcd( tszTempDir ); lstrcpy( tszRemoteIni, tszTempDir ); lstrcat( tszRemoteIni, TEXT("\\") ); lstrcat( tszRemoteIni, tszUpdateIniFile ); rcd( tszUpdateSiteDir ); // change to proper directory on Windows Update Server. if ( !FtpGetFile(hConnect, tszUpdateIniFile, tszUpdateIniFile, FALSE, 0, INTERNET_FLAG_RELOAD | dwType, 0) ) { ErrorOut(GetLastError(), TEXT("FtpGetFile")); Error((short)IDS_UPDATE_NOTCONNECTED_TITLE, (short)IDS_UPDATE_FTP_ERROR); goto _CLOSE; } hIniFile = CreateFile(tszRemoteIni, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if( hIniFile != INVALID_HANDLE_VALUE ) { GetFileTime( hIniFile, &ftCT, &ftLAT, &ftRemoteTime ); CloseHandle(hIniFile); } else { ErrorOut(GetLastError(), TEXT("CreateFile on Remote Ini file")); goto _CLOSE; } if( !fLocalIniExist || (CompareFileTime(&ftLocalTime, &ftRemoteTime) < 0) ) { // remote one is newer, overwrite local one. CopyFile( tszRemoteIni, tszLocalIni, FALSE ); } lstrcpy( tszDeviceCabFile, tszDeviceType ); lstrcat( tszDeviceCabFile, TEXT(".cab") ); if (!FtpGetFile(hConnect, tszDeviceCabFile, tszDeviceCabFile, FALSE, 0, INTERNET_FLAG_RELOAD | dwType, 0 ) ) { ErrorOut(GetLastError(), TEXT("FtpGetFile")); Error((short)IDS_UPDATE_NOTCONNECTED_TITLE, (short)IDS_UPDATE_FTP_ERROR); goto _CLOSE; } lstrcpy( tszTargetPath, tszTempDir ); lstrcat( tszTargetPath, TEXT("\\") ); lstrcpy( tszBuf, tszTempDir ); lstrcat( tszBuf, TEXT("\\")); lstrcat( tszBuf, tszDeviceCabFile ); // extract cab file ExtractCabinet( tszBuf ); // apply update inf file ApplyUpdateInf(); _CLOSE: Close(hConnect); return; } /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: lcd // // PURPOSE: Change to new directory on local // /////////////////////////////////////////////////////////////////////////////// BOOL lcd(TCHAR *tszDir) { if ((*tszDir != 0) && (_tchdir(tszDir) == -1)) { #ifdef _DEBUG OutputDebugString(TEXT("?Invalid Local Directory")); #endif return FALSE; } return TRUE; } /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: rcd // // PURPOSE: Change to new directory on remote side // /////////////////////////////////////////////////////////////////////////////// BOOL rcd(TCHAR *tszDir) { BOOL fRtn = FALSE; if (*tszDir != 0) { if (!FtpSetCurrentDirectory(hConnect, tszDir)) { ErrorOut(GetLastError(), TEXT("FtpSetCurrentDirectory")); fRtn = FALSE; } fRtn = TRUE; } return fRtn; } /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: Open // // PURPOSE: Open an Internect connection to a host. // /////////////////////////////////////////////////////////////////////////////// BOOL Open(TCHAR *tszHost, TCHAR *tszUser, TCHAR *tszPass) { if ( !(hConnect = InternetConnect( hOpen, tszHost , INTERNET_INVALID_PORT_NUMBER, tszUser, tszPass, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE , 0) ) ) { ErrorOut(GetLastError(), TEXT("InternetConnect")); return FALSE; } return TRUE; } /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: Close // // PURPOSE: Close the opened connection (hConnect) // /////////////////////////////////////////////////////////////////////////////// BOOL Close(HINTERNET hConnect) { if (!InternetCloseHandle (hConnect) ) { ErrorOut(GetLastError(), TEXT("InternetCloseHandle")); return FALSE; } return TRUE; } /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: ErrorOut // // PURPOSE: This function is used to get extended Internet error. // // COMMENTS: Function returns TRUE on success and FALSE on failure. // /////////////////////////////////////////////////////////////////////////////// BOOL ErrorOut( DWORD dError, TCHAR *szCallFunc) { #ifdef _DEBUG TCHAR szTemp[100] = "", *szBuffer=NULL, *szBufferFinal = NULL; DWORD dwIntError , dwLength = 0; wsprintf (szTemp, "%s error %d\n ", szCallFunc, dError ); if (dError == ERROR_INTERNET_EXTENDED_ERROR) { InternetGetLastResponseInfo (&dwIntError, NULL, &dwLength); if (dwLength) { if ( !(szBuffer = (TCHAR *) LocalAlloc ( LPTR, dwLength) ) ) { lstrcat (szTemp, TEXT ( "Unable to allocate memory to display Internet error code. Error code: ") ); lstrcat (szTemp, TEXT (_itoa (GetLastError(), szBuffer, 10) ) ); lstrcat (szTemp, TEXT ("\n") ); OutputDebugString(szTemp); return FALSE; } if (!InternetGetLastResponseInfo(&dwIntError, (LPTSTR) szBuffer, &dwLength)) { lstrcat (szTemp, TEXT ( "Unable to get Internet error. Error code: ") ); lstrcat (szTemp, TEXT (_itoa (GetLastError(), szBuffer, 10) ) ); lstrcat (szTemp, TEXT ("\n") ); OutputDebugString(szTemp); return FALSE; } if ( !(szBufferFinal = (TCHAR *) LocalAlloc( LPTR, (strlen (szBuffer) +strlen (szTemp) + 1) ) ) ) { lstrcat (szTemp, TEXT ( "Unable to allocate memory. Error code: ") ); lstrcat (szTemp, TEXT (_itoa (GetLastError(), szBuffer, 10) ) ); lstrcat (szTemp, TEXT ("\n") ); OutputDebugString(szTemp0; return FALSE; } lstrcpy (szBufferFinal, szTemp); lstrcat (szBufferFinal, szBuffer); LocalFree (szBuffer); OutputDebugString(szBufferFinal); LocalFree (szBufferFinal); } } else { OutputDebugString(szTemp); } #endif // _DEBUG return TRUE; } /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: CabinetCallback // // PURPOSE: Callback used in ExtractCabinet // /////////////////////////////////////////////////////////////////////////////// LRESULT WINAPI CabinetCallback ( IN PVOID pMyInstallData, IN UINT Notification, IN UINT Param1, IN UINT Param2 ) { LRESULT lRetVal = NO_ERROR; TCHAR szTarget[MAX_PATH]; FILE_IN_CABINET_INFO *pInfo = NULL; FILEPATHS *pFilePaths = NULL; lstrcpy(szTarget,tszTargetPath); switch(Notification) { case SPFILENOTIFY_FILEINCABINET: pInfo = (FILE_IN_CABINET_INFO *)Param1; lstrcat(szTarget, pInfo->NameInCabinet); lstrcpy(pInfo->FullTargetName, szTarget); lRetVal = FILEOP_DOIT; // Extract the file. break; case SPFILENOTIFY_FILEEXTRACTED: pFilePaths = (FILEPATHS *)Param1; lRetVal = NO_ERROR; break; case SPFILENOTIFY_NEEDNEWCABINET: // Unexpected. lRetVal = NO_ERROR; break; } return lRetVal; } /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: ExtractCabinet // // PURPOSE: Extract all files stored in the cab file. // /////////////////////////////////////////////////////////////////////////////// void ExtractCabinet(PTSTR pszCabFile) { if( !SetupIterateCabinet(pszCabFile, 0, (PSP_FILE_CALLBACK)CabinetCallback, 0) ) { ErrorOut( GetLastError(), TEXT("Extract Cab File") ); } } /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: ApplyUpdateInf // // PURPOSE: Run dimapins.inf to install configuration files and images // /////////////////////////////////////////////////////////////////////////////// void ApplyUpdateInf( void ) { TCHAR tszRundll[1024]; STARTUPINFO si; PROCESS_INFORMATION pi; GetWindowsDirectory(tszRundll, sizeof(tszRundll)); #ifdef _UNICODE lstrcat(tszRundll, tszFormatRundllNT); #else lstrcat(tszRundll, tszFormatRundll9x); #endif lstrcat(tszRundll, tszTargetPath); lstrcat(tszRundll, tszUpdateInf); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); if( CreateProcess(0, tszRundll, 0, 0, 0, 0, 0, 0, &si, &pi) ) { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } #ifdef _DEBUG else { OutputDebugString(TEXT("JOY.CPL: ApplyUpdateInf: CreateProcess Failed!\n")); } #endif } INT_PTR CALLBACK CplUpdateProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { BOOL fRet = FALSE; // HICON hIcon; switch (message) { case WM_INITDIALOG: // hIcon = LoadIcon(NULL, IDI_INFORMATION); // SendDlgItemMessage(hDlg, IDC_ICON_INFORMATION, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); fRet = TRUE; break; default: break; } break; default: break; } return fRet; } /////////////////////////////////////////////////////////////////////////////// // // FUNCTION: GetCurDeviceType // // PURPOSE: Get device type of the current selected device // /////////////////////////////////////////////////////////////////////////////// void GetCurDeviceType(HWND hDlg, TCHAR *tszDeviceType) { DIJOYCONFIG_DX5 diJoyConfig; HWND hListCtrl; int id; hListCtrl = GetDlgItem(hDlg, IDC_LIST_DEVICE); id = GetItemData(hListCtrl, (BYTE)iItem); ZeroMemory(&diJoyConfig, sizeof(DIJOYCONFIG_DX5)); diJoyConfig.dwSize = sizeof(DIJOYCONFIG_DX5); // find the assigned ID's if( SUCCEEDED(pDIJoyConfig->GetConfig(pAssigned[id]->ID, (LPDIJOYCONFIG)&diJoyConfig, DIJC_REGHWCONFIGTYPE)) ) { #ifdef _UNICODE lstrcpy(tszDeviceType, diJoyConfig.wszType ); #else USES_CONVERSION; lstrcpy(tszDeviceType, W2A(diJoyConfig.wszType) ); #endif } #if 0 // change '&' to '_' while( tszDeviceType ) { if( *tszDeviceType == TEXT('&') ) { *tszDeviceType = TEXT('_'); } tszDeviceType++; } #endif return; }