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.

758 lines
17 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
  4. /**********************************************************************/
  5. /*
  6. helper.h
  7. This file defines the following macros helper classes and functions:
  8. Macros to check HRESULT
  9. CDlgHelper -- helper class to Enable/Check dialog Item,
  10. CMangedPage -- helper class for PropertyPage,
  11. It manages ReadOnly, SetModified, and ContextHelp
  12. CStrArray -- an array of pointer to CString
  13. It does NOT duplicate the string upon Add
  14. and It deletes the pointer during destruction
  15. It imports and exports SAFEARRAY
  16. CReadWriteLock -- class for share read or exclusive write lock
  17. CStrBox -- wrapper class for CListBox and CComboBox
  18. CIPAddress -- wrapper for IPAddress
  19. CFramedRoute -- Wrapper for FramedRoute
  20. CStrParse -- parses string for TimeOfDay
  21. FILE HISTORY:
  22. */
  23. // helper functions for dialog and dialog items
  24. #ifndef _DLGHELPER_
  25. #define _DLGHELPER_
  26. #define SAYOK { return S_OK;}
  27. #define NOIMP { return E_NOTIMPL;}
  28. #define TRACEENTER(n) TRACE(_T("Enter" #n))
  29. #define TRACELEAVE(n) TRACE(_T("Leave" #n))
  30. // to reduce the step to set VARIANT
  31. #define V__BOOL(v, v1)\
  32. V_VT(v) = VT_BOOL, V_BOOL(v) = (v1)
  33. #define V__I4(v, v1)\
  34. V_VT(v) = VT_I4, V_I4(v) = (v1)
  35. #define V__I2(v, v1)\
  36. V_VT(v) = VT_I2, V_I2(v) = (v1)
  37. #define V__UI1(v, v1)\
  38. V_VT(v) = VT_UI1, V_UI1(v) = (v1)
  39. #define V__BSTR(v, v1)\
  40. V_VT(v) = VT_BSTR, V_BSTR(v) = (v1)
  41. #define V__ARRAY(v, v1)\
  42. V_VT(v) = VT_ARRAY, V_ARRAY(v) = (v1)
  43. #define REPORT_ERROR(hr) \
  44. TRACE(_T("**** ERROR RETURN <%s @line %d> -> %08lx\n"), \
  45. __FILE__, __LINE__, hr)); \
  46. ReportError(hr, 0, 0);
  47. #ifdef _DEBUG
  48. #define CHECK_HR(hr)\
  49. {if(!CheckADsError(hr, FALSE, __FILE__, __LINE__)){goto L_ERR;}}
  50. #else
  51. #define CHECK_HR(hr)\
  52. if FAILED(hr) goto L_ERR
  53. #endif
  54. #ifdef _DEBUG
  55. #define NOTINCACHE(hr)\
  56. (CheckADsError(hr, TRUE, __FILE__, __LINE__))
  57. #else
  58. #define NOTINCACHE(hr)\
  59. (E_ADS_PROPERTY_NOT_FOUND == (hr))
  60. #endif
  61. BOOL CheckADsError(HRESULT hr, BOOL fIgnoreAttrNotFound, PSTR file, int line);
  62. #ifdef _DEBUG
  63. #define TRACEAfxMessageBox(id) {\
  64. TRACE(_T("AfxMessageBox <%s @line %d> ID: %d\n"), \
  65. __FILE__, __LINE__, id); \
  66. AfxMessageBox(id);}\
  67. #else
  68. #define TRACEAfxMessageBox(id) AfxMessageBox(id)
  69. #endif
  70. // change string Name to CN=Name
  71. void DecorateName(LPWSTR outString, LPCWSTR inString);
  72. // find name from DN for example LDAP://CN=userA,CN=users... returns userA
  73. void FindNameByDN(LPWSTR outString, LPCWSTR inString);
  74. class CDlgHelper
  75. {
  76. public:
  77. static void EnableDlgItem(CDialog* pDialog, int id, bool bEnable = true);
  78. static int GetDlgItemCheck(CDialog* pDialog, int id);
  79. static void SetDlgItemCheck(CDialog* pDialog, int id, int nCheck);
  80. };
  81. // class CPageManager and CManagedPage together handle the situation when
  82. // the property sheet need to do some processing when OnApply function is called
  83. // on some of the pages
  84. class CPageManager
  85. {
  86. public:
  87. CPageManager(){ m_bModified = FALSE; m_bReadOnly = FALSE;};
  88. BOOL GetModified(){ return m_bModified;};
  89. void SetModified(BOOL bModified){ m_bModified = bModified;};
  90. void SetReadOnly(BOOL bReadOnly){ m_bReadOnly = bReadOnly;};
  91. BOOL GetReadOnly(){ return m_bReadOnly;};
  92. virtual BOOL OnApply()
  93. {
  94. if (!GetModified()) return FALSE;
  95. SetModified(FALSE); // prevent from doing this more than once
  96. return TRUE;
  97. }; // to be implemented by the propertysheet
  98. protected:
  99. BOOL m_bModified;
  100. BOOL m_bReadOnly;
  101. };
  102. class CManagedPage : public CPropertyPage // talk back to property sheet
  103. {
  104. DECLARE_DYNCREATE(CManagedPage)
  105. public:
  106. CManagedPage() : CPropertyPage(){
  107. m_bModified = FALSE;
  108. m_bNeedToSave = FALSE;
  109. m_pManager = NULL;
  110. };
  111. CManagedPage(UINT nIDTemplate) : CPropertyPage(nIDTemplate)
  112. {
  113. m_bModified = FALSE;
  114. m_bNeedToSave = FALSE;
  115. m_pManager = NULL;
  116. };
  117. void SetModified( BOOL bModified = TRUE )
  118. {
  119. ASSERT(m_pManager);
  120. if(!m_pManager->GetReadOnly()) // if NOT readonly
  121. {
  122. m_bModified = bModified;
  123. m_bNeedToSave= bModified;
  124. CPropertyPage::SetModified(bModified);
  125. // only set change
  126. if(bModified) m_pManager->SetModified(TRUE);
  127. }
  128. };
  129. BOOL GetModified() { return m_bModified;};
  130. BOOL OnApply()
  131. {
  132. m_bModified = FALSE;
  133. BOOL b = TRUE;
  134. if(m_pManager->GetModified()) // prevent from entering more than once
  135. b= m_pManager->OnApply();
  136. return (b && CPropertyPage::OnApply());
  137. };
  138. // a page has three states: not dirty, dirty and need to save, and not dirty but need to save
  139. // m_bModified == dirty flag
  140. // m_bNeedToSave == need to save flag
  141. // When m_bNeedToSave && !m_bModified is detected upon on saved failure, the modified flag of the page is set
  142. BOOL OnSaved(BOOL bSaved)
  143. {
  144. if(bSaved)
  145. {
  146. m_bModified = FALSE;
  147. m_bNeedToSave = FALSE;
  148. }
  149. else if(m_bNeedToSave && !m_bModified)
  150. SetModified(TRUE);
  151. return TRUE;
  152. };
  153. void SetManager(CPageManager* pManager) { m_pManager = pManager;};
  154. CPageManager* GetManager() { return m_pManager;};
  155. protected:
  156. // help info process
  157. BOOL OnHelpInfo(HELPINFO* pHelpInfo);
  158. void OnContextMenu(CWnd* pWnd, CPoint point);
  159. void SetHelpTable(const DWORD* pTable) { m_pHelpTable = pTable;};
  160. int MyMessageBox(UINT ids, UINT nType = MB_OK);
  161. int MyMessageBox1(LPCTSTR lpszText, LPCTSTR lpszCaption = NULL, UINT nType = MB_OK);
  162. protected:
  163. CPageManager* m_pManager;
  164. BOOL m_bModified;
  165. BOOL m_bNeedToSave;
  166. const DWORD* m_pHelpTable;
  167. };
  168. #include <afxtempl.h>
  169. class CStrArray : public CArray< CString*, CString* >
  170. {
  171. public:
  172. CStrArray(SAFEARRAY* pSA = NULL);
  173. CStrArray(const CStrArray& sarray);
  174. int Find(const CString& Str) const;
  175. int DeleteAll();
  176. virtual ~CStrArray();
  177. operator SAFEARRAY*();
  178. CStrArray& operator = (const CStrArray& sarray);
  179. bool AppendSA(SAFEARRAY* pSA);
  180. };
  181. class CDWArray : public CArray< DWORD, DWORD >
  182. {
  183. public:
  184. CDWArray(const CDWArray& dwarray);
  185. int Find(const DWORD dw) const;
  186. int DeleteAll(){ RemoveAll(); return 0;};
  187. virtual ~CDWArray(){RemoveAll();};
  188. CDWArray& operator = (const CDWArray& dwarray);
  189. operator SAFEARRAY*();
  190. bool AppendSA(SAFEARRAY* pSA);
  191. CDWArray(SAFEARRAY* pSA = NULL);
  192. };
  193. class CBYTEArray : public CArray< BYTE, BYTE >
  194. {
  195. public:
  196. CBYTEArray(const CBYTEArray& bytearray);
  197. int Find(const BYTE byte) const;
  198. int DeleteAll(){ RemoveAll(); return 0;};
  199. virtual ~CBYTEArray(){RemoveAll();};
  200. CBYTEArray& operator = (const CBYTEArray& bytearray);
  201. operator SAFEARRAY*();
  202. bool AppendSA(SAFEARRAY* pSA);
  203. HRESULT AssignBlob(PBYTE pByte, DWORD size);
  204. HRESULT GetBlob(PBYTE pByte, DWORD* pSize);
  205. CBYTEArray(SAFEARRAY* pSA = NULL);
  206. };
  207. // a lock to allow multiple read access exclusive or only one write access
  208. class CReadWriteLock // sharable read, exclusive write
  209. {
  210. public:
  211. CReadWriteLock() : m_nRead(0)
  212. {
  213. #ifdef _DEBUG
  214. d_bWrite = false;
  215. #endif
  216. };
  217. void EnterRead()
  218. {
  219. TRACE(_T("Entering Read Lock ..."));
  220. m_csRead.Lock();
  221. if (!m_nRead++)
  222. m_csWrite.Lock();
  223. m_csRead.Unlock();
  224. TRACE(_T("Entered Read Lock\n"));
  225. };
  226. void LeaveRead()
  227. {
  228. TRACE(_T("Leaving Read Lock ..."));
  229. m_csRead.Lock();
  230. ASSERT(m_nRead > 0);
  231. if (!--m_nRead)
  232. m_csWrite.Unlock();
  233. m_csRead.Unlock();
  234. TRACE(_T("Left Read Lock\n"));
  235. };
  236. void EnterWrite()
  237. {
  238. TRACE(_T("Entering Write Lock ..."));
  239. m_csWrite.Lock();
  240. TRACE(_T("Entered Write Lock\n"));
  241. #ifdef _DEBUG
  242. d_bWrite = true;
  243. #endif
  244. };
  245. void LeaveWrite()
  246. {
  247. #ifdef _DEBUG
  248. d_bWrite = false;
  249. #endif
  250. m_csWrite.Unlock();
  251. TRACE(_T("Left Write Lock\n"));
  252. };
  253. public:
  254. #ifdef _DEBUG
  255. bool d_bWrite;
  256. #endif
  257. protected:
  258. CCriticalSection m_csRead;
  259. CCriticalSection m_csWrite;
  260. int m_nRead;
  261. };
  262. // to manage a list box/ combo box
  263. template <class CBox>
  264. class CStrBox
  265. {
  266. public:
  267. CStrBox(CDialog* pDialog, int id, CStrArray& Strings)
  268. : m_Strings(Strings), m_id(id)
  269. {
  270. m_pDialog = pDialog;
  271. m_pBox = NULL;
  272. };
  273. int Fill()
  274. {
  275. m_pBox = (CBox*)m_pDialog->GetDlgItem(m_id);
  276. ASSERT(m_pBox);
  277. m_pBox->ResetContent();
  278. int count = (int)m_Strings.GetSize();
  279. int index;
  280. for(int i = 0; i < count; i++)
  281. {
  282. index = m_pBox->AddString(*m_Strings[(INT_PTR)i]);
  283. m_pBox->SetItemDataPtr(index, m_Strings[(INT_PTR)i]);
  284. }
  285. return count;
  286. };
  287. int DeleteSelected()
  288. {
  289. int index;
  290. ASSERT(m_pBox);
  291. index = m_pBox->GetCurSel();
  292. // if there is any selected
  293. if( index != LB_ERR )
  294. {
  295. CString* pStr;
  296. pStr = (CString*)m_pBox->GetItemDataPtr(index);
  297. // remove the entry from the box
  298. m_pBox->DeleteString(index);
  299. // find the string in the String array
  300. int count = m_Strings.GetSize();
  301. for(int i = 0; i < count; i++)
  302. {
  303. if (m_Strings[i] == pStr)
  304. break;
  305. }
  306. ASSERT(i < count);
  307. // remove the string from the string array
  308. m_Strings.RemoveAt(i);
  309. index = i;
  310. delete pStr;
  311. }
  312. return index;
  313. };
  314. int AddString(CString* pStr) // the pStr needs to dynamically allocated
  315. {
  316. int index;
  317. ASSERT(m_pBox && pStr);
  318. index = m_pBox->AddString(*pStr);
  319. m_pBox->SetItemDataPtr(index, pStr);
  320. return m_Strings.Add(pStr);
  321. };
  322. int Select(int arrayindex) // the pStr needs to dynamically allocated
  323. {
  324. ASSERT(arrayindex < m_Strings.GetSize());
  325. return m_pBox->SelectString(0, *m_Strings[(INT_PTR)arrayindex]);
  326. };
  327. void Enable(BOOL b) // the pStr needs to dynamically allocated
  328. {
  329. ASSERT(m_pBox);
  330. m_pBox->EnableWindow(b);
  331. };
  332. int GetSelected() // it returns the index where the
  333. {
  334. int index;
  335. ASSERT(m_pBox);
  336. index = m_pBox->GetCurSel();
  337. // if there is any selected
  338. if( index != LB_ERR )
  339. {
  340. CString* pStr;
  341. pStr = (CString*)m_pBox->GetItemDataPtr(index);
  342. // find the string in the String array
  343. int count = (int)m_Strings.GetSize();
  344. for(int i = 0; i < count; i++)
  345. {
  346. if (m_Strings[(INT_PTR)i] == pStr)
  347. break;
  348. }
  349. ASSERT(i < count);
  350. index = i;
  351. }
  352. return index;
  353. };
  354. CBox* m_pBox;
  355. protected:
  356. int m_id;
  357. CStrArray& m_Strings;
  358. CDialog* m_pDialog;
  359. };
  360. // class to take care of ip address
  361. class CIPAddress
  362. {
  363. public:
  364. CIPAddress(DWORD address = 0)
  365. {
  366. m_dwAddress = address;
  367. };
  368. // CIPAddress(const CString& strAddress){};
  369. operator DWORD() { return m_dwAddress;};
  370. operator CString()
  371. {
  372. CString str;
  373. WORD hi = HIWORD(m_dwAddress);
  374. WORD lo = LOWORD(m_dwAddress);
  375. str.Format(_T("%-d.%-d.%-d.%d"), HIBYTE(hi), LOBYTE(hi), HIBYTE(lo), LOBYTE(lo));
  376. return str;
  377. };
  378. DWORD m_dwAddress;
  379. };
  380. // format of framedroute: mask dest metric ; mask and dest in dot format
  381. class CFramedRoute
  382. {
  383. public:
  384. void SetRoute(CString* pRoute)
  385. {
  386. m_pStrRoute = pRoute;
  387. m_pStrRoute->TrimLeft();
  388. m_pStrRoute->TrimRight();
  389. m_iFirstSpace = m_pStrRoute->Find(_T(' ')) ;
  390. m_iLastSpace = m_pStrRoute->ReverseFind(_T(' ')) ;
  391. };
  392. CString& GetDest(CString& dest) const
  393. {
  394. int i = m_pStrRoute->Find(_T('/'));
  395. if(i == -1)
  396. i = m_iFirstSpace;
  397. dest = m_pStrRoute->Left(i);
  398. return dest;
  399. };
  400. CString& GetNextStop(CString& nextStop) const
  401. {
  402. nextStop = m_pStrRoute->Mid(m_iFirstSpace + 1, m_iLastSpace - m_iFirstSpace -1 );
  403. return nextStop;
  404. };
  405. CString& GetPrefixLength(CString& prefixLength) const
  406. {
  407. int i = m_pStrRoute->Find(_T('/'));
  408. if( i != -1)
  409. {
  410. prefixLength = m_pStrRoute->Mid(i + 1, m_iFirstSpace - i - 1);
  411. }
  412. else
  413. prefixLength = _T("");
  414. return prefixLength;
  415. };
  416. CString& GetMask(CString& mask) const
  417. {
  418. int i = m_pStrRoute->Find(_T('/'));
  419. DWORD dwMask = 0;
  420. DWORD dwBit = 0x80000000;
  421. DWORD dwPrefixLen;
  422. if( i != -1)
  423. {
  424. mask = m_pStrRoute->Mid(i + 1, m_iFirstSpace - i - 1);
  425. dwPrefixLen = _ttol((LPCTSTR)mask);
  426. while(dwPrefixLen--)
  427. {
  428. dwMask |= dwBit;
  429. dwBit >>= 1;
  430. }
  431. }
  432. else
  433. dwMask = 0;
  434. WORD hi1, lo1;
  435. hi1 = HIWORD(dwMask); lo1 = LOWORD(dwMask);
  436. mask.Format(_T("%-d.%-d.%d.%d"),
  437. HIBYTE(hi1), LOBYTE(hi1), HIBYTE(lo1), LOBYTE(lo1));
  438. return mask;
  439. };
  440. CString& GetMetric(CString& metric) const
  441. {
  442. metric = m_pStrRoute->Mid(m_iLastSpace + 1);
  443. return metric;
  444. };
  445. protected:
  446. // WARNING: the string is not copied, so user need to make sure the origin is valid
  447. CString* m_pStrRoute;
  448. int m_iFirstSpace;
  449. int m_iLastSpace;
  450. };
  451. class CStrParser
  452. {
  453. public:
  454. CStrParser(LPCTSTR pStr = NULL) : m_pStr(pStr) { }
  455. // get the current string position
  456. LPCTSTR GetStr() const { return m_pStr;};
  457. void SetStr(LPCTSTR pStr) { m_pStr = pStr;};
  458. // find a unsigned interger and return it, -1 == not found
  459. int GetUINT()
  460. {
  461. UINT ret = 0;
  462. while((*m_pStr < _T('0') || *m_pStr > _T('9')) && *m_pStr != _T('\0'))
  463. m_pStr++;
  464. if(*m_pStr == _T('\0')) return -1;
  465. while(*m_pStr >= _T('0') && *m_pStr <= _T('9'))
  466. {
  467. ret = ret * 10 + *m_pStr - _T('0');
  468. m_pStr++;
  469. }
  470. return ret;
  471. };
  472. // find c and skip it
  473. int GotoAfter(TCHAR c)
  474. {
  475. int ret = 0;
  476. // go until find c or end of string
  477. while(*m_pStr != c && *m_pStr != _T('\0'))
  478. m_pStr++, ret++;
  479. // if found
  480. if(*m_pStr == c)
  481. m_pStr++, ret++;
  482. else
  483. ret = -1;
  484. return ret;
  485. };
  486. // skip blank characters space tab
  487. void SkipBlank()
  488. {
  489. while((*m_pStr == _T(' ') || *m_pStr == _T('\t')) && *m_pStr != _T('\0'))
  490. m_pStr++;
  491. };
  492. // check to see if the first character is '0'-'6' for Monday(0) to Sunday(6)
  493. int DayOfWeek() {
  494. SkipBlank();
  495. if(*m_pStr >= _T('0') && *m_pStr <= _T('6'))
  496. return (*m_pStr++ - _T('0'));
  497. else
  498. return -1; // not day of week
  499. /* Mon Tue ... is not localizable
  500. static CString m_strDaysList = _T("MON TUE WED THU FRI SAT SUN");
  501. _strTemp = _T(" ");
  502. for(int i = 0; i < 3 && *m_pStr != _T('\0'); i++)
  503. {
  504. _strTemp.SetAt(i, *m_pStr);
  505. m_pStr++;
  506. }
  507. _strTemp.MakeUpper();
  508. i = m_strDaysList.Find(_strTemp);
  509. if(i == -1 || (i % 4) || ( i/4 > 6))
  510. return -1; // not any or wrong value
  511. return i/4;
  512. */
  513. };
  514. protected:
  515. LPCTSTR m_pStr;
  516. private:
  517. CString _strTemp;
  518. };
  519. void ReportError(HRESULT hr, int nStr, HWND hWnd);
  520. // number of characters
  521. void AFXAPI DDV_MinChars(CDataExchange* pDX, CString const& value, int nChars);
  522. /*!--------------------------------------------------------------------------
  523. IsStandaloneServer
  524. Returns S_OK if the machine name passed in is a standalone server,
  525. or if pszMachineName is S_FALSE.
  526. Returns S_FALSE otherwise.
  527. Author: WeiJiang
  528. ---------------------------------------------------------------------------*/
  529. HRESULT HrIsStandaloneServer(LPCTSTR pszMachineName);
  530. HRESULT HrIsNTServer(LPCWSTR pMachineName);
  531. class CBSTR
  532. {
  533. public:
  534. CBSTR() : m_bstr(NULL) {};
  535. CBSTR(LPCSTR cstr) : m_bstr(NULL)
  536. {
  537. USES_CONVERSION;
  538. m_bstr = A2BSTR(cstr);
  539. };
  540. CBSTR(LPCWSTR wstr) : m_bstr(NULL)
  541. {
  542. USES_CONVERSION;
  543. m_bstr = W2BSTR(wstr);
  544. };
  545. BSTR AssignBlob(const char* pByte, UINT size)
  546. {
  547. SysFreeString(m_bstr);
  548. m_bstr = SysAllocStringByteLen(pByte, size);
  549. return m_bstr;
  550. };
  551. BSTR AssignBSTR(const BSTR bstr)
  552. {
  553. return AssignBlob((const char *)bstr, SysStringByteLen(bstr));
  554. };
  555. UINT ByteLen()
  556. {
  557. UINT n = 0;
  558. if(m_bstr)
  559. n = SysStringByteLen(m_bstr);
  560. return n;
  561. };
  562. operator BSTR() { return m_bstr;};
  563. void Clean()
  564. {
  565. SysFreeString(m_bstr);
  566. };
  567. ~CBSTR()
  568. {
  569. Clean();
  570. };
  571. BSTR m_bstr;
  572. };
  573. template<class T> class CNetDataPtr
  574. {
  575. public:
  576. CNetDataPtr():m_pData(NULL){};
  577. ~CNetDataPtr()
  578. {
  579. NetApiBufferFree(m_pData);
  580. };
  581. T** operator&()
  582. {
  583. return &m_pData;
  584. };
  585. operator T*()
  586. {
  587. return m_pData;
  588. };
  589. T* operator ->()
  590. {
  591. return m_pData;
  592. };
  593. T* m_pData;
  594. };
  595. /*!--------------------------------------------------------------------------
  596. EnableChildControls
  597. Use this function to enable/disable/hide/show all child controls
  598. on a page (actually it will work with any child windows, the
  599. parent does not have to be a property page).
  600. Author: KennT
  601. ---------------------------------------------------------------------------*/
  602. HRESULT EnableChildControls(HWND hWnd, DWORD dwFlags);
  603. #define PROPPAGE_CHILD_SHOW 0x00000001
  604. #define PROPPAGE_CHILD_HIDE 0x00000002
  605. #define PROPPAGE_CHILD_ENABLE 0x00000004
  606. #define PROPPAGE_CHILD_DISABLE 0x00000008
  607. /*---------------------------------------------------------------------------
  608. Struct: AuthProviderData
  609. This structure is used to hold information for Authentication AND
  610. Accounting providers.
  611. ---------------------------------------------------------------------------*/
  612. struct AuthProviderData
  613. {
  614. // The following fields will hold data for ALL auth/acct/EAP providers
  615. CString m_stTitle;
  616. CString m_stConfigCLSID; // CLSID for config object
  617. CString m_stProviderTypeGUID; // GUID for the provider type
  618. // These fields are used by auth/acct providers.
  619. CString m_stGuid; // the identifying guid
  620. // This flag is used for EAP providers
  621. CString m_stKey; // name of registry key (for this provider)
  622. BOOL m_fSupportsEncryption; // used by EAP provider data
  623. DWORD m_dwStandaloneSupported;
  624. };
  625. typedef CArray<AuthProviderData, AuthProviderData&> AuthProviderArray;
  626. HRESULT GetEapProviders(LPCTSTR machineName, AuthProviderArray *pProvList);
  627. #endif