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.

753 lines
17 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. OptCom.cpp
  5. Abstract:
  6. Base Class for optional component work.
  7. Author:
  8. Rohde Wakefield [rohde] 09-Oct-1997
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #include "rsoptcom.h"
  13. #include "OptCom.h"
  14. //////////////////////////////////////////////////////////////////////
  15. // Construction/Destruction
  16. //////////////////////////////////////////////////////////////////////
  17. CRsOptCom::CRsOptCom()
  18. {
  19. TRACEFN( "CRsOptCom::CRsOptCom" );
  20. }
  21. CRsOptCom::~CRsOptCom()
  22. {
  23. TRACEFN( "CRsOptCom::CRsOptCom" );
  24. }
  25. DWORD
  26. CRsOptCom::SetupProc(
  27. IN LPCVOID /*ComponentId*/,
  28. IN LPCVOID SubcomponentId,
  29. IN UINT Function,
  30. IN UINT_PTR Param1,
  31. IN OUT PVOID Param2
  32. )
  33. {
  34. TRACEFN( "CRsOptCom::SetupProc" );
  35. TRACE( L"Function = <%ls><%p>", StringFromFunction( Function ), Function );
  36. SHORT subcomponentId = IdFromString( (LPCTSTR)SubcomponentId );
  37. DWORD dwRet = 0;
  38. switch( Function ) {
  39. case OC_PREINITIALIZE:
  40. dwRet = PreInitialize( (DWORD)Param1 );
  41. break;
  42. case OC_INIT_COMPONENT:
  43. dwRet = InitComponent( (PSETUP_INIT_COMPONENT)Param2 );
  44. break;
  45. case OC_SET_LANGUAGE:
  46. dwRet = (DWORD)SetLanguage( (WORD)Param1 );
  47. break;
  48. #ifndef _WIN64
  49. case OC_QUERY_IMAGE:
  50. // Note: The casting of the return value from HBITMAP to DWORD is broken on IA64,
  51. // however, Setup avoids calling with OC_QUERY_IMAGE on IA64, rather it uses OC_QUERY_IMAGE_EX
  52. dwRet = (DWORD)QueryImage( subcomponentId, (SubComponentInfo)Param1, LOWORD(Param2), HIWORD(Param2) );
  53. break;
  54. #endif
  55. #ifdef _WIN64
  56. case OC_QUERY_IMAGE_EX:
  57. dwRet = (DWORD)QueryImageEx( subcomponentId, (OC_QUERY_IMAGE_INFO *)Param1, (HBITMAP *)Param2 );
  58. break;
  59. #endif
  60. case OC_REQUEST_PAGES:
  61. dwRet = (DWORD)RequestPages( (WizardPagesType)Param1, (PSETUP_REQUEST_PAGES)Param2 );
  62. break;
  63. case OC_QUERY_CHANGE_SEL_STATE:
  64. dwRet = (DWORD)QueryChangeSelState( subcomponentId, Param1 != 0, (ULONG)((ULONG_PTR)Param2) );
  65. break;
  66. case OC_CALC_DISK_SPACE:
  67. dwRet = CalcDiskSpace( subcomponentId, Param1 != 0, (HDSKSPC)Param2 );
  68. break;
  69. case OC_QUEUE_FILE_OPS:
  70. dwRet = QueueFileOps( subcomponentId, (HSPFILEQ)Param2 );
  71. break;
  72. case OC_QUERY_STEP_COUNT:
  73. dwRet = (DWORD)QueryStepCount( subcomponentId );
  74. break;
  75. case OC_COMPLETE_INSTALLATION:
  76. dwRet = CompleteInstallation( subcomponentId );
  77. break;
  78. case OC_CLEANUP:
  79. CleanUp( );
  80. break;
  81. case OC_ABOUT_TO_COMMIT_QUEUE:
  82. dwRet = AboutToCommitQueue( subcomponentId );
  83. break;
  84. case OC_QUERY_SKIP_PAGE:
  85. dwRet = (DWORD)QuerySkipPage( (OcManagerPage)Param1 );
  86. break;
  87. case OC_QUERY_STATE:
  88. dwRet = (DWORD)QueryState( subcomponentId );
  89. break;
  90. case OC_NOTIFICATION_FROM_QUEUE:
  91. case OC_NEED_MEDIA:
  92. case OC_WIZARD_CREATED:
  93. break;
  94. default:
  95. break;
  96. }
  97. return( dwRet );
  98. }
  99. DWORD
  100. CRsOptCom::PreInitialize(
  101. IN DWORD /*Flags*/
  102. )
  103. {
  104. TRACEFNDW( "CRsOptCom::PreInitialize" );
  105. #ifdef UNICODE
  106. dwRet = OCFLAG_UNICODE;
  107. #else
  108. dwRet = OCFLAG_ANSI;
  109. #endif
  110. return( dwRet );
  111. }
  112. DWORD
  113. CRsOptCom::InitComponent(
  114. IN PSETUP_INIT_COMPONENT SetupInitComponent )
  115. {
  116. TRACEFNDW( "CRsOptCom::InitComponent" );
  117. dwRet = NO_ERROR;
  118. m_OCManagerVersion = SetupInitComponent->OCManagerVersion;
  119. m_ComponentVersion = SetupInitComponent->ComponentVersion;
  120. m_OCInfHandle = SetupInitComponent->OCInfHandle;
  121. m_ComponentInfHandle = SetupInitComponent->ComponentInfHandle;
  122. m_SetupData = SetupInitComponent->SetupData;
  123. m_HelperRoutines = SetupInitComponent->HelperRoutines;
  124. return( dwRet );
  125. }
  126. SubComponentState
  127. CRsOptCom::DetectInitialState(
  128. IN SHORT /*SubcomponentId*/
  129. )
  130. {
  131. TRACEFN( "CRsOptCom::DetectInitialState" );
  132. SubComponentState retval = SubcompUseOcManagerDefault;
  133. return( retval );
  134. }
  135. SubComponentState
  136. CRsOptCom::QueryState(
  137. IN SHORT /*SubcomponentId*/
  138. )
  139. {
  140. TRACEFN( "CRsOptCom::QueryState" );
  141. SubComponentState retval = SubcompUseOcManagerDefault;
  142. return( retval );
  143. }
  144. BOOL
  145. CRsOptCom::SetLanguage(
  146. WORD /*LangId*/
  147. )
  148. {
  149. TRACEFNBOOL( "CRsOptCom::SetLanguage" );
  150. boolRet = TRUE;
  151. return( boolRet );
  152. }
  153. HBITMAP
  154. CRsOptCom::QueryImage(
  155. IN SHORT /*SubcomponentId*/,
  156. IN SubComponentInfo /*WhichImage*/,
  157. IN WORD /*Width*/,
  158. IN WORD /*Height*/
  159. )
  160. {
  161. TRACEFN( "CRsOptCom::QueryImage" );
  162. HBITMAP retval = 0;
  163. return( retval );
  164. }
  165. BOOL
  166. CRsOptCom::QueryImageEx(
  167. IN SHORT /*SubcomponentId*/,
  168. IN OC_QUERY_IMAGE_INFO* /*pQueryImageInfo*/,
  169. OUT HBITMAP *phBitmap
  170. )
  171. {
  172. TRACEFNBOOL( "CRsOptCom::QueryImageEx" );
  173. if (phBitmap) {
  174. *phBitmap = NULL;
  175. }
  176. boolRet = FALSE;
  177. return( boolRet );
  178. }
  179. LONG
  180. CRsOptCom::RequestPages(
  181. IN WizardPagesType /*Type*/,
  182. IN OUT PSETUP_REQUEST_PAGES /*RequestPages*/
  183. )
  184. {
  185. TRACEFNLONG( "CRsOptCom::RequestPages" );
  186. lRet = 0;
  187. return( lRet );
  188. }
  189. BOOL
  190. CRsOptCom::QuerySkipPage(
  191. IN OcManagerPage /*Page*/
  192. )
  193. {
  194. TRACEFNBOOL( "CRsOptCom::QuerySkipPage" );
  195. boolRet = FALSE;
  196. return( boolRet );
  197. }
  198. BOOL
  199. CRsOptCom::QueryChangeSelState(
  200. IN SHORT /*SubcomponentId*/,
  201. IN BOOL /*NewState*/,
  202. IN DWORD /*Flags*/
  203. )
  204. {
  205. TRACEFNBOOL( "CRsOptCom::QueryChangeSelState" );
  206. boolRet = TRUE;
  207. return( boolRet );
  208. }
  209. DWORD
  210. CRsOptCom::CalcDiskSpace(
  211. IN SHORT /*SubcomponentId*/,
  212. IN BOOL /*AddSpace*/,
  213. IN HDSKSPC /*hDiskSpace*/
  214. )
  215. {
  216. TRACEFNDW( "CRsOptCom::CalcDiskSpace" );
  217. dwRet = 0;
  218. return( dwRet );
  219. }
  220. DWORD
  221. CRsOptCom::QueueFileOps(
  222. IN SHORT /*SubcomponentId*/,
  223. IN HSPFILEQ /*hFileQueue*/
  224. )
  225. {
  226. TRACEFNDW( "CRsOptCom::QueueFileOps" );
  227. dwRet = 0;
  228. return( dwRet );
  229. }
  230. LONG
  231. CRsOptCom::QueryStepCount(
  232. IN SHORT /*SubcomponentId*/
  233. )
  234. {
  235. TRACEFNLONG( "CRsOptCom::QueryStepCount" );
  236. lRet = 0;
  237. return( lRet );
  238. }
  239. DWORD
  240. CRsOptCom::AboutToCommitQueue(
  241. IN SHORT /*SubcomponentId*/
  242. )
  243. {
  244. TRACEFNDW( "CRsOptCom::AboutToCommitQueue" );
  245. dwRet = 0;
  246. return( dwRet );
  247. }
  248. DWORD
  249. CRsOptCom::CompleteInstallation(
  250. IN SHORT /*SubcomponentId*/
  251. )
  252. {
  253. TRACEFNDW( "CRsOptCom::CompleteInstallation" );
  254. dwRet = 0;
  255. return( dwRet );
  256. }
  257. void
  258. CRsOptCom::CleanUp(
  259. void
  260. )
  261. {
  262. TRACEFN( "CRsOptCom::CleanUp" );
  263. }
  264. DWORD
  265. CRsOptCom::DoCalcDiskSpace(
  266. IN BOOL AddSpace,
  267. IN HDSKSPC hDiskSpace,
  268. IN LPCTSTR SectionName
  269. )
  270. {
  271. TRACEFNDW( "CRsOptCom::DoCalcDiskSpace" );
  272. dwRet = NO_ERROR;
  273. HINF hLayoutInf = SetupOpenInfFile( L"layout.inf", 0, INF_STYLE_WIN4 | INF_STYLE_OLDNT , 0 );
  274. if( INVALID_HANDLE_VALUE == hLayoutInf) {
  275. dwRet = GetLastError( );
  276. TRACE( _T("CRsOptCom::AboutToCommitQueue Error opening LAYOUT.INF") );
  277. }
  278. if( NO_ERROR == dwRet ) {
  279. if( AddSpace ) {
  280. if( SetupAddInstallSectionToDiskSpaceList( hDiskSpace, m_ComponentInfHandle, hLayoutInf, SectionName, 0, 0 ) ) {
  281. dwRet = GetLastError( );
  282. }
  283. } else {
  284. if ( SetupRemoveInstallSectionFromDiskSpaceList( hDiskSpace, m_ComponentInfHandle, hLayoutInf, SectionName, 0, 0 ) ) {
  285. dwRet = GetLastError( );
  286. }
  287. }
  288. }
  289. if( INVALID_HANDLE_VALUE != hLayoutInf) {
  290. SetupCloseInfFile( hLayoutInf );
  291. }
  292. return( dwRet );
  293. }
  294. DWORD
  295. CRsOptCom::DoQueueFileOps(
  296. IN SHORT SubcomponentId,
  297. IN HSPFILEQ hFileQueue,
  298. IN LPCTSTR InstallSectionName,
  299. IN LPCTSTR UninstallSectionName
  300. )
  301. {
  302. TRACEFNDW( "CRsOptCom::DoQueueFileOps" );
  303. BOOL success = TRUE;
  304. RSOPTCOM_ACTION action = GetSubAction( SubcomponentId );
  305. switch( action ) {
  306. case ACTION_INSTALL:
  307. success = SetupInstallFilesFromInfSection( m_ComponentInfHandle, 0, hFileQueue, InstallSectionName, 0, SP_COPY_FORCE_NEWER );
  308. break;
  309. case ACTION_UNINSTALL:
  310. success = SetupInstallFilesFromInfSection( m_ComponentInfHandle, 0, hFileQueue, UninstallSectionName, 0, 0 );
  311. break;
  312. case ACTION_UPGRADE:
  313. success = SetupInstallFilesFromInfSection( m_ComponentInfHandle, 0, hFileQueue, InstallSectionName, 0, SP_COPY_FORCE_NEWER );
  314. break;
  315. }
  316. dwRet = success ? NO_ERROR : GetLastError( );
  317. return( dwRet );
  318. }
  319. DWORD
  320. CRsOptCom::DoRegistryOps(
  321. IN SHORT SubcomponentId,
  322. IN RSOPTCOM_ACTION actionForReg,
  323. IN LPCTSTR SectionName
  324. )
  325. {
  326. TRACEFNDW( "CRsOptCom::DoRegistryOps" );
  327. BOOL success = TRUE;
  328. RSOPTCOM_ACTION action = GetSubAction( SubcomponentId );
  329. if ( action == actionForReg ) {
  330. success = SetupInstallFromInfSection(
  331. NULL, m_ComponentInfHandle, SectionName,
  332. SPINST_REGISTRY, NULL, NULL,
  333. 0, NULL, NULL, NULL, NULL );
  334. }
  335. dwRet = success ? NO_ERROR : GetLastError( );
  336. return( dwRet );
  337. }
  338. LPCWSTR
  339. CRsOptCom::StringFromFunction(
  340. UINT Function
  341. )
  342. {
  343. #define CASE_FUNCTION( a ) case a: return( OLESTR( #a ) );
  344. switch( Function ) {
  345. CASE_FUNCTION( OC_PREINITIALIZE )
  346. CASE_FUNCTION( OC_INIT_COMPONENT )
  347. CASE_FUNCTION( OC_SET_LANGUAGE )
  348. CASE_FUNCTION( OC_QUERY_IMAGE )
  349. CASE_FUNCTION( OC_REQUEST_PAGES )
  350. CASE_FUNCTION( OC_QUERY_CHANGE_SEL_STATE )
  351. CASE_FUNCTION( OC_CALC_DISK_SPACE )
  352. CASE_FUNCTION( OC_QUEUE_FILE_OPS )
  353. CASE_FUNCTION( OC_NOTIFICATION_FROM_QUEUE )
  354. CASE_FUNCTION( OC_QUERY_STEP_COUNT )
  355. CASE_FUNCTION( OC_COMPLETE_INSTALLATION )
  356. CASE_FUNCTION( OC_CLEANUP )
  357. CASE_FUNCTION( OC_QUERY_STATE )
  358. CASE_FUNCTION( OC_NEED_MEDIA )
  359. CASE_FUNCTION( OC_ABOUT_TO_COMMIT_QUEUE )
  360. CASE_FUNCTION( OC_QUERY_SKIP_PAGE )
  361. CASE_FUNCTION( OC_WIZARD_CREATED )
  362. }
  363. return( TEXT( "Unknown" ) );
  364. }
  365. LPCWSTR
  366. CRsOptCom::StringFromPageType(
  367. WizardPagesType PageType
  368. )
  369. {
  370. #define CASE_PAGETYPE( a ) case a: return( OLESTR( #a ) );
  371. switch( PageType ) {
  372. CASE_PAGETYPE( WizPagesWelcome )
  373. CASE_PAGETYPE( WizPagesMode )
  374. CASE_PAGETYPE( WizPagesEarly )
  375. CASE_PAGETYPE( WizPagesPrenet )
  376. CASE_PAGETYPE( WizPagesPostnet )
  377. CASE_PAGETYPE( WizPagesLate )
  378. CASE_PAGETYPE( WizPagesFinal )
  379. CASE_PAGETYPE( WizPagesTypeMax )
  380. }
  381. return( TEXT( "Unknown" ) );
  382. }
  383. LPCWSTR
  384. CRsOptCom::StringFromAction(
  385. RSOPTCOM_ACTION Action
  386. )
  387. {
  388. #define CASE_ACTION( a ) case a: return( OLESTR( #a ) );
  389. switch( Action ) {
  390. CASE_ACTION( ACTION_NONE )
  391. CASE_ACTION( ACTION_INSTALL )
  392. CASE_ACTION( ACTION_UNINSTALL )
  393. CASE_ACTION( ACTION_REINSTALL )
  394. CASE_ACTION( ACTION_UPGRADE )
  395. }
  396. return( TEXT( "Unknown" ) );
  397. }
  398. RSOPTCOM_ACTION
  399. CRsOptCom::GetSubAction(
  400. SHORT SubcomponentId
  401. )
  402. {
  403. TRACEFN( "CRsOptCom::GetSubAction" );
  404. RSOPTCOM_ACTION retval = ACTION_NONE;
  405. UINT setupMode = GetSetupMode( );
  406. DWORDLONG operationFlags = m_SetupData.OperationFlags;
  407. BOOL originalState = QuerySelectionState( SubcomponentId, OCSELSTATETYPE_ORIGINAL );
  408. BOOL currentState = QuerySelectionState( SubcomponentId, OCSELSTATETYPE_CURRENT );
  409. if( !originalState && currentState ) {
  410. retval = ACTION_INSTALL;
  411. } else if( originalState && !currentState ) {
  412. retval = ACTION_UNINSTALL;
  413. } else if( ( SETUPOP_NTUPGRADE & operationFlags ) && originalState && currentState ) {
  414. retval = ACTION_UPGRADE;
  415. }
  416. TRACE( L"SubcomponentId = <%hd>, originalState = <%hs>, currentState = <%hs>", SubcomponentId, RsBoolAsString( originalState ), RsBoolAsString( currentState ) );
  417. TRACE( L"OperationsFlags = <0x%0.16I64x>, setupMode = <0x%p>", operationFlags, setupMode );
  418. TRACE( L"retval = <%ls>", StringFromAction( retval ) );
  419. return( retval );
  420. }
  421. HRESULT
  422. CRsOptCom::CreateLink(
  423. LPCTSTR lpszProgram,
  424. LPCTSTR lpszArgs,
  425. LPTSTR lpszLink,
  426. LPCTSTR lpszDir,
  427. LPCTSTR lpszDesc,
  428. int nItemDescId,
  429. int nDescId,
  430. LPCTSTR lpszIconPath,
  431. int iIconIndex
  432. )
  433. {
  434. TRACEFNHR( "CRsOptCom::CreateLink" );
  435. CComPtr<IShellLink> pShellLink;
  436. TCHAR szSystemPath[MAX_PATH];
  437. TCHAR szResourceString[MAX_PATH+128];
  438. UINT uLen = 0;
  439. szSystemPath[0] = _T('\0');
  440. szResourceString[0] = _T('\0');
  441. // CoInitialize must be called before this
  442. // Get a pointer to the IShellLink interface.
  443. hrRet = CoInitialize( 0 );
  444. if( SUCCEEDED( hrRet ) ) {
  445. hrRet = CoCreateInstance( CLSID_ShellLink, 0, CLSCTX_SERVER, IID_IShellLink, (void**)&pShellLink );
  446. if( SUCCEEDED( hrRet ) ) {
  447. CComPtr<IPersistFile> pPersistFile;
  448. // Set the path to the shortcut target, and add the description.
  449. pShellLink->SetPath( lpszProgram );
  450. pShellLink->SetArguments( lpszArgs );
  451. pShellLink->SetWorkingDirectory( lpszDir );
  452. pShellLink->SetIconLocation( lpszIconPath, iIconIndex );
  453. // Description should be set using the resource id in order to support MUI
  454. uLen = GetSystemDirectory(szSystemPath, MAX_PATH);
  455. if ((uLen > 0) && (uLen < MAX_PATH)) {
  456. wsprintf(szResourceString, TEXT("@%s\\setup\\RsOptCom.dll,-%d"), szSystemPath, nDescId);
  457. pShellLink->SetDescription(szResourceString);
  458. } else {
  459. // Set English description
  460. pShellLink->SetDescription(lpszDesc);
  461. }
  462. // Query IShellLink for the IPersistFile interface for saving the
  463. // shortcut in persistent storage.
  464. hrRet = pShellLink->QueryInterface( IID_IPersistFile, (void**)&pPersistFile );
  465. if( SUCCEEDED( hrRet ) ) {
  466. CComBSTR wsz = lpszLink;
  467. // Save the link by calling IPersistFile::Save.
  468. hrRet = pPersistFile->Save( wsz, TRUE );
  469. if( SUCCEEDED(hrRet) && (uLen > 0) && (uLen < MAX_PATH)) {
  470. // Shortcut created - set MUI name.
  471. wsprintf(szResourceString, TEXT("%s\\setup\\RsOptCom.dll"), szSystemPath);
  472. hrRet = SHSetLocalizedName(lpszLink, szResourceString, nItemDescId);
  473. }
  474. }
  475. }
  476. CoUninitialize();
  477. }
  478. return( hrRet );
  479. }
  480. BOOL
  481. CRsOptCom::DeleteLink(
  482. LPTSTR lpszShortcut
  483. )
  484. {
  485. TRACEFNBOOL( "CRsOptCom::DeleteLink" );
  486. boolRet = TRUE;
  487. TCHAR szFile[_MAX_PATH];
  488. SHFILEOPSTRUCT fos;
  489. ZeroMemory( szFile, sizeof(szFile) );
  490. lstrcpy( szFile, lpszShortcut );
  491. if( DoesFileExist( szFile ) ) {
  492. ZeroMemory( &fos, sizeof(fos) );
  493. fos.hwnd = NULL;
  494. fos.wFunc = FO_DELETE;
  495. fos.pFrom = szFile;
  496. fos.fFlags = FOF_SILENT | FOF_NOCONFIRMATION;
  497. SHFileOperation( &fos );
  498. }
  499. return( boolRet );
  500. }
  501. HRESULT
  502. CRsOptCom::GetGroupPath(
  503. int nFolder,
  504. LPTSTR szPath
  505. )
  506. {
  507. TRACEFNHR( "CRsOptCom::GetGroupPath" );
  508. szPath[0] = _T('\0');
  509. hrRet = SHGetFolderPath( 0, nFolder | CSIDL_FLAG_CREATE, 0, 0, szPath );
  510. TRACE( L"szPath = <%ls>", szPath );
  511. return( hrRet );
  512. }
  513. void
  514. CRsOptCom::AddItem(
  515. int nFolder,
  516. LPCTSTR szItemDesc,
  517. LPCTSTR szProgram,
  518. LPCTSTR szArgs,
  519. LPCTSTR szDir,
  520. LPCTSTR szDesc,
  521. int nItemDescId,
  522. int nDescId,
  523. LPCTSTR szIconPath,
  524. int iIconIndex
  525. )
  526. {
  527. TRACEFN( "CRsOptCom::AddItem" );
  528. TCHAR szPath[_MAX_PATH];
  529. if( S_OK == GetGroupPath( nFolder, szPath ) ) {
  530. lstrcat( szPath, _T("\\") );
  531. lstrcat( szPath, szItemDesc );
  532. lstrcat( szPath, _T(".lnk") );
  533. CreateLink( szProgram, szArgs, szPath, szDir, szDesc, nItemDescId, nDescId, szIconPath, iIconIndex );
  534. }
  535. }
  536. void
  537. CRsOptCom::DeleteItem(
  538. int nFolder,
  539. LPCTSTR szAppName
  540. )
  541. {
  542. TRACEFN( "CRsOptCom::DeleteItem" );
  543. TCHAR szPath[_MAX_PATH];
  544. if( S_OK == GetGroupPath( nFolder, szPath ) ) {
  545. lstrcat( szPath, _T("\\") );
  546. lstrcat( szPath, szAppName );
  547. lstrcat( szPath, _T(".lnk") );
  548. DeleteLink( szPath );
  549. }
  550. }
  551. typedef
  552. HRESULT
  553. (WINAPI *PFN_DLLENTRYPOINT)(
  554. void
  555. );
  556. HRESULT
  557. CRsOptCom::CallDllEntryPoint(
  558. LPCTSTR pszDLLName,
  559. LPCSTR pszEntryPoint
  560. )
  561. {
  562. TRACEFNHR( "CRsOptCom::CallDllEntryPoint" );
  563. TRACE( _T("Dll <%s> Func <%hs>"), pszDLLName, pszEntryPoint );
  564. HINSTANCE hDLL = 0;
  565. PFN_DLLENTRYPOINT pfnEntryPoint;
  566. try {
  567. hDLL = LoadLibrary( pszDLLName );
  568. RsOptAffirmStatus( hDLL );
  569. pfnEntryPoint = (PFN_DLLENTRYPOINT)GetProcAddress( hDLL, pszEntryPoint );
  570. RsOptAffirmStatus( pfnEntryPoint );
  571. hrRet = pfnEntryPoint();
  572. } RsOptCatch( hrRet );
  573. if( hDLL ) FreeLibrary( hDLL );
  574. return( hrRet );
  575. }