Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

728 lines
23 KiB

  1. // autorun.cpp: implementation of the CDataSource class for the welcome applet.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include <windows.h>
  5. #include <ntverp.h>
  6. #include <winbase.h>
  7. #include "autorun.h"
  8. #include "resource.h"
  9. #include <tchar.h>
  10. #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
  11. #define MAJOR (VER_PRODUCTMAJORVERSION) // defined in ntverp.h
  12. #define MINOR (VER_PRODUCTMINORVERSION) // defined in ntverp.h
  13. #define BUILD (VER_PRODUCTBUILD) // defined in ntverp.h
  14. #define REG_KEY_OPK _T("SOFTWARE\\Microsoft\\OPK")
  15. #define REG_KEY_OPK_LANGS REG_KEY_OPK _T("\\Langs")
  16. #define REG_VAL_PATH _T("Path")
  17. #define REG_VAL_LANG _T("Lang")
  18. #define STR_VAL_EXE_NAME _T("langinst.exe")
  19. #define STR_VAL_INF_NAME _T("langinst.inf")
  20. #define INF_SEC_STRINGS _T("Strings")
  21. #define INF_KEY_LANG _T("Lang")
  22. // Memory managing macros.
  23. //
  24. #ifdef MALLOC
  25. #undef MALLOC
  26. #endif // MALLOC
  27. #define MALLOC(cb) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb)
  28. #ifdef REALLOC
  29. #undef REALLOC
  30. #endif // REALLOC
  31. #define REALLOC(lp, cb) HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lp, cb)
  32. #ifdef FREE
  33. #undef FREE
  34. #endif // FREE
  35. #define FREE(lp) ( (lp != NULL) ? ( (HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, (LPVOID) lp)) ? ((lp = NULL) == NULL) : (FALSE) ) : (FALSE) )
  36. // I'm doing my own version of these functions because they weren't in win95.
  37. // These come from shell\shlwapi\strings.c.
  38. #ifdef UNIX
  39. #ifdef BIG_ENDIAN
  40. #define READNATIVEWORD(x) MAKEWORD(*(char*)(x), *(char*)((char*)(x) + 1))
  41. #else
  42. #define READNATIVEWORD(x) MAKEWORD(*(char*)((char*)(x) + 1), *(char*)(x))
  43. #endif
  44. #else
  45. #define READNATIVEWORD(x) (*(UNALIGNED WORD *)x)
  46. #endif
  47. LPTSTR RegGetStringEx(HKEY hKeyReg, LPTSTR lpKey, LPTSTR lpValue, BOOL bExpand)
  48. {
  49. HKEY hOpenKey = NULL;
  50. LPTSTR lpBuffer = NULL,
  51. lpExpand = NULL;
  52. DWORD dwSize = 0,
  53. dwType;
  54. // If the key is specified, we must open it. Otherwise we can
  55. // just use the HKEY passed in.
  56. //
  57. if (lpKey)
  58. {
  59. // If the open key fails, return NULL because the value can't exist.
  60. //
  61. if (RegOpenKeyEx(hKeyReg, lpKey, 0, KEY_ALL_ACCESS, &hOpenKey) != ERROR_SUCCESS)
  62. return NULL;
  63. }
  64. else
  65. hOpenKey = hKeyReg;
  66. // Now query the value to get the size to allocate. Make sure the date
  67. // type is a string and that the malloc doesn't fail.
  68. //
  69. if ( ( RegQueryValueEx(hOpenKey, lpValue, NULL, &dwType, NULL, &dwSize) == ERROR_SUCCESS ) &&
  70. ( ( dwType == REG_SZ ) || ( dwType == REG_EXPAND_SZ ) ) &&
  71. ( lpBuffer = (LPTSTR) MALLOC(dwSize) ) )
  72. {
  73. // We know the value exists and we have the memory we need to query the value again.
  74. //
  75. if ( ( RegQueryValueEx(hOpenKey, lpValue, NULL, NULL, (LPBYTE) lpBuffer, &dwSize) == ERROR_SUCCESS ) &&
  76. ( ( dwType == REG_SZ ) || ( dwType == REG_EXPAND_SZ ) ) )
  77. {
  78. // We should expand it if it is supposed to be.
  79. //
  80. if ( ( bExpand ) &&
  81. ( dwType == REG_EXPAND_SZ ) )
  82. {
  83. if ( ( dwSize = ExpandEnvironmentStrings(lpBuffer, NULL, 0) ) &&
  84. ( lpExpand = (LPTSTR) MALLOC(dwSize * sizeof(TCHAR)) ) &&
  85. ( ExpandEnvironmentStrings(lpBuffer, lpExpand, dwSize) ) &&
  86. ( *lpExpand ) )
  87. {
  88. // The expand worked, so free the original buffer and return
  89. // the expanded one.
  90. //
  91. FREE(lpBuffer);
  92. lpBuffer = lpExpand;
  93. }
  94. else
  95. {
  96. // The expand failed see we should free everything up
  97. // and return NULL.
  98. //
  99. FREE(lpExpand);
  100. FREE(lpBuffer);
  101. }
  102. }
  103. }
  104. else
  105. // For some reason the query failed, that shouldn't happen
  106. // but now we need to free and return NULL.
  107. //
  108. FREE(lpBuffer);
  109. }
  110. // If we opened a key, we must close it.
  111. //
  112. if (lpKey)
  113. RegCloseKey(hOpenKey);
  114. // Return the buffer allocated, or NULL if something failed.
  115. //
  116. return lpBuffer;
  117. }
  118. LPTSTR RegGetString(HKEY hKeyReg, LPTSTR lpKey, LPTSTR lpValue)
  119. {
  120. return RegGetStringEx(hKeyReg, lpKey, lpValue, FALSE);
  121. }
  122. /*
  123. * ChrCmp - Case sensitive character comparison for DBCS
  124. * Assumes w1, wMatch are characters to be compared
  125. * Return FALSE if they match, TRUE if no match
  126. */
  127. __inline BOOL ChrCmpA_inline(WORD w1, WORD wMatch)
  128. {
  129. /* Most of the time this won't match, so test it first for speed.
  130. */
  131. if (LOBYTE(w1) == LOBYTE(wMatch))
  132. {
  133. if (IsDBCSLeadByte(LOBYTE(w1)))
  134. {
  135. return(w1 != wMatch);
  136. }
  137. return FALSE;
  138. }
  139. return TRUE;
  140. }
  141. /*
  142. * StrRChr - Find last occurrence of character in string
  143. * Assumes lpStart points to start of string
  144. * lpEnd points to end of string (NOT included in search)
  145. * wMatch is the character to match
  146. * returns ptr to the last occurrence of ch in str, NULL if not found.
  147. */
  148. LPSTR StrRChr(LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch)
  149. {
  150. LPCSTR lpFound = NULL;
  151. ASSERT(lpStart);
  152. ASSERT(!lpEnd || lpEnd <= lpStart + lstrlenA(lpStart));
  153. if (!lpEnd)
  154. lpEnd = lpStart + lstrlenA(lpStart);
  155. for ( ; lpStart < lpEnd; lpStart = AnsiNext(lpStart))
  156. {
  157. // (ChrCmp returns FALSE when characters match)
  158. if (!ChrCmpA_inline(READNATIVEWORD(lpStart), wMatch))
  159. lpFound = lpStart;
  160. }
  161. return ((LPSTR)lpFound);
  162. }
  163. /*
  164. * StrChr - Find first occurrence of character in string
  165. * Assumes lpStart points to start of null terminated string
  166. * wMatch is the character to match
  167. * returns ptr to the first occurrence of ch in str, NULL if not found.
  168. */
  169. LPSTR _StrChrA(LPCSTR lpStart, WORD wMatch, BOOL fMBCS)
  170. {
  171. if (fMBCS) {
  172. for ( ; *lpStart; lpStart = AnsiNext(lpStart))
  173. {
  174. if (!ChrCmpA_inline(READNATIVEWORD(lpStart), wMatch))
  175. return((LPSTR)lpStart);
  176. }
  177. } else {
  178. for ( ; *lpStart; lpStart++)
  179. {
  180. if ((BYTE)*lpStart == LOBYTE(wMatch)) {
  181. return((LPSTR)lpStart);
  182. }
  183. }
  184. }
  185. return (NULL);
  186. }
  187. LPSTR StrChr(LPCSTR lpStart, WORD wMatch)
  188. {
  189. CPINFO cpinfo;
  190. return _StrChrA(lpStart, wMatch, GetCPInfo(CP_ACP, &cpinfo) && cpinfo.LeadByte[0]);
  191. }
  192. // Must match string table entries in resource.rc
  193. //
  194. #define INSTALL_WINNT 0
  195. #define LAUNCH_ARP 1
  196. #define SUPPORT_TOOLS 2
  197. #define OPK_TOOLS 3
  198. #define EXIT_AUTORUN 4
  199. #define BACK 5
  200. #define BROWSE_CD 6
  201. #define HOMENET_WIZ 7
  202. #define TS_CLIENT 8
  203. #define COMPAT_WEB 9
  204. #define MAX_OPTIONS 10
  205. const int c_aiMain[] = {INSTALL_WINNT, SUPPORT_TOOLS, EXIT_AUTORUN};
  206. const int c_aiWhistler[] = {INSTALL_WINNT, LAUNCH_ARP, SUPPORT_TOOLS, EXIT_AUTORUN};
  207. const int c_aiOpk[] = {OPK_TOOLS, BROWSE_CD, EXIT_AUTORUN};
  208. #if BUILD_PERSONAL_VERSION
  209. const int c_aiSupport[] = {HOMENET_WIZ, BROWSE_CD, TS_CLIENT, COMPAT_WEB, BACK};
  210. #else
  211. const int c_aiSupport[] = {TS_CLIENT, COMPAT_WEB, BACK};
  212. #endif
  213. //////////////////////////////////////////////////////////////////////
  214. // Construction/Destruction
  215. //////////////////////////////////////////////////////////////////////
  216. CDataSource::CDataSource()
  217. {
  218. m_iItems = 0;
  219. }
  220. CDataSource::~CDataSource()
  221. {
  222. }
  223. CDataItem & CDataSource::operator[](int i)
  224. {
  225. return m_data[m_piScreen[i]];
  226. }
  227. /*
  228. 10.05.96 Shunichi Kajisa (shunk) Support NEC PC-98
  229. 1. Determine if autorun is running on PC-98 or regular PC/AT by:
  230. bNEC98 = (HIBYTE(LOWORD(GetKeyboardType(1))) == 0x0D)? TRUE : FALSE;
  231. Following description is from KB Q130054, and this can be applied on NT and Win95:
  232. If an application uses the GetKeyboardType API, it can get OEM ID by
  233. specifying "1" (keyboard subtype) as argument of the function. Each OEM ID
  234. is listed here:
  235. OEM Windows OEM ID
  236. ------------------------------
  237. Microsoft 00H (DOS/V)
  238. ....
  239. NEC 0DH
  240. 2. If autorun is running on PC-98, replace every "I386" resource with "PC98" at runtime,
  241. regardless that autorun is running on NT or Win95.
  242. Notes:
  243. - NEC PC-98 is available only in Japan.
  244. - NEC PC-98 uses x86 processor, but the underlaying hardware architecture is different.
  245. The PC98 files is stored under CD:\pc98 directory instead of CD:\i386.
  246. - There was an idea that we should detect PC-98 in SHELL32.DLL, and treat PC98 as a different
  247. platform, like having [AutoRun.Pc98] section in NT CD's autorun.inf. We don't do this, since
  248. Win95 doesn't support this, and we don't want to introduce the apps incompatibility.
  249. In any case, if app has any dependency on the hardware and needs to do any special things,
  250. the app should detect the hardware and OS. This is separate issue from Autorun.exe.
  251. */
  252. BOOL CDataSource::IsNec98()
  253. {
  254. return ((GetKeyboardType(0) == 7) && ((GetKeyboardType(1) & 0xff00) == 0x0d00));
  255. }
  256. void PathRemoveFilespec( LPTSTR psz )
  257. {
  258. TCHAR * pszT = StrRChr( psz, psz+lstrlen(psz)-1, TEXT('\\') );
  259. if (pszT)
  260. *(pszT+1) = NULL;
  261. }
  262. void PathAppend(LPTSTR pszPath, LPTSTR pMore)
  263. {
  264. lstrcpy(pszPath+lstrlen(pszPath), pMore);
  265. }
  266. BOOL PathFileExists( LPTSTR pszPath )
  267. {
  268. BOOL fResult = FALSE;
  269. DWORD dwErrMode;
  270. dwErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  271. fResult = ((UINT)GetFileAttributes(pszPath) != (UINT)-1);
  272. SetErrorMode(dwErrMode);
  273. return fResult;
  274. }
  275. #ifdef BUILD_OPK_VERSION
  276. void RunLangInst(LPTSTR lpszFileName, LPTSTR lpszLangInstInf)
  277. {
  278. STARTUPINFO si;
  279. PROCESS_INFORMATION pi;
  280. TCHAR szCmdLine[MAX_PATH * 2]; // Make sure that we have enough space.
  281. lstrcpyn(szCmdLine, lpszFileName, ARRAYSIZE(szCmdLine) );
  282. lstrcat(szCmdLine, _T(" "));
  283. lstrcpyn(szCmdLine + lstrlen(szCmdLine), lpszLangInstInf, ARRAYSIZE(szCmdLine) - lstrlen(szCmdLine));
  284. ZeroMemory(&si, sizeof(si));
  285. ZeroMemory(&pi, sizeof(pi));
  286. si.cb = sizeof(si);
  287. // Run langinst. Create a message pump so that the window redraws properly.
  288. //
  289. if (CreateProcess(NULL,
  290. szCmdLine,
  291. NULL,
  292. NULL,
  293. FALSE,
  294. 0,
  295. NULL,
  296. NULL,
  297. &si,
  298. &pi))
  299. {
  300. if (NULL != pi.hProcess)
  301. {
  302. CloseHandle(pi.hThread);
  303. CloseHandle(pi.hProcess);
  304. }
  305. }
  306. }
  307. #endif
  308. // Init
  309. //
  310. // For autorun we read all the items out of the resources.
  311. bool CDataSource::Init()
  312. {
  313. // read the text for the items from the resources
  314. HINSTANCE hinst = GetModuleHandle(NULL);
  315. TCHAR szModuleName[MAX_PATH];
  316. TCHAR szTitle[256];
  317. TCHAR szDesc[1024];
  318. TCHAR szMenu[256];
  319. TCHAR szConfig[MAX_PATH];
  320. TCHAR szArgs[MAX_PATH];
  321. szModuleName[0] = TEXT('\0'); // in case GetModuleFileName fails to initialize szModuleName
  322. GetModuleFileName(hinst, szModuleName, ARRAYSIZE(szModuleName)); // ex: "e:\i386\autorun.exe" or "e:\setup.exe"
  323. PathRemoveFilespec(szModuleName); // ex: "e:\i386\" or "e:\"
  324. PathAppend(szModuleName, TEXT("winnt32.exe")); //
  325. if ( PathFileExists(szModuleName) )
  326. {
  327. // we were launched from the platform directory, use szModuleName as the winnt32 path
  328. }
  329. else
  330. {
  331. // we were launched from the root. Append either "alpha", "i386", or "NEC98" to the path.
  332. SYSTEM_INFO si;
  333. PathRemoveFilespec(szModuleName);
  334. GetSystemInfo(&si);
  335. #if !(defined(_AMD64_) || defined(_X86_) || defined(_IA64_))
  336. #error New architecture must be added to switch statement.
  337. #endif
  338. switch (si.wProcessorArchitecture)
  339. {
  340. case PROCESSOR_ARCHITECTURE_AMD64:
  341. {
  342. PathAppend(szModuleName, TEXT("amd64\\winnt32.exe"));
  343. }
  344. case PROCESSOR_ARCHITECTURE_IA64:
  345. {
  346. PathAppend(szModuleName, TEXT("ia64\\winnt32.exe"));
  347. }
  348. break;
  349. case PROCESSOR_ARCHITECTURE_INTEL:
  350. default:
  351. {
  352. if (IsNec98())
  353. {
  354. PathAppend(szModuleName, TEXT("nec98\\winnt32.exe"));
  355. }
  356. else
  357. {
  358. PathAppend(szModuleName, TEXT("i386\\winnt32.exe"));
  359. }
  360. }
  361. break;
  362. }
  363. }
  364. for (int i=0; i<MAX_OPTIONS; i++)
  365. {
  366. LoadString(hinst, IDS_TITLE0+i, szTitle, ARRAYSIZE(szTitle));
  367. LoadString(hinst, IDS_MENU0+i, szMenu, ARRAYSIZE(szMenu));
  368. LoadString(hinst, IDS_DESC0+i, szDesc, ARRAYSIZE(szDesc));
  369. // for INSTALL_WINNT we prepend the correct path to winnt32 in front of the string
  370. if ( INSTALL_WINNT == i )
  371. {
  372. lstrcpy( szConfig, szModuleName );
  373. if ( !PathFileExists(szModuleName) )
  374. {
  375. // we can't run the item if it's not there. This will prevent an
  376. // alpha CD from trying to install on an x86 and vice versa.
  377. m_data[INSTALL_WINNT].m_dwFlags |= WF_DISABLED|WF_ALTERNATECOLOR;
  378. }
  379. }
  380. // Copied this code from nt\shell\applets\autorun\autorun.cpp
  381. //
  382. else if (BROWSE_CD == i) // for BROWSE_CD we pass the directory as an argument to explorer.exe
  383. {
  384. // PathRemoveFileSpce twice to remove the path added to module name above.
  385. // This is really crappy code!!!
  386. //
  387. lstrcpy( szArgs, szModuleName );
  388. PathRemoveFilespec( szArgs );
  389. PathRemoveFilespec( szArgs );
  390. LoadString(hinst, IDS_CONFIG0+i, szConfig, ARRAYSIZE(szConfig));
  391. }
  392. else
  393. {
  394. LoadString(hinst, IDS_CONFIG0+i, szConfig, ARRAYSIZE(szConfig));
  395. LoadString(hinst, IDS_ARGS0+i, szArgs, ARRAYSIZE(szArgs));
  396. }
  397. m_data[i].SetData( szTitle, szMenu, szDesc, szConfig, *szArgs?szArgs:NULL, 0, (i+1)%4 );
  398. //these are not implemented yet
  399. switch (i)
  400. {
  401. case HOMENET_WIZ:
  402. case TS_CLIENT:
  403. case COMPAT_WEB:
  404. m_data[i].m_dwFlags |= WF_DISABLED|WF_ALTERNATECOLOR;
  405. break;
  406. default:
  407. break;
  408. }
  409. }
  410. // Should we display the "This CD contains a newer version" dialog?
  411. OSVERSIONINFO ovi;
  412. ovi.dwOSVersionInfoSize = sizeof ( OSVERSIONINFO );
  413. if ( !GetVersionEx(&ovi) || ovi.dwPlatformId==VER_PLATFORM_WIN32s )
  414. {
  415. // We cannot upgrade win32s systems.
  416. m_Version = VER_INCOMPATIBLE;
  417. }
  418. else if ( ovi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS )
  419. {
  420. if (ovi.dwMajorVersion > 3)
  421. {
  422. // we can always upgrade win98+ systems to NT
  423. m_Version = VER_OLDER;
  424. // Disable ARP. ARP is only enabled if the CD and the OS are the same version
  425. m_data[LAUNCH_ARP].m_dwFlags |= WF_DISABLED|WF_ALTERNATECOLOR;
  426. }
  427. else
  428. {
  429. m_Version = VER_INCOMPATIBLE;
  430. }
  431. }
  432. else if ((MAJOR > ovi.dwMajorVersion) ||
  433. ((MAJOR == ovi.dwMajorVersion) && ((MINOR > ovi.dwMinorVersion) || ((MINOR == ovi.dwMinorVersion) && (BUILD > ovi.dwBuildNumber)))))
  434. {
  435. // For NT to NT upgrades, we only upgrade if the version is lower
  436. // For NT 3.51 we have some special case code
  437. if ( ovi.dwMajorVersion == 3 )
  438. {
  439. // must be at least NT 3.51
  440. if ( ovi.dwMinorVersion < 51 )
  441. {
  442. // On NT 3.1 we might be able to launch winnt32.exe
  443. STARTUPINFO sinfo =
  444. {
  445. sizeof(STARTUPINFO),
  446. };
  447. PROCESS_INFORMATION pinfo;
  448. CreateProcess(NULL,szModuleName,NULL,NULL,FALSE,0,NULL,NULL,&sinfo,&pinfo);
  449. return FALSE;
  450. }
  451. }
  452. m_Version = VER_OLDER;
  453. // Disable ARP. ARP is only enabled if the CD and the OS are the same version
  454. m_data[LAUNCH_ARP].m_dwFlags |= WF_DISABLED|WF_ALTERNATECOLOR;
  455. }
  456. else if ((MAJOR < ovi.dwMajorVersion) || (MINOR < ovi.dwMinorVersion) || (BUILD < ovi.dwBuildNumber))
  457. {
  458. m_Version = VER_NEWER;
  459. // disable upgrade and ARP buttons
  460. m_data[INSTALL_WINNT].m_dwFlags |= WF_DISABLED|WF_ALTERNATECOLOR;
  461. m_data[LAUNCH_ARP].m_dwFlags |= WF_DISABLED|WF_ALTERNATECOLOR;
  462. }
  463. else
  464. {
  465. m_Version = VER_SAME;
  466. }
  467. #ifdef BUILD_OPK_VERSION
  468. //
  469. // We don't support Win9x and NT 4 or older
  470. //
  471. if ( (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) ||
  472. ((ovi.dwMajorVersion <= 4) && (ovi.dwPlatformId==VER_PLATFORM_WIN32_NT))
  473. )
  474. {
  475. return DisplayErrorMessage(IDS_WRONGOS);
  476. }
  477. m_piScreen = c_aiOpk;
  478. m_iItems = ARRAYSIZE(c_aiOpk);
  479. #else
  480. if (m_Version == VER_SAME)
  481. {
  482. m_piScreen = c_aiWhistler;
  483. m_iItems = ARRAYSIZE(c_aiWhistler);
  484. }
  485. else
  486. {
  487. m_piScreen = c_aiMain;
  488. m_iItems = ARRAYSIZE(c_aiMain);
  489. }
  490. #endif
  491. return true;
  492. }
  493. void CDataSource::Invoke( int i, HWND hwnd )
  494. {
  495. i = m_piScreen[i];
  496. // if this item is disalbled then do nothing
  497. if ( m_data[i].m_dwFlags & WF_DISABLED )
  498. {
  499. MessageBeep(0);
  500. return;
  501. }
  502. // otherwise we have already built the correct command and arg strings so just invoke them
  503. switch (i)
  504. {
  505. case INSTALL_WINNT:
  506. case LAUNCH_ARP:
  507. m_data[i].Invoke(hwnd);
  508. break;
  509. case EXIT_AUTORUN:
  510. DestroyWindow( m_hwndDlg );
  511. PostQuitMessage( 0 );
  512. break;
  513. #ifdef BUILD_OPK_VERSION
  514. case OPK_TOOLS:
  515. {
  516. LPTSTR lpPath;
  517. LPTSTR lpLang;
  518. TCHAR szBuffer[10] = TEXT(""); // Languages are normally 3 characters.
  519. BOOL bLangInstRun = FALSE;
  520. // Check here to see if the opktools are installed already.
  521. // If they are, and the language we are trying to install is different
  522. // then run langinst.exe instead of the msi.
  523. //
  524. lpPath = RegGetString(HKEY_LOCAL_MACHINE, REG_KEY_OPK, REG_VAL_PATH);
  525. lpLang = RegGetString(HKEY_LOCAL_MACHINE, REG_KEY_OPK, REG_VAL_LANG);
  526. if ( lpPath && lpLang)
  527. {
  528. TCHAR szLangInstExe[MAX_PATH];
  529. TCHAR szLangInstInf[MAX_PATH] = TEXT("\0");
  530. // Build the path to the langinst.inf from the install media.
  531. //
  532. GetModuleFileName(NULL, szLangInstInf, MAX_PATH);
  533. PathRemoveFilespec(szLangInstInf);
  534. PathAppend(szLangInstInf, STR_VAL_INF_NAME);
  535. // Create the path to point to langinst.exe that's installed on the system.
  536. //
  537. lstrcpy(szLangInstExe, lpPath);
  538. PathAppend(szLangInstExe, STR_VAL_EXE_NAME);
  539. // Only run langinst if the language that is installed on the machine is different than
  540. // the language we are trying to install.
  541. //
  542. if ( GetPrivateProfileString(INF_SEC_STRINGS, INF_KEY_LANG, _T(""), szBuffer, ARRAYSIZE(szBuffer), szLangInstInf) &&
  543. szBuffer[0] &&
  544. (0 != lstrcmpi(szBuffer, lpLang))
  545. )
  546. {
  547. // Remove the inf name from the path.
  548. //
  549. PathRemoveFilespec(szLangInstInf);
  550. if ( PathFileExists( szLangInstExe ) )
  551. {
  552. // Run langinst.exe if it's there on the disk but with the langinst.inf from the
  553. // install media
  554. //
  555. RunLangInst(szLangInstExe, szLangInstInf);
  556. bLangInstRun = TRUE;
  557. }
  558. }
  559. }
  560. // If Langinst.exe did not run for any reason just run the opk.msi.
  561. //
  562. if ( !bLangInstRun )
  563. {
  564. m_data[i].Invoke(hwnd);
  565. }
  566. FREE(lpPath); // MACRO checks for NULL
  567. FREE(lpLang); // MACRO checks for NULL
  568. PostQuitMessage(0);
  569. break;
  570. }
  571. case BROWSE_CD:
  572. m_data[i].Invoke(hwnd);
  573. break;
  574. #endif
  575. case SUPPORT_TOOLS:
  576. m_piScreen = c_aiSupport;
  577. m_iItems = ARRAYSIZE(c_aiSupport);
  578. PostMessage(m_hwndDlg, ARM_CHANGESCREEN, 0, 0);
  579. break;
  580. case BACK:
  581. if (m_Version == VER_SAME)
  582. {
  583. m_piScreen = c_aiWhistler;
  584. m_iItems = ARRAYSIZE(c_aiWhistler);
  585. }
  586. else
  587. {
  588. m_piScreen = c_aiMain;
  589. m_iItems = ARRAYSIZE(c_aiMain);
  590. }
  591. PostMessage(m_hwndDlg, ARM_CHANGESCREEN, 0, 0);
  592. break;
  593. default:
  594. // Assert? Debug trace message?
  595. break;
  596. }
  597. }
  598. // Uninit
  599. //
  600. // This is a chance to do any required shutdown stuff, such as persisting state information.
  601. void CDataSource::Uninit(DWORD dwData)
  602. {
  603. }
  604. // ShowSplashScreen
  605. //
  606. // This hook is provided to allow the display of additional UI right after the main window is diaplyed.
  607. // In our case we want to show a dialog asking if the user wants to upgrade.
  608. void CDataSource::ShowSplashScreen(HWND hwnd)
  609. {
  610. m_hwndDlg = hwnd;
  611. }
  612. // DisplayMessage
  613. //
  614. // Displays the ids in a message box and returns false so we quit the app.
  615. //
  616. bool CDataSource::DisplayErrorMessage(int ids)
  617. {
  618. HINSTANCE hinst = GetModuleHandle(NULL);
  619. TCHAR szMessage[256], szTitle[256];
  620. if (hinst)
  621. {
  622. LoadString(hinst, IDS_TITLE_OPK, szTitle, ARRAYSIZE(szTitle));
  623. LoadString(hinst, ids, szMessage, ARRAYSIZE(szMessage));
  624. MessageBox(0, szMessage, szTitle, MB_ICONSTOP|MB_OK);
  625. }
  626. return false;
  627. }