Source code of Windows XP (NT5)
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.

686 lines
16 KiB

  1. #define STRICT
  2. #define LEAN_AND_MEAN
  3. #include <windows.h>
  4. #include <setupapi.h>
  5. #include <assert.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <mbstring.h>
  9. #include "miginf.h"
  10. #define DIRECTORYKEY "SOFTWARE\\Microsoft\\DevStudio\\5.0\\Products\\Microsoft Visual C++"
  11. #define DIRECTORYVALUE "ProductDir"
  12. #define DIR_95SPECIFIC "\\bin\\win95"
  13. #define FILE_PVIEW "pview.exe"
  14. #define MESSAGE \
  15. "PVIEW.EXE has been found in one or more directories outside of your Visual C++ 5.0" \
  16. " installation directory. These copies will not be updated with the NT version." \
  17. #define MESSAGE_SECTION "Microsoft\\Visual C++ 5.0\\Process Viewer"
  18. #define SIZENEEDED 100000L
  19. #define CP_USASCII 1252
  20. //
  21. // 9x side globals.
  22. //
  23. const CHAR g_ProductId[] = {"Microsoft Visual C++ 5.0"};
  24. UINT g_DllVersion = 1;
  25. INT g_CodePageArray[] = {CP_USASCII,-1};
  26. CHAR g_ExeNamesBuffer[] = {"pview95.exe\0""\0"};
  27. //
  28. // Nt side globals.
  29. //
  30. //
  31. // Uncomment next line to get popups.
  32. //
  33. //#define MYDEBUG
  34. #ifdef MYDEBUG
  35. # define INFO(x) (MessageBoxA(NULL,(x),"PVIEW Sample Migration Dll",MB_OK | MB_ICONINFORMATION))
  36. #else
  37. # define INFO(x)
  38. #endif
  39. static
  40. BOOL
  41. PathIsInPath(
  42. IN PCSTR SubPath,
  43. IN PCSTR ParentPath
  44. )
  45. {
  46. DWORD parentLength;
  47. BOOL rInPath;
  48. //
  49. // This function assumes both parameters are non-NULL.
  50. //
  51. assert(SubPath);
  52. assert(ParentPath);
  53. parentLength = _mbslen(ParentPath);
  54. //
  55. // A path is considered "in" another path if the path is in the ParentPath
  56. // or a subdirectory of it.
  57. //
  58. rInPath = !_mbsnicmp(SubPath,ParentPath,parentLength);
  59. if (rInPath) {
  60. rInPath = SubPath[parentLength] == 0 || SubPath[parentLength] == '\\';
  61. }
  62. return rInPath;
  63. }
  64. static
  65. PSTR
  66. GetPviewDirectoryNt (
  67. VOID
  68. )
  69. {
  70. HKEY softwareKey;
  71. LONG rc;
  72. LONG valueType;
  73. LONG sizeNeeded;
  74. PSTR rString = NULL;
  75. //
  76. // First, open the key.
  77. //
  78. rc = RegOpenKeyEx(
  79. HKEY_LOCAL_MACHINE,
  80. DIRECTORYKEY,
  81. 0,
  82. KEY_READ,
  83. &softwareKey
  84. );
  85. if (rc == ERROR_SUCCESS) {
  86. //
  87. // Determine how large of a buffer to allocate.
  88. //
  89. rc = RegQueryValueEx(
  90. softwareKey,
  91. DIRECTORYVALUE,
  92. 0,
  93. &valueType,
  94. NULL,
  95. &sizeNeeded
  96. );
  97. //
  98. // Allocate enough space for the registry path, with the additional
  99. // subpath to Visual C++ 5.0's win 95 specific binaries.
  100. //
  101. rString = LocalAlloc(0,sizeNeeded + lstrlen(DIR_95SPECIFIC) + 1);
  102. }
  103. if (rc == ERROR_SUCCESS && rString != NULL) {
  104. //
  105. // Read in the buffer.
  106. //
  107. rc = RegQueryValueEx(
  108. softwareKey,
  109. DIRECTORYVALUE,
  110. 0,
  111. &valueType,
  112. (PBYTE) rString,
  113. &sizeNeeded
  114. );
  115. if (rc == ERROR_SUCCESS) {
  116. if (valueType != REG_SZ) {
  117. rc = ERROR_INVALID_DATATYPE;
  118. }
  119. }
  120. }
  121. //
  122. // If we didn't complete successfully, set the last error, and free the
  123. // return string if it was allocated.
  124. //
  125. if (rc != ERROR_SUCCESS) {
  126. SetLastError(rc);
  127. if (rString) {
  128. LocalFree(rString);
  129. rString = NULL;
  130. }
  131. }
  132. return rString;
  133. }
  134. static
  135. PSTR
  136. GetPviewDirectory9x (
  137. VOID
  138. )
  139. {
  140. HKEY softwareKey;
  141. LONG rc;
  142. LONG valueType;
  143. LONG sizeNeeded;
  144. PSTR rString = NULL;
  145. //
  146. // First, open the key.
  147. //
  148. rc = RegOpenKeyEx(
  149. HKEY_LOCAL_MACHINE,
  150. DIRECTORYKEY,
  151. 0,
  152. KEY_READ,
  153. &softwareKey
  154. );
  155. if (rc == ERROR_SUCCESS) {
  156. //
  157. // Determine how large of a buffer to allocate.
  158. //
  159. rc = RegQueryValueEx(
  160. softwareKey,
  161. DIRECTORYVALUE,
  162. 0,
  163. &valueType,
  164. NULL,
  165. &sizeNeeded
  166. );
  167. //
  168. // Allocate enough space for the registry path, with the additional
  169. // subpath to Visual C++ 5.0's win 95 specific binaries.
  170. //
  171. rString = LocalAlloc(0,sizeNeeded + lstrlen(DIR_95SPECIFIC) + 1);
  172. }
  173. if (rc == ERROR_SUCCESS && rString != NULL) {
  174. //
  175. // Read in the buffer.
  176. //
  177. rc = RegQueryValueEx(
  178. softwareKey,
  179. DIRECTORYVALUE,
  180. 0,
  181. &valueType,
  182. (PBYTE) rString,
  183. &sizeNeeded
  184. );
  185. if (rc == ERROR_SUCCESS) {
  186. if (valueType == REG_SZ) {
  187. //
  188. // We have successfully read in the value of the installation
  189. // directory into rString. Now, all we need to do is tack on
  190. // the win 95 specific portion that we care about.
  191. //
  192. lstrcat(rString,DIR_95SPECIFIC);
  193. }
  194. else {
  195. rc = ERROR_INVALID_DATATYPE;
  196. }
  197. }
  198. }
  199. //
  200. // If we didn't complete successfully, set the last error, and free the
  201. // return string if it was allocated.
  202. //
  203. if (rc != ERROR_SUCCESS) {
  204. SetLastError(rc);
  205. if (rString) {
  206. LocalFree(rString);
  207. rString = NULL;
  208. }
  209. }
  210. return rString;
  211. }
  212. static
  213. LONG
  214. CheckForInstalledComponents (
  215. VOID
  216. )
  217. {
  218. BOOL rc;
  219. HKEY softwareKey;
  220. //
  221. // Attempt to open the key.
  222. //
  223. rc = RegOpenKeyEx(
  224. HKEY_LOCAL_MACHINE,
  225. DIRECTORYKEY,
  226. 0,
  227. KEY_READ,
  228. &softwareKey
  229. );
  230. //
  231. // If the key exists, then assume that Microsoft Visual C++ 5.0 is installed.
  232. //
  233. RegCloseKey(softwareKey);
  234. return rc;
  235. }
  236. BOOL
  237. WINAPI
  238. DllMain (
  239. IN HANDLE Instance,
  240. IN ULONG Reason,
  241. IN LPVOID Reserved
  242. )
  243. {
  244. switch (Reason) {
  245. case DLL_PROCESS_ATTACH:
  246. break;
  247. case DLL_PROCESS_DETACH:
  248. //
  249. // Ensure that the MigInf structure is cleaned up before unloading this DLL.
  250. //
  251. MigInf_CleanUp();
  252. break;
  253. }
  254. return TRUE;
  255. }
  256. LONG
  257. CALLBACK
  258. QueryVersion (
  259. OUT LPCSTR * ProductId,
  260. OUT LPUINT DllVersion,
  261. OUT LPINT * CodePageArray, OPTIONAL
  262. OUT LPCSTR * ExeNamesBuf, OPTIONAL
  263. LPVOID Reserved
  264. )
  265. {
  266. LONG rc;
  267. INFO("Entering QueryVersion.");
  268. assert(ProductId);
  269. assert(DllVersion);
  270. assert(CodePageArray);
  271. assert(ExeNamesBuf);
  272. //
  273. // Setup is calling us to query our version information and to identify if
  274. // we need processing. We always need to provide the product ID and the
  275. // DLL version.
  276. //
  277. *ProductId = g_ProductId;
  278. *DllVersion = g_DllVersion;
  279. //
  280. // Check to see if there is anything to do.
  281. //
  282. if (CheckForInstalledComponents() == ERROR_SUCCESS) {
  283. //
  284. // There are installed components. Return the information Setup is
  285. // asking for.
  286. //
  287. *CodePageArray = g_CodePageArray; // Use the CP_ACP code page for conversion to unicode,
  288. *ExeNamesBuf = g_ExeNamesBuffer;
  289. //
  290. // Since there is work to do, return EXIT_SUCCESS. This informs Setup
  291. // that this dll does require processing during migration.
  292. //
  293. rc = ERROR_SUCCESS;
  294. }
  295. else {
  296. rc = ERROR_NOT_INSTALLED;
  297. }
  298. return rc;
  299. }
  300. LONG
  301. CALLBACK
  302. Initialize9x (
  303. IN LPCSTR WorkingDirectory,
  304. IN LPCSTR SourceDirectories,
  305. LPVOID Reserved
  306. )
  307. {
  308. LONG rc;
  309. //
  310. // Setup guarantees that the source directories parameter is valid.
  311. //
  312. assert(SourceDirectories);
  313. INFO("Entering Initialize9x.");
  314. //
  315. // Initialize the MigInf structure.
  316. //
  317. if (!MigInf_Initialize()) {
  318. rc = GetLastError();
  319. }
  320. else {
  321. rc = ERROR_SUCCESS;
  322. }
  323. return rc;
  324. }
  325. LONG
  326. CALLBACK
  327. MigrateUser9x (
  328. IN HWND ParentWnd,
  329. IN LPCSTR UnattendFile,
  330. IN HKEY UserRegKey,
  331. IN LPCSTR UserName,
  332. LPVOID Reserved
  333. )
  334. {
  335. //
  336. // Setup guarantees that UnattendFile,UserRegKey will be non-NULL
  337. //
  338. assert(UnattendFile);
  339. assert(UserRegKey);
  340. INFO("Entering MigrateUser9x.");
  341. //
  342. // Nothing to do per user, so, return ERROR_NO_MORE_FILES
  343. //
  344. return ERROR_NOT_INSTALLED;
  345. }
  346. LONG
  347. CALLBACK
  348. MigrateSystem9x (
  349. IN HWND ParentWnd,
  350. IN LPCSTR UnattendFile,
  351. LPVOID Reserved
  352. )
  353. {
  354. LONG rc = EXIT_SUCCESS;
  355. PSTR visualCppDirectory = NULL;
  356. MIGINFSECTIONENUM sectionEnum;
  357. BOOL firstMessage = TRUE;
  358. PCSTR messageSection = NULL;
  359. //
  360. // Setup guarantees that UnattendFile will be non-NULL.
  361. //
  362. assert(UnattendFile);
  363. INFO("Entering MigrateSystem9x");
  364. //
  365. // Since we are in this function, Initialize9x MUST have returned ERROR_SUCCESS.
  366. // Microsoft Visual C++ is installed on this machine.
  367. //
  368. //
  369. // Initialize the miginf module to handle interfacing with Migrate.Inf and retrieve
  370. // the installation directory for Visual C++.
  371. //
  372. visualCppDirectory = GetPviewDirectory9x();
  373. if (!visualCppDirectory) {
  374. rc = GetLastError();
  375. }
  376. else {
  377. //
  378. // The migration INF was successfully initialized. See if there is anything for
  379. // us to do. There is work to be done if (1) the [Migration Paths] section of
  380. // Migrate.inf contains some paths (Indicating that setup found some of the files
  381. // we asked it to look for in ExeNamesBuf) and (2) The Visual CPP Install directory
  382. // is not in the Excluded Paths Section.
  383. //
  384. if (MigInf_FirstInSection(SECTION_MIGRATIONPATHS,&sectionEnum)
  385. && !MigInf_PathIsExcluded(visualCppDirectory)) {
  386. //
  387. // All checks are good. We have work to do.
  388. // we need to sift through the files that
  389. // Setup returned in the Migration paths section. If the files
  390. // returned are in the installation directory, we will write them
  391. // to both the [Handled Files] sections and the [Moved Files]
  392. // sections. If not, we will write the file to the [Handled Files]
  393. // section and then write a message to the [Incompatible Messages]
  394. // section. This will allow us to override the message that
  395. // Setup is providing for these files with a more meaningful one.
  396. //
  397. do {
  398. if (PathIsInPath(sectionEnum.Key,visualCppDirectory)) {
  399. //
  400. // This file is in our installation path. We'll be handling it.
  401. //
  402. if (!MigInf_AddObject(
  403. MIG_FILE,
  404. SECTION_HANDLED,
  405. sectionEnum.Key,
  406. NULL
  407. )) {
  408. rc = ERROR_CANTWRITE;
  409. break;
  410. }
  411. //
  412. // We also need to note the amount of space that we will use.
  413. //
  414. if (!MigInf_UseSpace(sectionEnum.Key,SIZENEEDED)) {
  415. rc = ERROR_CANTWRITE;
  416. break;
  417. }
  418. }
  419. else {
  420. //
  421. // This file is not in our installation path.
  422. //
  423. if (firstMessage) {
  424. //
  425. // We'll only add one message to the incompatible messages
  426. // section, no matter how many PVIEW's we find outside of
  427. // the installation directory. However, we'll add all of
  428. // those files to the section that controls that message.
  429. // That way, the message will always appear unless _every_
  430. // file in that section has been handled by something
  431. // (i.e. another migration DLL.)
  432. //
  433. firstMessage = FALSE;
  434. if (!MigInf_AddObject(
  435. MIG_MESSAGE,
  436. SECTION_INCOMPATIBLE,
  437. MESSAGE_SECTION,
  438. MESSAGE
  439. )) {
  440. rc = ERROR_CANTWRITE;
  441. break;
  442. }
  443. }
  444. if (!MigInf_AddObject(
  445. MIG_FILE,
  446. MESSAGE_SECTION,
  447. sectionEnum.Key,
  448. NULL
  449. )) {
  450. rc = ERROR_CANTWRITE;
  451. break;
  452. }
  453. }
  454. } while (MigInf_NextInSection(&sectionEnum));
  455. }
  456. else {
  457. //
  458. // There is nothing for us to do.
  459. //
  460. rc = ERROR_NOT_INSTALLED;
  461. }
  462. MigInf_WriteInfToDisk();
  463. }
  464. //
  465. // Free the memory allocated in GetVisualCppDirectory.
  466. //
  467. if (visualCppDirectory) {
  468. LocalFree(visualCppDirectory);
  469. }
  470. return rc;
  471. }
  472. LONG
  473. CALLBACK
  474. InitializeNT (
  475. IN LPCWSTR WorkingDirectory,
  476. IN LPCWSTR SourceDirectory,
  477. LPVOID Reserved
  478. )
  479. {
  480. //
  481. // Setup ensures that WorkingDirectory and SourceDirectory will be non-NULL.
  482. //
  483. assert(WorkingDirectory != NULL && SourceDirectory != NULL);
  484. //
  485. // We do not need to do anything in this call. Simply return ERROR_SUCCES
  486. //
  487. return ERROR_SUCCESS;
  488. }
  489. LONG
  490. CALLBACK
  491. MigrateUserNT (
  492. IN HINF UnattendInfHandle,
  493. IN HKEY UserRegHandle,
  494. IN LPCWSTR UserName,
  495. LPVOID Reserved
  496. )
  497. {
  498. //
  499. // Setup guarantees that UnattendInfHandle and UserRegHandle are non-NULL and valid.
  500. // UserName can be NULL, however, for the default user.
  501. //
  502. assert(UnattendInfHandle);
  503. //
  504. // Nothing to do per user. Simply return ERROR_SUCCESS.
  505. // (Note the difference in return codes between MigrateUser9x and MigrateUserNT.)
  506. //
  507. return ERROR_SUCCESS;
  508. }
  509. LONG
  510. CALLBACK
  511. MigrateSystemNT (
  512. IN HINF UnattendInfHandle,
  513. LPVOID Reserved
  514. )
  515. {
  516. LONG rc;
  517. PSTR pviewDir;
  518. CHAR fromPath[MAX_PATH];
  519. CHAR toPath[MAX_PATH];
  520. //
  521. // Setup guarantees that UnattendInfHandle is non-NULL and is valid.
  522. //
  523. assert(UnattendInfHandle && UnattendInfHandle != INVALID_HANDLE_VALUE);
  524. //
  525. // If we have gotten to this point, we know that we are installed. All we need to do is copy
  526. // the NT version of PVIEW into the installation directory of Visual C++ 5.0 Note that we do
  527. // not replace the 9x version as a normal Visual C++ install on NT would have the 9x of PVIEW
  528. // as well.
  529. //
  530. pviewDir = GetPviewDirectoryNt();
  531. if (pviewDir) {
  532. sprintf(fromPath,".\\%s",FILE_PVIEW);
  533. sprintf(toPath,"%s\\%s",pviewDir,FILE_PVIEW);
  534. if (!CopyFileA(fromPath,toPath,FALSE)) {
  535. rc = GetLastError();
  536. }
  537. else {
  538. rc = ERROR_SUCCESS;
  539. }
  540. }
  541. else {
  542. rc = GetLastError();
  543. }
  544. return rc = ERROR_SUCCESS;
  545. }