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.

960 lines
27 KiB

  1. //
  2. // APITHK.C
  3. //
  4. // This file has API thunks that allow shell32 to load and run on
  5. // multiple versions of NT or Win95. Since this component needs
  6. // to load on the base-level NT 4.0 and Win95, any calls to system
  7. // APIs introduced in later OS versions must be done via GetProcAddress.
  8. //
  9. // Also, any code that may need to access data structures that are
  10. // post-4.0 specific can be added here.
  11. //
  12. // NOTE: this file does *not* use the standard precompiled header,
  13. // so it can set _WIN32_WINNT to a later version.
  14. //
  15. #include "priv.h" // Don't use precompiled header here
  16. #include "appwiz.h"
  17. #define c_szARPJob TEXT("ARP Job")
  18. // Return: hIOPort for the CompletionPort
  19. HANDLE _SetJobCompletionPort(HANDLE hJob)
  20. {
  21. HANDLE hRet = NULL;
  22. HANDLE hIOPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)hJob, 1 );
  23. if ( hIOPort != NULL )
  24. {
  25. JOBOBJECT_ASSOCIATE_COMPLETION_PORT CompletionPort;
  26. CompletionPort.CompletionKey = hJob ;
  27. CompletionPort.CompletionPort = hIOPort;
  28. if (SetInformationJobObject( hJob,JobObjectAssociateCompletionPortInformation,
  29. &CompletionPort, sizeof(CompletionPort) ) )
  30. {
  31. hRet = hIOPort;
  32. }
  33. }
  34. return hRet;
  35. }
  36. STDAPI_(DWORD) WaitingThreadProc(void *pv)
  37. {
  38. HANDLE hIOPort = (HANDLE)pv;
  39. // RIP(hIOPort);
  40. DWORD dwCompletionCode;
  41. PVOID pCompletionKey;
  42. LPOVERLAPPED lpOverlapped;
  43. while (TRUE)
  44. {
  45. // Wait for all the processes to finish...
  46. if (!GetQueuedCompletionStatus( hIOPort, &dwCompletionCode, (PULONG_PTR) &pCompletionKey,
  47. &lpOverlapped, INFINITE ) || (dwCompletionCode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO))
  48. {
  49. break;
  50. }
  51. }
  52. return 0;
  53. }
  54. /*-------------------------------------------------------------------------
  55. Purpose: Creates a process and waits for it to finish
  56. */
  57. STDAPI_(BOOL) NT5_CreateAndWaitForProcess(LPTSTR pszExeName)
  58. {
  59. PROCESS_INFORMATION pi = {0};
  60. STARTUPINFO si = {0};
  61. BOOL fWorked = FALSE;
  62. #ifdef WX86
  63. DWORD cchArch;
  64. WCHAR szArchValue[32];
  65. #endif
  66. HANDLE hJob = CreateJobObject(NULL, c_szARPJob);
  67. if (hJob)
  68. {
  69. HANDLE hIOPort = _SetJobCompletionPort(hJob);
  70. if (hIOPort)
  71. {
  72. DWORD dwCreationFlags = 0;
  73. // Create the install process
  74. si.cb = sizeof(si);
  75. #ifdef WX86
  76. if (bWx86Enabled && bForceX86Env) {
  77. cchArch = GetEnvironmentVariableW(ProcArchName,
  78. szArchValue,
  79. sizeof(szArchValue)
  80. );
  81. if (!cchArch || cchArch >= sizeof(szArchValue)) {
  82. szArchValue[0]=L'\0';
  83. }
  84. SetEnvironmentVariableW(ProcArchName, L"x86");
  85. }
  86. #endif
  87. dwCreationFlags = CREATE_SUSPENDED | CREATE_SEPARATE_WOW_VDM;
  88. // Create the process
  89. fWorked = CreateProcess(NULL, pszExeName, NULL, NULL, FALSE, dwCreationFlags, NULL, NULL,
  90. &si, &pi);
  91. if (fWorked)
  92. {
  93. HANDLE hWait = NULL;
  94. if (AssignProcessToJobObject(hJob, pi.hProcess))
  95. {
  96. hWait = CreateThread(NULL, 0, WaitingThreadProc, (LPVOID)hIOPort, 0, NULL);
  97. }
  98. if (hWait == NULL)
  99. {
  100. // We might get here if the call to AssignProcessToJobObject has failed because
  101. // the process already has a job assigned to it, or because we couldn't create the
  102. // waiting thread. Try a more direct approach by just watching the process handle.
  103. // This method won't catch spawned processes, but it is better than nothing.
  104. hWait = pi.hProcess;
  105. }
  106. else
  107. {
  108. // we are not waiting on the process handle, so we are done /w it.
  109. CloseHandle(pi.hProcess);
  110. }
  111. ResumeThread(pi.hThread);
  112. CloseHandle(pi.hThread);
  113. #ifdef WX86
  114. if (bWx86Enabled && bForceX86Env)
  115. {
  116. SetEnvironmentVariableW(ProcArchName, szArchValue);
  117. }
  118. #endif
  119. // we should have a valid handle at this point for sure
  120. ASSERT(hWait && (hWait != INVALID_HANDLE_VALUE));
  121. SHProcessSentMessagesUntilEvent(NULL, hWait, INFINITE);
  122. CloseHandle(hWait);
  123. }
  124. CloseHandle(hIOPort);
  125. }
  126. CloseHandle(hJob);
  127. }
  128. return fWorked;
  129. }
  130. #define PFN_FIRSTTIME ((void *)-1)
  131. // GetLongPathName
  132. typedef UINT (WINAPI * PFNGETLONGPATHNAME)(LPCTSTR pszShortPath, LPTSTR pszLongBuf, DWORD cchBuf);
  133. /*----------------------------------------------------------
  134. Purpose: Thunk for NT 5's GetLongPathName
  135. */
  136. DWORD NT5_GetLongPathName(LPCTSTR pszShortPath, LPTSTR pszLongBuf, DWORD cchBuf)
  137. {
  138. static PFNGETLONGPATHNAME s_pfn = PFN_FIRSTTIME;
  139. if (PFN_FIRSTTIME == s_pfn)
  140. {
  141. // It is safe to GetModuleHandle KERNEL32 because we implicitly link
  142. // to it, so it is guaranteed to be loaded in every thread.
  143. HINSTANCE hinst = GetModuleHandleA("KERNEL32.DLL");
  144. if (hinst)
  145. {
  146. // The unicode-decorated MSI APIs translate to ansi internally
  147. // on Win95, so it should be safe to call them all the time.
  148. #ifdef UNICODE
  149. s_pfn = (PFNGETLONGPATHNAME)GetProcAddress(hinst, "GetLongPathNameW");
  150. #else
  151. s_pfn = (PFNGETLONGPATHNAME)GetProcAddress(hinst, "GetLongPathNameA");
  152. #endif
  153. }
  154. else
  155. s_pfn = NULL;
  156. }
  157. if (s_pfn)
  158. return s_pfn(pszShortPath, pszLongBuf, cchBuf);
  159. if (0 < cchBuf && pszLongBuf)
  160. *pszLongBuf = 0;
  161. return 0; // failure
  162. }
  163. // VerSetConditionMask
  164. typedef ULONGLONG (WINAPI * PFNVERSETCONDITIONMASK)(ULONGLONG conditionMask, DWORD dwTypeMask, BYTE condition);
  165. /*----------------------------------------------------------
  166. Purpose: Thunk for NT 5's VerSetConditionMask
  167. */
  168. ULONGLONG NT5_VerSetConditionMask(ULONGLONG conditionMask, DWORD dwTypeMask, BYTE condition)
  169. {
  170. static PFNVERSETCONDITIONMASK s_pfn = PFN_FIRSTTIME;
  171. if (PFN_FIRSTTIME == s_pfn)
  172. {
  173. // It is safe to GetModuleHandle KERNEL32 because we implicitly link
  174. // to it, so it is guaranteed to be loaded in every thread.
  175. HINSTANCE hinst = GetModuleHandleA("KERNEL32.DLL");
  176. if (hinst)
  177. s_pfn = (PFNVERSETCONDITIONMASK)GetProcAddress(hinst, "VerSetConditionMask");
  178. else
  179. s_pfn = NULL;
  180. }
  181. if (s_pfn)
  182. return s_pfn(conditionMask, dwTypeMask, condition);
  183. return 0; // failure
  184. }
  185. // MsiReinstallProduct
  186. typedef UINT (WINAPI * PFNMSIREINSTALLPRODUCT) (LPCTSTR szProduct, DWORD dwReinstallMode);
  187. /*----------------------------------------------------------
  188. Purpose: Thunk for NT 5's MsiReinstallProduct
  189. */
  190. UINT MSI_MsiReinstallProduct(LPCTSTR szProduct, DWORD dwReinstallMode)
  191. {
  192. static PFNMSIREINSTALLPRODUCT s_pfn = PFN_FIRSTTIME;
  193. if (PFN_FIRSTTIME == s_pfn)
  194. {
  195. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  196. if (hinst)
  197. {
  198. // The unicode-decorated MSI APIs translate to ansi internally
  199. // on Win95, so it should be safe to call them all the time.
  200. #ifdef UNICODE
  201. s_pfn = (PFNMSIREINSTALLPRODUCT)GetProcAddress(hinst, "MsiReinstallProductW");
  202. #else
  203. s_pfn = (PFNMSIREINSTALLPRODUCT)GetProcAddress(hinst, "MsiReinstallProductA");
  204. #endif
  205. }
  206. else
  207. s_pfn = NULL;
  208. }
  209. if (s_pfn)
  210. return s_pfn(szProduct, dwReinstallMode);
  211. return ERROR_CALL_NOT_IMPLEMENTED;
  212. }
  213. // MsiEnumProducts
  214. typedef UINT (WINAPI * PFNMSIENUMPRODUCTS) (DWORD iProductIndex, LPTSTR lpProductBuf);
  215. /*----------------------------------------------------------
  216. Purpose: Thunk for NT 5's MsiEnumProducts
  217. */
  218. UINT MSI_MsiEnumProducts(DWORD iProductIndex, LPTSTR lpProductBuf)
  219. {
  220. static PFNMSIENUMPRODUCTS s_pfn = PFN_FIRSTTIME;
  221. if (PFN_FIRSTTIME == s_pfn)
  222. {
  223. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  224. if (hinst)
  225. {
  226. // The unicode-decorated MSI APIs translate to ansi internally
  227. // on Win95, so it should be safe to call them all the time.
  228. #ifdef UNICODE
  229. s_pfn = (PFNMSIENUMPRODUCTS)GetProcAddress(hinst, "MsiEnumProductsW");
  230. #else
  231. s_pfn = (PFNMSIENUMPRODUCTS)GetProcAddress(hinst, "MsiEnumProductsA");
  232. #endif
  233. }
  234. else
  235. s_pfn = NULL;
  236. }
  237. if (s_pfn)
  238. return s_pfn(iProductIndex, lpProductBuf);
  239. return ERROR_CALL_NOT_IMPLEMENTED;
  240. }
  241. // MsiEnumFeatures
  242. typedef UINT (WINAPI * PFNMSIENUMFEATURES) (LPCTSTR szProduct, DWORD iFeatureIndex, LPTSTR lpFeatureBuf, LPTSTR lpParentBuf);
  243. /*----------------------------------------------------------
  244. Purpose: Thunk for NT 5's MsiEnumFeatures
  245. */
  246. UINT MSI_MsiEnumFeatures(LPCTSTR szProduct, DWORD iFeatureIndex, LPTSTR lpFeatureBuf, LPTSTR lpParentBuf)
  247. {
  248. static PFNMSIENUMFEATURES s_pfn = PFN_FIRSTTIME;
  249. if (PFN_FIRSTTIME == s_pfn)
  250. {
  251. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  252. if (hinst)
  253. {
  254. // The unicode-decorated MSI APIs translate to ansi internally
  255. // on Win95, so it should be safe to call them all the time.
  256. #ifdef UNICODE
  257. s_pfn = (PFNMSIENUMFEATURES)GetProcAddress(hinst, "MsiEnumFeaturesW");
  258. #else
  259. s_pfn = (PFNMSIENUMFEATURES)GetProcAddress(hinst, "MsiEnumFeaturesA");
  260. #endif
  261. }
  262. else
  263. s_pfn = NULL;
  264. }
  265. if (s_pfn)
  266. return s_pfn(szProduct, iFeatureIndex, lpFeatureBuf, lpParentBuf);
  267. return ERROR_CALL_NOT_IMPLEMENTED;
  268. }
  269. // MsiGetProductInfo
  270. typedef UINT (WINAPI * PFNMSIGETPRODUCTINFO) (LPCTSTR szProduct, LPCTSTR szAttribute, LPTSTR lpValueBuf, DWORD *pcchValueBuf);
  271. /*----------------------------------------------------------
  272. Purpose: Thunk for NT 5's MsiGetProductInfo
  273. */
  274. UINT MSI_MsiGetProductInfo(LPCTSTR szProduct, LPCTSTR szAttribute, LPTSTR lpValueBuf, DWORD *pcchValueBuf)
  275. {
  276. static PFNMSIGETPRODUCTINFO s_pfn = PFN_FIRSTTIME;
  277. if (PFN_FIRSTTIME == s_pfn)
  278. {
  279. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  280. if (hinst)
  281. {
  282. // The unicode-decorated MSI APIs translate to ansi internally
  283. // on Win95, so it should be safe to call them all the time.
  284. #ifdef UNICODE
  285. s_pfn = (PFNMSIGETPRODUCTINFO)GetProcAddress(hinst, "MsiGetProductInfoW");
  286. #else
  287. s_pfn = (PFNMSIGETPRODUCTINFO)GetProcAddress(hinst, "MsiGetProductInfoA");
  288. #endif
  289. }
  290. else
  291. s_pfn = NULL;
  292. }
  293. if (s_pfn)
  294. return s_pfn(szProduct, szAttribute, lpValueBuf, pcchValueBuf);
  295. return ERROR_CALL_NOT_IMPLEMENTED;
  296. }
  297. // MsiSetInternalUI
  298. typedef INSTALLUILEVEL (WINAPI * PFNMSISETINTERNALUI) (INSTALLUILEVEL dwUILevel, HWND * phwnd);
  299. /*----------------------------------------------------------
  300. Purpose: Thunk for NT 5's MsiSetInternalUI
  301. */
  302. INSTALLUILEVEL MSI_MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND * phwnd)
  303. {
  304. static PFNMSISETINTERNALUI s_pfn = PFN_FIRSTTIME;
  305. if (PFN_FIRSTTIME == s_pfn)
  306. {
  307. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  308. if (hinst)
  309. {
  310. s_pfn = (PFNMSISETINTERNALUI)GetProcAddress(hinst, "MsiSetInternalUI");
  311. }
  312. else
  313. s_pfn = NULL;
  314. }
  315. if (s_pfn)
  316. return s_pfn(dwUILevel, phwnd);
  317. return INSTALLUILEVEL_NOCHANGE;
  318. }
  319. // MsiConfigureProduct
  320. typedef UINT (WINAPI * PFNMSICONFIGUREPRODUCT) (LPCTSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState);
  321. /*----------------------------------------------------------
  322. Purpose: Thunk for NT 5's MsiConfigureProduct
  323. */
  324. UINT MSI_MsiConfigureProduct(LPCTSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState)
  325. {
  326. static PFNMSICONFIGUREPRODUCT s_pfn = PFN_FIRSTTIME;
  327. if (PFN_FIRSTTIME == s_pfn)
  328. {
  329. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  330. if (hinst)
  331. {
  332. // The unicode-decorated MSI APIs translate to ansi internally
  333. // on Win95, so it should be safe to call them all the time.
  334. #ifdef UNICODE
  335. s_pfn = (PFNMSICONFIGUREPRODUCT)GetProcAddress(hinst, "MsiConfigureProductW");
  336. #else
  337. s_pfn = (PFNMSICONFIGUREPRODUCT)GetProcAddress(hinst, "MsiConfigureProductA");
  338. #endif
  339. }
  340. else
  341. s_pfn = NULL;
  342. }
  343. if (s_pfn)
  344. return s_pfn(szProduct, iInstallLevel, eInstallState);
  345. return ERROR_CALL_NOT_IMPLEMENTED;
  346. }
  347. // MsiQueryProductState
  348. typedef INSTALLSTATE (WINAPI * PFNMSIQUERYPRODUCTSTATE) (LPCTSTR szProductID);
  349. /*----------------------------------------------------------
  350. Purpose: Thunk for NT 5's MsiQueryProductState
  351. */
  352. INSTALLSTATE MSI_MsiQueryProductState(LPCTSTR szProductID)
  353. {
  354. static PFNMSIQUERYPRODUCTSTATE s_pfn = PFN_FIRSTTIME;
  355. if (PFN_FIRSTTIME == s_pfn)
  356. {
  357. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  358. if (hinst)
  359. {
  360. // The unicode-decorated MSI APIs translate to ansi internally
  361. // on Win95, so it should be safe to call them all the time.
  362. #ifdef UNICODE
  363. s_pfn = (PFNMSIQUERYPRODUCTSTATE)GetProcAddress(hinst, "MsiQueryProductStateW");
  364. #else
  365. s_pfn = (PFNMSIQUERYPRODUCTSTATE)GetProcAddress(hinst, "MsiQueryProductStateA");
  366. #endif
  367. }
  368. else
  369. s_pfn = NULL;
  370. }
  371. if (s_pfn)
  372. return s_pfn(szProductID);
  373. return ERROR_CALL_NOT_IMPLEMENTED;
  374. }
  375. // MsiQueryFeatureState
  376. typedef INSTALLSTATE (WINAPI * PFNMSIQUERYFEATURESTATE) (LPCTSTR szProductID, LPCTSTR szFeature);
  377. /*----------------------------------------------------------
  378. Purpose: Thunk for NT 5's MsiQueryFeatureState
  379. */
  380. INSTALLSTATE MSI_MsiQueryFeatureState(LPCTSTR szProductID, LPCTSTR szFeature)
  381. {
  382. static PFNMSIQUERYFEATURESTATE s_pfn = PFN_FIRSTTIME;
  383. if (PFN_FIRSTTIME == s_pfn)
  384. {
  385. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  386. if (hinst)
  387. {
  388. // The unicode-decorated MSI APIs translate to ansi internally
  389. // on Win95, so it should be safe to call them all the time.
  390. #ifdef UNICODE
  391. s_pfn = (PFNMSIQUERYFEATURESTATE)GetProcAddress(hinst, "MsiQueryFeatureStateW");
  392. #else
  393. s_pfn = (PFNMSIQUERYFEATURESTATE)GetProcAddress(hinst, "MsiQueryFeatureStateA");
  394. #endif
  395. }
  396. else
  397. s_pfn = NULL;
  398. }
  399. if (s_pfn)
  400. return s_pfn(szProductID, szFeature);
  401. return ERROR_CALL_NOT_IMPLEMENTED;
  402. }
  403. // MsiOpenPackage
  404. typedef UINT (WINAPI * PFNMSIOPENPACKAGE) (LPCTSTR szPackagePath, MSIHANDLE * hProduct);
  405. /*----------------------------------------------------------
  406. Purpose: Thunk for NT 5's MsiOpenPackage
  407. */
  408. UINT MSI_MsiOpenPackage(LPCTSTR szPackagePath, MSIHANDLE * hProduct)
  409. {
  410. static PFNMSIOPENPACKAGE s_pfn = PFN_FIRSTTIME;
  411. if (PFN_FIRSTTIME == s_pfn)
  412. {
  413. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  414. if (hinst)
  415. {
  416. // The unicode-decorated MSI APIs translate to ansi internally
  417. // on Win95, so it should be safe to call them all the time.
  418. #ifdef UNICODE
  419. s_pfn = (PFNMSIOPENPACKAGE)GetProcAddress(hinst, "MsiOpenPackageW");
  420. #else
  421. s_pfn = (PFNMSIOPENPACKAGE)GetProcAddress(hinst, "MsiOpenPackageA");
  422. #endif
  423. }
  424. else
  425. s_pfn = NULL;
  426. }
  427. if (s_pfn)
  428. return s_pfn(szPackagePath, hProduct);
  429. return ERROR_CALL_NOT_IMPLEMENTED;
  430. }
  431. // MsiCloseHandle
  432. typedef UINT (WINAPI * PFNMSICLOSEHANDLE) (MSIHANDLE hAny);
  433. /*----------------------------------------------------------
  434. Purpose: Thunk for NT 5's MsiCloseHandle
  435. */
  436. UINT MSI_MsiCloseHandle(MSIHANDLE hAny)
  437. {
  438. static PFNMSICLOSEHANDLE s_pfn = PFN_FIRSTTIME;
  439. if (PFN_FIRSTTIME == s_pfn)
  440. {
  441. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  442. if (hinst)
  443. {
  444. s_pfn = (PFNMSICLOSEHANDLE)GetProcAddress(hinst, "MsiCloseHandle");
  445. }
  446. else
  447. s_pfn = NULL;
  448. }
  449. if (s_pfn)
  450. return s_pfn(hAny);
  451. return ERROR_CALL_NOT_IMPLEMENTED;
  452. }
  453. // MsiDoAction
  454. typedef UINT (WINAPI * PFNMSIDOACTION) (MSIHANDLE hAny, LPCTSTR szAction);
  455. /*----------------------------------------------------------
  456. Purpose: Thunk for NT 5's MsiDoAction
  457. */
  458. UINT MSI_MsiDoAction(MSIHANDLE hAny, LPCTSTR szAction)
  459. {
  460. static PFNMSIDOACTION s_pfn = PFN_FIRSTTIME;
  461. if (PFN_FIRSTTIME == s_pfn)
  462. {
  463. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  464. if (hinst)
  465. {
  466. // The unicode-decorated MSI APIs translate to ansi internally
  467. // on Win95, so it should be safe to call them all the time.
  468. #ifdef UNICODE
  469. s_pfn = (PFNMSIDOACTION)GetProcAddress(hinst, "MsiDoActionW");
  470. #else
  471. s_pfn = (PFNMSIDOACTION)GetProcAddress(hinst, "MsiDoActionA");
  472. #endif
  473. }
  474. else
  475. s_pfn = NULL;
  476. }
  477. if (s_pfn)
  478. return s_pfn(hAny, szAction);
  479. return ERROR_CALL_NOT_IMPLEMENTED;
  480. }
  481. // MsiGetFeatureCost
  482. typedef UINT (WINAPI * PFNMSIGETFEATURECOST) (MSIHANDLE hInstall, LPCTSTR szFeature, MSICOSTTREE iCostTree, INSTALLSTATE iState, INT *piCost);
  483. /*----------------------------------------------------------
  484. Purpose: Thunk for NT 5's MsiGetFeatureCost
  485. */
  486. UINT MSI_MsiGetFeatureCost(MSIHANDLE hInstall, LPCTSTR szFeature, MSICOSTTREE iCostTree, INSTALLSTATE iState, INT *piCost)
  487. {
  488. static PFNMSIGETFEATURECOST s_pfn = PFN_FIRSTTIME;
  489. if (PFN_FIRSTTIME == s_pfn)
  490. {
  491. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  492. if (hinst)
  493. {
  494. // The unicode-decorated MSI APIs translate to ansi internally
  495. // on Win95, so it should be safe to call them all the time.
  496. #ifdef UNICODE
  497. s_pfn = (PFNMSIGETFEATURECOST)GetProcAddress(hinst, "MsiGetFeatureCostW");
  498. #else
  499. s_pfn = (PFNMSIGETFEATURECOST)GetProcAddress(hinst, "MsiGetFeatureCostA");
  500. #endif
  501. }
  502. else
  503. s_pfn = NULL;
  504. }
  505. if (s_pfn)
  506. return s_pfn(hInstall, szFeature, iCostTree, iState, piCost);
  507. return ERROR_CALL_NOT_IMPLEMENTED;
  508. }
  509. // MsiSetFeatureState
  510. typedef UINT (WINAPI * PFNMSISETFEATURESTATE) (MSIHANDLE hInstall, LPCTSTR szFeature, INSTALLSTATE iState);
  511. /*----------------------------------------------------------
  512. Purpose: Thunk for NT 5's MsiSetFeatureState
  513. */
  514. UINT MSI_MsiSetFeatureState(MSIHANDLE hInstall, LPCTSTR szFeature, INSTALLSTATE iState)
  515. {
  516. static PFNMSISETFEATURESTATE s_pfn = PFN_FIRSTTIME;
  517. if (PFN_FIRSTTIME == s_pfn)
  518. {
  519. HINSTANCE hinst = LoadLibraryA("MSI.DLL");
  520. if (hinst)
  521. {
  522. // The unicode-decorated MSI APIs translate to ansi internally
  523. // on Win95, so it should be safe to call them all the time.
  524. #ifdef UNICODE
  525. s_pfn = (PFNMSISETFEATURESTATE)GetProcAddress(hinst, "MsiSetFeatureStateW");
  526. #else
  527. s_pfn = (PFNMSISETFEATURESTATE)GetProcAddress(hinst, "MsiSetFeatureStateA");
  528. #endif
  529. }
  530. else
  531. s_pfn = NULL;
  532. }
  533. if (s_pfn)
  534. return s_pfn(hInstall, szFeature, iState);
  535. return ERROR_CALL_NOT_IMPLEMENTED;
  536. }
  537. typedef HRESULT (__stdcall * PFNRELEASEAPPCATEGORYINFOLIST)(APPCATEGORYINFOLIST *pAppCategoryList);
  538. /*----------------------------------------------------------
  539. Purpose: Thunk for NT 5's ReleaseAppCategoryInfoList
  540. */
  541. HRESULT NT5_ReleaseAppCategoryInfoList(APPCATEGORYINFOLIST *pAppCategoryList)
  542. {
  543. static PFNRELEASEAPPCATEGORYINFOLIST s_pfn = PFN_FIRSTTIME;
  544. if (PFN_FIRSTTIME == s_pfn)
  545. {
  546. HINSTANCE hinst = LoadLibraryA("APPMGMTS.DLL");
  547. if (hinst)
  548. s_pfn = (PFNRELEASEAPPCATEGORYINFOLIST)GetProcAddress(hinst, "ReleaseAppCategoryInfoList");
  549. else
  550. s_pfn = NULL;
  551. }
  552. if (s_pfn)
  553. return s_pfn(pAppCategoryList);
  554. return E_NOTIMPL;
  555. }
  556. /*----------------------------------------------------------
  557. Purpose: Thunk for NT 5's AllowSetForegroundWindow
  558. */
  559. typedef UINT (WINAPI * PFNALLOWSFW) (DWORD dwPRocessID);
  560. BOOL NT5_AllowSetForegroundWindow(DWORD dwProcessID)
  561. {
  562. static PFNALLOWSFW s_pfn = PFN_FIRSTTIME;
  563. if (PFN_FIRSTTIME == s_pfn)
  564. {
  565. HINSTANCE hinst = LoadLibraryA("USER32.DLL");
  566. if (hinst)
  567. {
  568. s_pfn = (PFNALLOWSFW)GetProcAddress(hinst, "AllowSetForegroundWindow");
  569. }
  570. else
  571. s_pfn = NULL;
  572. }
  573. if (s_pfn)
  574. return s_pfn(dwProcessID);
  575. return FALSE;
  576. }
  577. // InstallApplication
  578. typedef DWORD (WINAPI * PFNINSTALLAPP)(PINSTALLDATA pInstallInfo);
  579. /*----------------------------------------------------------
  580. Purpose: Thunk for NT 5's InstallApplication
  581. */
  582. DWORD NT5_InstallApplication(PINSTALLDATA pInstallInfo)
  583. {
  584. static PFNINSTALLAPP s_pfn = PFN_FIRSTTIME;
  585. if (PFN_FIRSTTIME == s_pfn)
  586. {
  587. // It is safe to GetModuleHandle ADVAPI32 because we implicitly link
  588. // to it, so it is guaranteed to be loaded in every thread.
  589. HINSTANCE hinst = GetModuleHandleA("ADVAPI32.DLL");
  590. if (hinst)
  591. s_pfn = (PFNINSTALLAPP)GetProcAddress(hinst, "InstallApplication");
  592. else
  593. s_pfn = NULL;
  594. }
  595. if (s_pfn)
  596. return s_pfn(pInstallInfo);
  597. return ERROR_INVALID_FUNCTION; // failure
  598. }
  599. // UninstallApplication
  600. typedef DWORD (WINAPI * PFNUNINSTALLAPP)(WCHAR * pszProductCode, DWORD dwStatus);
  601. /*----------------------------------------------------------
  602. Purpose: Thunk for NT 5's UninstallApplication
  603. */
  604. DWORD NT5_UninstallApplication(WCHAR * pszProductCode, DWORD dwStatus)
  605. {
  606. static PFNUNINSTALLAPP s_pfn = PFN_FIRSTTIME;
  607. if (PFN_FIRSTTIME == s_pfn)
  608. {
  609. // It is safe to GetModuleHandle ADVAPI32 because we implicitly link
  610. // to it, so it is guaranteed to be loaded in every thread.
  611. HINSTANCE hinst = GetModuleHandleA("ADVAPI32.DLL");
  612. if (hinst)
  613. s_pfn = (PFNUNINSTALLAPP)GetProcAddress(hinst, "UninstallApplication");
  614. else
  615. s_pfn = NULL;
  616. }
  617. if (s_pfn)
  618. return s_pfn(pszProductCode, dwStatus);
  619. return ERROR_INVALID_FUNCTION; // failure
  620. }
  621. // GetApplicationState
  622. typedef DWORD (WINAPI * PFNGETAPPSTATE)(WCHAR * ProductCode, APPSTATE * pAppState);
  623. /*----------------------------------------------------------
  624. Purpose: Thunk for NT 5's GetApplicationState
  625. */
  626. DWORD NT5_GetApplicationState(WCHAR * pszProductCode, APPSTATE * pAppState)
  627. {
  628. static PFNGETAPPSTATE s_pfn = PFN_FIRSTTIME;
  629. if (PFN_FIRSTTIME == s_pfn)
  630. {
  631. // It is safe to GetModuleHandle ADVAPI32 because we implicitly link
  632. // to it, so it is guaranteed to be loaded in every thread.
  633. HINSTANCE hinst = GetModuleHandleA("ADVAPI32.DLL");
  634. if (hinst)
  635. s_pfn = (PFNGETAPPSTATE)GetProcAddress(hinst, "GetApplicationState");
  636. else
  637. s_pfn = NULL;
  638. }
  639. if (s_pfn)
  640. return s_pfn(pszProductCode, pAppState);
  641. return ERROR_INVALID_FUNCTION; // failure
  642. }
  643. // CommandLineFromMsiDescriptor
  644. typedef DWORD (WINAPI * PFNCMDLINE)(WCHAR * Descriptor, WCHAR * CommandLine, DWORD * CommandLineLength);
  645. /*----------------------------------------------------------
  646. Purpose: Thunk for NT 5's CommandLineFromMsiDescriptor
  647. */
  648. DWORD NT5_CommandLineFromMsiDescriptor(WCHAR * pszDescriptor, WCHAR * pszCommandLine, DWORD * pcchCommandLine)
  649. {
  650. static PFNCMDLINE s_pfn = PFN_FIRSTTIME;
  651. if (PFN_FIRSTTIME == s_pfn)
  652. {
  653. // It is safe to GetModuleHandle ADVAPI32 because we implicitly link
  654. // to it, so it is guaranteed to be loaded in every thread.
  655. HINSTANCE hinst = GetModuleHandleA("ADVAPI32.DLL");
  656. if (hinst)
  657. s_pfn = (PFNCMDLINE)GetProcAddress(hinst, "CommandLineFromMsiDescriptor");
  658. else
  659. s_pfn = NULL;
  660. }
  661. if (s_pfn)
  662. return s_pfn(pszDescriptor, pszCommandLine, pcchCommandLine);
  663. return ERROR_INVALID_FUNCTION; // failure
  664. }
  665. // GetManagedApplications
  666. typedef DWORD (WINAPI * PFNGETAPPS)(GUID * pCategory, DWORD dwQueryFlags, DWORD dwInfoLevel, LPDWORD pdwApps, PMANAGEDAPPLICATION* prgManagedApps);
  667. /*----------------------------------------------------------
  668. Purpose: Thunk for NT 5's GetManagedApplications
  669. */
  670. DWORD NT5_GetManagedApplications(GUID * pCategory, DWORD dwQueryFlags, DWORD dwInfoLevel, LPDWORD pdwApps, PMANAGEDAPPLICATION* prgManagedApps)
  671. {
  672. static PFNGETAPPS s_pfn = PFN_FIRSTTIME;
  673. if (PFN_FIRSTTIME == s_pfn)
  674. {
  675. // It is safe to GetModuleHandle ADVAPI32 because we implicitly link
  676. // to it, so it is guaranteed to be loaded in every thread.
  677. HINSTANCE hinst = GetModuleHandleA("ADVAPI32.DLL");
  678. if (hinst)
  679. s_pfn = (PFNGETAPPS)GetProcAddress(hinst, "GetManagedApplications");
  680. else
  681. s_pfn = NULL;
  682. }
  683. if (s_pfn)
  684. return s_pfn(pCategory, dwQueryFlags, dwInfoLevel, pdwApps, prgManagedApps);
  685. return ERROR_INVALID_FUNCTION; // failure
  686. }
  687. typedef DWORD (__stdcall * PFNGETMANAGEDAPPLICATIONCATEGORIES)(DWORD dwReserved, APPCATEGORYINFOLIST *pAppCategoryList);
  688. /*----------------------------------------------------------
  689. Purpose: Thunk for NT 5's CsGetAppCategories
  690. */
  691. DWORD NT5_GetManagedApplicationCategories(DWORD dwReserved, APPCATEGORYINFOLIST *pAppCategoryList)
  692. {
  693. static PFNGETMANAGEDAPPLICATIONCATEGORIES s_pfn = PFN_FIRSTTIME;
  694. if (PFN_FIRSTTIME == s_pfn)
  695. {
  696. HINSTANCE hinst = LoadLibraryA("ADVAPI32.DLL");
  697. if (hinst)
  698. s_pfn = (PFNGETMANAGEDAPPLICATIONCATEGORIES)GetProcAddress(hinst, "GetManagedApplicationCategories");
  699. else
  700. s_pfn = NULL;
  701. }
  702. if (s_pfn)
  703. return s_pfn(dwReserved, pAppCategoryList);
  704. return ERROR_INVALID_FUNCTION;
  705. }
  706. // NetGetJoinInformation
  707. typedef NET_API_STATUS (WINAPI * PFNGETJOININFO)(LPCWSTR lpServer, LPWSTR *lpNameBuffer, PNETSETUP_JOIN_STATUS BufferType);
  708. /*----------------------------------------------------------
  709. Purpose: Thunk for NT 5's NetGetJoinInformation
  710. */
  711. NET_API_STATUS NT5_NetGetJoinInformation(LPCWSTR lpServer, LPWSTR *lpNameBuffer, PNETSETUP_JOIN_STATUS BufferType)
  712. {
  713. static PFNGETJOININFO s_pfn = PFN_FIRSTTIME;
  714. if (PFN_FIRSTTIME == s_pfn)
  715. {
  716. HINSTANCE hinst = LoadLibraryA("NETAPI32.DLL");
  717. GetLastError();
  718. if (hinst)
  719. s_pfn = (PFNGETJOININFO)GetProcAddress(hinst, "NetGetJoinInformation");
  720. else
  721. s_pfn = NULL;
  722. }
  723. if (s_pfn)
  724. return s_pfn(lpServer, lpNameBuffer, BufferType);
  725. return NERR_NetNotStarted; // failure
  726. }
  727. // NetApiBufferFree
  728. typedef NET_API_STATUS (WINAPI * PFNNETFREEBUFFER)(LPVOID lpBuffer);
  729. /*----------------------------------------------------------
  730. Purpose: Thunk for NT 5's NetApiBufferFree
  731. */
  732. NET_API_STATUS NT5_NetApiBufferFree(LPVOID lpBuffer)
  733. {
  734. static PFNNETFREEBUFFER s_pfn = PFN_FIRSTTIME;
  735. if (PFN_FIRSTTIME == s_pfn)
  736. {
  737. HINSTANCE hinst = LoadLibraryA("NETAPI32.DLL");
  738. if (hinst)
  739. s_pfn = (PFNNETFREEBUFFER)GetProcAddress(hinst, "NetApiBufferFree");
  740. else
  741. s_pfn = NULL;
  742. }
  743. if (s_pfn)
  744. return s_pfn(lpBuffer);
  745. return NERR_NetNotStarted; // failure
  746. }