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.

742 lines
20 KiB

  1. //
  2. // Microsoft Corporation 1998
  3. //
  4. // SNAPIN.CPP - CSnapin rountines
  5. //
  6. #include "main.h"
  7. #include <shlwapi.h>
  8. #define MAX_INI_SECTION_SIZE 10
  9. #define MAX_OPTION_SIZE 256
  10. #define RIGPSNAP_HELP_TOPIC L"RISconcepts.chm::/sag_RIS_CIW_Policy_and_ACLs.htm"
  11. unsigned int CSnapIn::m_cfNodeType = RegisterClipboardFormat(CCF_NODETYPE);
  12. TCHAR CSnapIn::m_szDefaultIcon[] = TEXT("mydocs.dll,0");
  13. struct {
  14. DWORD dwCtlIdAllow; // dialog control IDs
  15. DWORD dwCtlIdDontCare; // dialog control IDs
  16. DWORD dwCtlIdDeny; // dialog control IDs
  17. DWORD dwValId; // string resouce ID for the option's name
  18. } g_ChoiceOptions[] = {
  19. { IDC_R_AUTO_ALLOW, IDC_R_AUTO_DONTCARE, IDC_R_AUTO_DENY, IDS_AUTO },
  20. { IDC_R_CUST_ALLOW, IDC_R_CUST_DONTCARE, IDC_R_CUST_DENY, IDS_CUSTOM },
  21. { IDC_R_RESTART_ALLOW, IDC_R_RESTART_DONTCARE, IDC_R_RESTART_DENY, IDS_RESTART },
  22. { IDC_R_TOOLS_ALLOW, IDC_R_TOOLS_DONTCARE, IDC_R_TOOLS_DENY, IDS_TOOLS }
  23. };
  24. ///////////////////////////////////////////////////////////////////////////////
  25. //
  26. // CSnapIn object implementation
  27. //
  28. CSnapIn::CSnapIn(CComponentData *pComponent)
  29. {
  30. m_cRef = 1;
  31. InterlockedIncrement(&g_cRefThisDll);
  32. m_pcd = pComponent;
  33. m_pConsole = NULL;
  34. m_pResult = NULL;
  35. m_pHeader = NULL;
  36. m_pImageResult = NULL;
  37. m_pConsoleVerb = NULL;
  38. m_nColumnSize = 180;
  39. m_lViewMode = LVS_ICON;
  40. //LoadString(g_hInstance, IDS_NAME, m_column1, sizeof(m_column1));
  41. }
  42. CSnapIn::~CSnapIn()
  43. {
  44. InterlockedDecrement(&g_cRefThisDll);
  45. }
  46. ///////////////////////////////////////////////////////////////////////////////
  47. //
  48. // CSnapIn object implementation (IUnknown)
  49. //
  50. HRESULT CSnapIn::QueryInterface (REFIID riid, void **ppv)
  51. {
  52. if (IsEqualIID(riid, IID_IComponent) || IsEqualIID(riid, IID_IUnknown))
  53. {
  54. *ppv = (LPCOMPONENT)this;
  55. m_cRef++;
  56. return S_OK;
  57. }
  58. else if (IsEqualIID(riid, IID_IExtendPropertySheet))
  59. {
  60. *ppv = (LPEXTENDPROPERTYSHEET)this;
  61. m_cRef++;
  62. return S_OK;
  63. }
  64. else
  65. {
  66. *ppv = NULL;
  67. return E_NOINTERFACE;
  68. }
  69. }
  70. ULONG CSnapIn::AddRef (void)
  71. {
  72. return ++m_cRef;
  73. }
  74. ULONG CSnapIn::Release (void)
  75. {
  76. if (--m_cRef == 0) {
  77. delete this;
  78. return 0;
  79. }
  80. return m_cRef;
  81. }
  82. ///////////////////////////////////////////////////////////////////////////////
  83. //
  84. // CSnapIn object implementation (IComponent)
  85. //
  86. STDMETHODIMP CSnapIn::Initialize(LPCONSOLE lpConsole)
  87. {
  88. HRESULT hr;
  89. if (!LoadString(g_hInstance, IDS_NAME, m_column1, ARRAYSIZE(m_column1))) {
  90. return(HRESULT_FROM_WIN32(GetLastError()));
  91. }
  92. // Save the IConsole pointer
  93. m_pConsole = lpConsole;
  94. m_pConsole->AddRef();
  95. hr = m_pConsole->QueryInterface(IID_IHeaderCtrl,
  96. reinterpret_cast<void**>(&m_pHeader));
  97. // Give the console the header control interface pointer
  98. if (SUCCEEDED(hr))
  99. m_pConsole->SetHeader(m_pHeader);
  100. m_pConsole->QueryInterface(IID_IResultData,
  101. reinterpret_cast<void**>(&m_pResult));
  102. hr = m_pConsole->QueryResultImageList(&m_pImageResult);
  103. hr = m_pConsole->QueryConsoleVerb(&m_pConsoleVerb);
  104. return S_OK;
  105. }
  106. STDMETHODIMP CSnapIn::Destroy(MMC_COOKIE cookie)
  107. {
  108. if (m_pConsole != NULL)
  109. {
  110. m_pConsole->SetHeader(NULL);
  111. m_pConsole->Release();
  112. m_pConsole = NULL;
  113. }
  114. if (m_pHeader != NULL)
  115. {
  116. m_pHeader->Release();
  117. m_pHeader = NULL;
  118. }
  119. if (m_pResult != NULL)
  120. {
  121. m_pResult->Release();
  122. m_pResult = NULL;
  123. }
  124. if (m_pImageResult != NULL)
  125. {
  126. m_pImageResult->Release();
  127. m_pImageResult = NULL;
  128. }
  129. if (m_pConsoleVerb != NULL)
  130. {
  131. m_pConsoleVerb->Release();
  132. m_pConsoleVerb = NULL;
  133. }
  134. return S_OK;
  135. }
  136. STDMETHODIMP CSnapIn::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
  137. {
  138. HRESULT hr = S_OK;
  139. switch(event)
  140. {
  141. case MMCN_CONTEXTHELP:
  142. {
  143. IDisplayHelp * phelp = NULL;
  144. hr = m_pConsole->QueryInterface( IID_IDisplayHelp,
  145. (void **)&phelp );
  146. if (SUCCEEDED( hr ))
  147. {
  148. phelp->ShowTopic ( RIGPSNAP_HELP_TOPIC );
  149. }
  150. if ( phelp != NULL )
  151. {
  152. phelp->Release();
  153. }
  154. }
  155. break;
  156. case MMCN_DBLCLICK:
  157. hr = S_FALSE;
  158. break;
  159. case MMCN_ADD_IMAGES:
  160. HBITMAP hbmp16x16;
  161. HBITMAP hbmp32x32;
  162. hbmp16x16 = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_16x16));
  163. hbmp32x32 = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_32x32));
  164. if (hbmp16x16 && hbmp32x32) {
  165. // Set the images
  166. m_pImageResult->ImageListSetStrip(reinterpret_cast<PLONG_PTR>(hbmp16x16),
  167. reinterpret_cast<PLONG_PTR>(hbmp32x32),
  168. 0, RGB(255, 0, 255));
  169. }
  170. if (hbmp16x16) {
  171. DeleteObject(hbmp16x16);
  172. }
  173. if (hbmp32x32) {
  174. DeleteObject(hbmp32x32);
  175. }
  176. break;
  177. case MMCN_SHOW:
  178. if (arg == TRUE)
  179. {
  180. RESULTDATAITEM resultItem;
  181. LPGPTDATAOBJECT pGPTDataObject;
  182. MMC_COOKIE cookie;
  183. INT i;
  184. //
  185. // Get the cookie of the scope pane item
  186. //
  187. hr = lpDataObject->QueryInterface(IID_IGPTDataObject, (LPVOID *)&pGPTDataObject);
  188. if (FAILED(hr))
  189. return S_OK;
  190. hr = pGPTDataObject->GetCookie(&cookie);
  191. pGPTDataObject->Release(); // release initial ref
  192. if (FAILED(hr))
  193. return S_OK;
  194. //
  195. // Prepare the view
  196. //
  197. m_pHeader->InsertColumn(0, m_column1, LVCFMT_LEFT, m_nColumnSize);
  198. m_pResult->SetViewMode(m_lViewMode);
  199. //
  200. // Add result pane items for this node
  201. //
  202. for (i = 0; i < g_NameSpace[cookie].cResultItems; i++)
  203. {
  204. resultItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
  205. resultItem.str = MMC_CALLBACK;
  206. resultItem.nImage = g_NameSpace[cookie].pResultItems[i].iImage;
  207. resultItem.lParam = (LPARAM) &g_NameSpace[cookie].pResultItems[i];
  208. m_pResult->InsertItem(&resultItem);
  209. }
  210. //m_pResult->Sort(0, 0, -1);
  211. }
  212. else
  213. {
  214. m_pHeader->GetColumnWidth(0, &m_nColumnSize);
  215. m_pResult->GetViewMode(&m_lViewMode);
  216. }
  217. break;
  218. case MMCN_SELECT:
  219. if (m_pConsoleVerb)
  220. {
  221. LPRESULTITEM pItem;
  222. LPGPTDATAOBJECT pGPTDataObject;
  223. DATA_OBJECT_TYPES type;
  224. MMC_COOKIE cookie;
  225. //
  226. // Set the default verb to open
  227. //
  228. m_pConsoleVerb->SetDefaultVerb(MMC_VERB_OPEN);
  229. //
  230. // See if this is one of our items.
  231. //
  232. hr = lpDataObject->QueryInterface(IID_IGPTDataObject, (LPVOID *)&pGPTDataObject);
  233. if (FAILED(hr))
  234. break;
  235. pGPTDataObject->GetType(&type);
  236. pGPTDataObject->GetCookie(&cookie);
  237. pGPTDataObject->Release();
  238. //
  239. // If this is a result pane item or the root of the namespace
  240. // nodes, enable the Properties menu item
  241. //
  242. if ((type == CCT_RESULT) || ((type == CCT_SCOPE) && (cookie == 0)))
  243. {
  244. m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE);
  245. //
  246. // If this is a result pane item, then change the default
  247. // verb to Properties.
  248. //
  249. if (type == CCT_RESULT)
  250. m_pConsoleVerb->SetDefaultVerb(MMC_VERB_PROPERTIES);
  251. }
  252. }
  253. break;
  254. default:
  255. hr = E_UNEXPECTED;
  256. break;
  257. }
  258. return hr;
  259. }
  260. STDMETHODIMP CSnapIn::GetDisplayInfo(LPRESULTDATAITEM pResult)
  261. {
  262. if (pResult)
  263. {
  264. if (pResult->bScopeItem == TRUE)
  265. {
  266. if (pResult->mask & RDI_STR)
  267. {
  268. if (pResult->nCol == 0)
  269. pResult->str = g_NameSpace[pResult->lParam].szDisplayName;
  270. else
  271. pResult->str = L"";
  272. }
  273. if (pResult->mask & RDI_IMAGE)
  274. {
  275. pResult->nImage = 0;
  276. }
  277. }
  278. else
  279. {
  280. if (pResult->mask & RDI_STR)
  281. {
  282. if (pResult->nCol == 0)
  283. {
  284. LPRESULTITEM lpResultItem = (LPRESULTITEM)pResult->lParam;
  285. if (lpResultItem->szDisplayName[0] == TEXT('\0'))
  286. {
  287. if (!LoadString (g_hInstance, lpResultItem->iStringID,
  288. lpResultItem->szDisplayName,
  289. MAX_DISPLAYNAME_SIZE)) {
  290. return(HRESULT_FROM_WIN32(GetLastError()));
  291. }
  292. }
  293. pResult->str = lpResultItem->szDisplayName;
  294. }
  295. if (pResult->str == NULL)
  296. pResult->str = (LPOLESTR)L"";
  297. }
  298. }
  299. }
  300. return S_OK;
  301. }
  302. STDMETHODIMP CSnapIn::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT *ppDataObject)
  303. {
  304. return m_pcd->QueryDataObject(cookie, type, ppDataObject);
  305. }
  306. STDMETHODIMP CSnapIn::GetResultViewType(MMC_COOKIE cookie, LPOLESTR *ppViewType,
  307. LONG *pViewOptions)
  308. {
  309. return S_FALSE;
  310. }
  311. STDMETHODIMP CSnapIn::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
  312. {
  313. HRESULT hr = S_FALSE;
  314. LPGPTDATAOBJECT pGPTDataObjectA, pGPTDataObjectB;
  315. MMC_COOKIE cookie1, cookie2;
  316. if (lpDataObjectA == NULL || lpDataObjectB == NULL)
  317. return E_POINTER;
  318. //
  319. // QI for the private GPTDataObject interface
  320. //
  321. if (FAILED(lpDataObjectA->QueryInterface(IID_IGPTDataObject,
  322. (LPVOID *)&pGPTDataObjectA)))
  323. {
  324. return S_FALSE;
  325. }
  326. if (FAILED(lpDataObjectB->QueryInterface(IID_IGPTDataObject,
  327. (LPVOID *)&pGPTDataObjectB)))
  328. {
  329. pGPTDataObjectA->Release();
  330. return S_FALSE;
  331. }
  332. pGPTDataObjectA->GetCookie(&cookie1);
  333. pGPTDataObjectB->GetCookie(&cookie2);
  334. if (cookie1 == cookie2)
  335. {
  336. hr = S_OK;
  337. }
  338. pGPTDataObjectA->Release();
  339. pGPTDataObjectB->Release();
  340. return hr;
  341. }
  342. ///////////////////////////////////////////////////////////////////////////////
  343. //
  344. // CComponentData object implementation (IExtendPropertySheet)
  345. //
  346. STDMETHODIMP CSnapIn::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
  347. LONG_PTR handle, LPDATAOBJECT lpDataObject)
  348. {
  349. HRESULT hr;
  350. PROPSHEETPAGE psp;
  351. HPROPSHEETPAGE hPage[2];
  352. LPGPTDATAOBJECT pGPTDataObject;
  353. LPRESULTITEM pItem;
  354. MMC_COOKIE cookie;
  355. //
  356. // Make sure this is one of our objects
  357. //
  358. if (FAILED(lpDataObject->QueryInterface(IID_IGPTDataObject,
  359. (LPVOID *)&pGPTDataObject)))
  360. {
  361. return S_OK;
  362. }
  363. //
  364. // Get the cookie
  365. //
  366. pGPTDataObject->GetCookie(&cookie);
  367. pGPTDataObject->Release();
  368. pItem = (LPRESULTITEM)cookie;
  369. //
  370. // Initialize the common fields in the property sheet structure
  371. //
  372. psp.dwSize = sizeof(PROPSHEETPAGE);
  373. psp.dwFlags = 0;
  374. psp.hInstance = g_hInstance;
  375. psp.lParam = (LPARAM) this;
  376. //
  377. // Do the page specific stuff
  378. //
  379. switch (pItem->dwID)
  380. {
  381. case 2:
  382. psp.pszTemplate = MAKEINTRESOURCE(IDD_SCREEN);
  383. psp.pfnDlgProc = ChoiceDlgProc;
  384. hPage[0] = CreatePropertySheetPage(&psp);
  385. if (hPage[0])
  386. {
  387. hr = lpProvider->AddPage(hPage[0]);
  388. }
  389. else
  390. {
  391. DebugMsg((DM_WARNING, TEXT("CSnapIn::CreatePropertyPages: Failed to create property sheet page with %d."),
  392. GetLastError()));
  393. hr = E_FAIL;
  394. }
  395. break;
  396. }
  397. return (hr);
  398. }
  399. STDMETHODIMP CSnapIn::QueryPagesFor(LPDATAOBJECT lpDataObject)
  400. {
  401. LPGPTDATAOBJECT pGPTDataObject;
  402. DATA_OBJECT_TYPES type;
  403. if (SUCCEEDED(lpDataObject->QueryInterface(IID_IGPTDataObject,
  404. (LPVOID *)&pGPTDataObject)))
  405. {
  406. pGPTDataObject->GetType(&type);
  407. pGPTDataObject->Release();
  408. if (type == CCT_RESULT)
  409. return S_OK;
  410. }
  411. return S_FALSE;
  412. }
  413. ///////////////////////////////////////////////////////////////////////////////
  414. //
  415. // CSnapIn object implementation (Internal functions)
  416. //
  417. INT_PTR CALLBACK CSnapIn::ReadmeDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  418. {
  419. return FALSE;
  420. }
  421. INT_PTR CALLBACK CSnapIn::_CreateDirectoryIfNeeded( LPOLESTR pszPath )
  422. {
  423. BOOL b = FALSE;
  424. LPOLESTR psz = &pszPath[ wcslen( pszPath ) ];
  425. DWORD dwErr;
  426. while ( psz = StrRChr( pszPath, psz, L'\\' ) )
  427. {
  428. WCHAR tmp = *psz; // save
  429. *psz = L'\0'; // terminate
  430. b = CreateDirectory( pszPath, NULL );
  431. *psz = tmp; // restore
  432. if (b)
  433. { // success in creating directory
  434. psz++;
  435. while ( psz = StrChr( psz, L'\\' ) )
  436. {
  437. tmp = *psz; // save
  438. *psz = L'\0'; // terminate
  439. b = CreateDirectory( pszPath, NULL );
  440. *psz = tmp; // restore
  441. if ( !b )
  442. {
  443. dwErr = GetLastError();
  444. break;
  445. }
  446. psz++;
  447. }
  448. break;
  449. }
  450. // else failed... keep backing up
  451. dwErr = GetLastError();
  452. psz--;
  453. }
  454. return b;
  455. }
  456. INT_PTR CALLBACK CSnapIn::ChoiceDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  457. {
  458. CSnapIn * pCS = (CSnapIn*) GetWindowLongPtr( hDlg, DWLP_USER );
  459. static BOOL bDirty;
  460. BOOL fReturn = FALSE;
  461. HRESULT hr;
  462. BSTR pszPath = NULL;
  463. if ( message == WM_INITDIALOG )
  464. {
  465. bDirty = FALSE;
  466. pCS = (CSnapIn *) (((LPPROPSHEETPAGE)lParam)->lParam);
  467. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR) pCS);
  468. if (!pCS)
  469. goto Cleanup;
  470. pszPath = SysAllocStringByteLen( NULL, MAX_PATH * sizeof(OLECHAR) );
  471. if (!pszPath)
  472. goto Cleanup;
  473. hr = pCS->m_pcd->m_pGPTInformation->GetFileSysPath( GPO_SECTION_USER, pszPath, MAX_PATH );
  474. if (SUCCEEDED(hr) &&
  475. (wcslen(pszPath) + ARRAYSIZE(L"\\Microsoft\\RemoteInstall\\oscfilter.ini") <= MAX_PATH ))
  476. {
  477. wcscat( pszPath, L"\\Microsoft\\RemoteInstall\\oscfilter.ini");
  478. for ( INT i = 0; i < ARRAYSIZE(g_ChoiceOptions); i++ )
  479. {
  480. WCHAR szValue[MAX_INI_SECTION_SIZE];
  481. LONG lValue = -1; // don't care
  482. DWORD dw;
  483. WCHAR szOption[ MAX_OPTION_SIZE ];
  484. if (!LoadString(
  485. g_hInstance,
  486. g_ChoiceOptions[i].dwValId,
  487. szOption,
  488. ARRAYSIZE( szOption ))) {
  489. lValue = -1;
  490. } else {
  491. dw = GetPrivateProfileString( L"Choice", szOption, L"", szValue, ARRAYSIZE( szValue ), pszPath );
  492. if ( dw != 0 )
  493. {
  494. lValue = wcstol( szValue, NULL, 10 );
  495. }
  496. }
  497. switch (lValue)
  498. {
  499. case 0: // Deny
  500. Button_SetCheck( GetDlgItem( hDlg, g_ChoiceOptions[i].dwCtlIdDeny ), BST_CHECKED );
  501. break;
  502. case 1: // Allow
  503. Button_SetCheck( GetDlgItem( hDlg, g_ChoiceOptions[i].dwCtlIdAllow ), BST_CHECKED );
  504. break;
  505. default: // don't care / unknown value
  506. Button_SetCheck( GetDlgItem( hDlg, g_ChoiceOptions[i].dwCtlIdDontCare ), BST_CHECKED );
  507. break;
  508. }
  509. }
  510. }
  511. }
  512. if (!pCS)
  513. goto Cleanup;
  514. switch (message)
  515. {
  516. case WM_HELP:
  517. case WM_CONTEXTMENU:
  518. {
  519. MMCPropertyHelp( RIGPSNAP_HELP_TOPIC );
  520. }
  521. break;
  522. case WM_COMMAND:
  523. if ( ( LOWORD(wParam) >= IDC_FIRST_RADIO_BUTTON )
  524. && ( LOWORD(wParam) <= IDC_LAST_RADIO_BUTTON ) )
  525. {
  526. if ( !bDirty )
  527. {
  528. SendMessage (GetParent(hDlg), PSM_CHANGED, (WPARAM) hDlg, 0);
  529. bDirty = TRUE;
  530. }
  531. }
  532. break;
  533. case WM_NOTIFY:
  534. switch (((NMHDR FAR*)lParam)->code)
  535. {
  536. case PSN_APPLY:
  537. {
  538. if (bDirty)
  539. {
  540. pszPath = SysAllocStringByteLen( NULL, MAX_PATH );
  541. if (!pszPath)
  542. goto Cleanup;
  543. hr = pCS->m_pcd->m_pGPTInformation->GetFileSysPath( GPO_SECTION_USER, pszPath, MAX_PATH );
  544. if (SUCCEEDED(hr) &&
  545. (wcslen(pszPath) + ARRAYSIZE(L"\\Microsoft\\RemoteInstall\\oscfilter.ini") <= MAX_PATH ))
  546. {
  547. wcscat( pszPath, L"\\Microsoft\\RemoteInstall\\oscfilter.ini");
  548. pCS->_CreateDirectoryIfNeeded( pszPath );
  549. for ( INT i = 0; i < ARRAYSIZE(g_ChoiceOptions); i++ )
  550. {
  551. DWORD dw;
  552. WCHAR szOption[ MAX_OPTION_SIZE ];
  553. if (LoadString(
  554. g_hInstance,
  555. g_ChoiceOptions[i].dwValId,
  556. szOption,
  557. ARRAYSIZE( szOption ))) {
  558. if ( Button_GetCheck( GetDlgItem( hDlg, g_ChoiceOptions[i].dwCtlIdDeny ) ) == BST_CHECKED )
  559. {
  560. WritePrivateProfileString( L"Choice", szOption, L"0", pszPath );
  561. }
  562. if ( Button_GetCheck( GetDlgItem( hDlg, g_ChoiceOptions[i].dwCtlIdAllow ) ) == BST_CHECKED )
  563. {
  564. WritePrivateProfileString( L"Choice", szOption, L"1", pszPath );
  565. }
  566. if ( Button_GetCheck( GetDlgItem( hDlg, g_ChoiceOptions[i].dwCtlIdDontCare ) ) == BST_CHECKED )
  567. {
  568. WritePrivateProfileString( L"Choice", szOption, NULL, pszPath );
  569. }
  570. }
  571. }
  572. // Notify the GPT manager that policy has changed
  573. pCS->m_pcd->m_pGPTInformation->PolicyChanged( FALSE, TRUE, (GUID *)&CLSID_RIClientExtension, (GUID *)&CLSID_GPTRemoteInstall );
  574. }
  575. }
  576. }
  577. // fall through...
  578. case PSN_RESET:
  579. SetWindowLongPtr (hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
  580. bDirty = FALSE;
  581. fReturn = TRUE;
  582. break;
  583. }
  584. break;
  585. }
  586. Cleanup:
  587. if ( pszPath )
  588. SysFreeString( pszPath );
  589. return fReturn;
  590. }