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.

875 lines
19 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: K K R E G . C P P
  7. //
  8. // Contents: Windows NT Registry Access Class
  9. //
  10. // Notes:
  11. //
  12. // Author: kumarp 14 April 97 (09:22:00 pm)
  13. //
  14. // Notes:
  15. // kumarp 1/16/97 most of the code in this file was originally in
  16. // net\ui\rhino\common\classes\common.h
  17. // extracted only that portion related to CRegKey & related classes
  18. // kumarp 3/27/97 the original code used MFC. converted the entire code
  19. // to make it use STL
  20. //----------------------------------------------------------------------------
  21. #include "pch.h"
  22. #pragma hdrstop
  23. #include "kkreg.h"
  24. #include "kkstl.h"
  25. #include "kkutils.h"
  26. #include "nceh.h"
  27. #include "ncreg.h"
  28. HRESULT HrGetRegErrorForTrace(LONG err)
  29. {
  30. HRESULT hr = ((err == ERROR_FILE_NOT_FOUND) ||
  31. (err == ERROR_NO_MORE_ITEMS))
  32. ? S_OK : HRESULT_FROM_WIN32(err);
  33. return hr;
  34. }
  35. #define TraceRegFunctionError(e) TraceFunctionError(HrGetRegErrorForTrace(e))
  36. //+---------------------------------------------------------------------------
  37. //
  38. // Member: CORegKey::CORegKey
  39. //
  40. // Purpose: constructor for an existing key
  41. //
  42. // Arguments: none
  43. //
  44. // Author: kumarp 12 April 97 (05:53:03 pm)
  45. //
  46. // Notes:
  47. //
  48. CORegKey::CORegKey (HKEY hKeyBase,
  49. PCWSTR pchSubKey,
  50. REGSAM regSam,
  51. PCWSTR pchServerName )
  52. : m_hKey( NULL ),
  53. m_dwDisposition( 0 ),
  54. m_fInherit(FALSE)
  55. {
  56. DefineFunctionName("CORegKey::CORegKey(HKEY hKeyBase, PCWSTR pchSubKey, )");
  57. HKEY hkBase = NULL ;
  58. LONG err = 0 ;
  59. if ( pchServerName )
  60. {
  61. // This is a remote connection.
  62. if ( err = ::RegConnectRegistry( (PWSTR) pchServerName,
  63. hKeyBase, & hkBase ) )
  64. {
  65. TraceLastWin32Error("RegConnectRegistry failed");
  66. hkBase = NULL ;
  67. }
  68. }
  69. else
  70. {
  71. hkBase = hKeyBase ;
  72. }
  73. if ( err == 0 )
  74. {
  75. if ( pchSubKey )
  76. {
  77. err = ::RegOpenKeyEx( hkBase, pchSubKey, 0, regSam, & m_hKey ) ;
  78. /*
  79. if (err)
  80. {
  81. TraceLastWin32Error("RegOpenKeyEx failed");
  82. }
  83. */
  84. }
  85. else
  86. {
  87. m_hKey = hkBase ;
  88. hkBase = NULL ;
  89. m_fInherit = TRUE;
  90. }
  91. if ( hkBase && hkBase != hKeyBase )
  92. {
  93. ::RegCloseKey( hkBase ) ;
  94. }
  95. }
  96. if ( err )
  97. {
  98. // ReportError( err ) ;
  99. m_hKey = NULL ;
  100. }
  101. TraceRegFunctionError(err);
  102. }
  103. //+---------------------------------------------------------------------------
  104. //
  105. // Member: CORegKey::CORegKey
  106. //
  107. // Purpose: constructor for creating a new key
  108. //
  109. // Arguments: none
  110. //
  111. // Author: kumarp 12 April 97 (05:53:03 pm)
  112. //
  113. // Notes:
  114. //
  115. CORegKey::CORegKey (PCWSTR pchSubKey,
  116. HKEY hKeyBase,
  117. DWORD dwOptions,
  118. REGSAM regSam,
  119. LPSECURITY_ATTRIBUTES pSecAttr,
  120. PCWSTR pchServerName)
  121. : m_hKey( NULL ),
  122. m_dwDisposition( 0 ),
  123. m_fInherit(FALSE)
  124. {
  125. DefineFunctionName("CORegKey::CORegKey(PCWSTR pchSubKey, HKEY hKeyBase, )");
  126. HKEY hkBase = NULL ;
  127. LONG err = 0;
  128. if ( pchServerName )
  129. {
  130. // This is a remote connection.
  131. if ( err = ::RegConnectRegistry( (PWSTR) pchServerName,
  132. hKeyBase, & hkBase ) )
  133. {
  134. hkBase = NULL ;
  135. TraceLastWin32Error("RegConnectRegistry failed");
  136. }
  137. hkBase = NULL ;
  138. }
  139. else
  140. {
  141. hkBase = hKeyBase ;
  142. }
  143. if (err == 0)
  144. {
  145. PCWSTR szEmpty = L"" ;
  146. err = ::RegCreateKeyEx( hkBase, pchSubKey,
  147. 0, (PWSTR) szEmpty,
  148. dwOptions, regSam, pSecAttr,
  149. & m_hKey,
  150. & m_dwDisposition ) ;
  151. }
  152. if ( err )
  153. {
  154. TraceLastWin32Error("RegCreateKeyEx failed");
  155. m_hKey = NULL ;
  156. }
  157. TraceRegFunctionError(err);
  158. }
  159. CORegKey::~CORegKey ()
  160. {
  161. if ( m_hKey && !m_fInherit)
  162. {
  163. ::RegCloseKey( m_hKey ) ;
  164. }
  165. }
  166. // Prepare to read a value by finding the value's size.
  167. LONG CORegKey::PrepareValue (PCWSTR pchValueName,
  168. DWORD * pdwType,
  169. DWORD * pcbSize,
  170. BYTE ** ppbData )
  171. {
  172. DefineFunctionName("CORegKey::PrepareValue");
  173. LONG err = 0 ;
  174. BYTE chDummy[2] ;
  175. DWORD cbData = 0 ;
  176. do
  177. {
  178. // Set the resulting buffer size to 0.
  179. *pcbSize = 0 ;
  180. *ppbData = NULL ;
  181. err = ::RegQueryValueExW( *this,
  182. (PWSTR) pchValueName,
  183. 0, pdwType,
  184. chDummy, & cbData ) ;
  185. // The only error we should get here is ERROR_MORE_DATA, but
  186. // we may get no error if the value has no data.
  187. if ( err == 0 )
  188. {
  189. cbData = sizeof (LONG) ; // Just a fudgy number
  190. }
  191. else
  192. if ( err != ERROR_MORE_DATA )
  193. break ;
  194. // Allocate a buffer large enough for the data.
  195. *ppbData = new BYTE [ (*pcbSize = cbData) + sizeof (LONG) ] ;
  196. if ( *ppbData == NULL )
  197. {
  198. err = ERROR_NOT_ENOUGH_MEMORY ;
  199. break ;
  200. }
  201. // Now that have a buffer, re-fetch the value.
  202. err = ::RegQueryValueExW( *this,
  203. (PWSTR) pchValueName,
  204. 0, pdwType,
  205. *ppbData, pcbSize ) ;
  206. } while ( FALSE ) ;
  207. if ( err )
  208. {
  209. delete [] *ppbData ;
  210. }
  211. TraceRegFunctionError(err);
  212. return err ;
  213. }
  214. // Overloaded value query members; each returns ERROR_INVALID_PARAMETER
  215. // if data exists but not in correct form to deliver into result object.
  216. LONG CORegKey::QueryValue ( PCWSTR pchValueName, tstring& strResult )
  217. {
  218. DefineFunctionName("CORegKey::QueryValue(tstring& strResult)");
  219. LONG err = 0 ;
  220. DWORD dwType ;
  221. DWORD cbData ;
  222. BYTE * pabData = NULL ;
  223. // strResult.remove();
  224. strResult = c_szEmpty;
  225. do
  226. {
  227. if ( err = PrepareValue( pchValueName, & dwType, & cbData, & pabData ) )
  228. break ;
  229. if (( dwType != REG_SZ ) && (dwType != REG_EXPAND_SZ))
  230. {
  231. err = ERROR_INVALID_PARAMETER ;
  232. break ;
  233. }
  234. // Guarantee that the data looks like a string
  235. pabData[cbData] = 0 ;
  236. NC_TRY
  237. {
  238. strResult = (PWSTR) pabData ;
  239. }
  240. NC_CATCH_ALL
  241. {
  242. err = ERROR_NOT_ENOUGH_MEMORY ;
  243. }
  244. }
  245. while ( FALSE ) ;
  246. delete [] pabData ;
  247. TraceRegFunctionError(err);
  248. return err ;
  249. }
  250. LONG CORegKey::QueryValue ( PCWSTR pchValueName, TStringList& strList )
  251. {
  252. DefineFunctionName("CORegKey::QueryValue(TStringList& strList)");
  253. LONG err = 0 ;
  254. DWORD dwType ;
  255. DWORD cbData ;
  256. BYTE * pabData = NULL ;
  257. PWSTR pbTemp, pbTempLimit ;
  258. EraseAndDeleteAll(&strList);
  259. do
  260. {
  261. if ( err = PrepareValue( pchValueName, & dwType, & cbData, & pabData ) )
  262. break ;
  263. if ( dwType != REG_MULTI_SZ )
  264. {
  265. err = ERROR_INVALID_PARAMETER ;
  266. break ;
  267. }
  268. // Guarantee that the trailing data looks like a string
  269. pabData[cbData] = 0 ;
  270. pbTemp = (PWSTR) pabData ;
  271. //kumarp: changed the following because it gives wrong results for UNICODE
  272. // pbTempLimit = & pbTemp[cbData] ;
  273. pbTempLimit = & pbTemp[(cbData / sizeof(WCHAR))-1] ;
  274. // Catch exceptions trying to build the list
  275. NC_TRY
  276. {
  277. for ( ; pbTemp < pbTempLimit ; )
  278. {
  279. // Raid 237766
  280. if (pbTemp && wcslen(pbTemp))
  281. {
  282. strList.insert(strList.end(), new tstring(pbTemp) ) ;
  283. }
  284. pbTemp += wcslen( pbTemp ) + 1 ;
  285. }
  286. }
  287. NC_CATCH_ALL
  288. {
  289. err = ERROR_NOT_ENOUGH_MEMORY ;
  290. }
  291. }
  292. while ( FALSE ) ;
  293. delete [] pabData ;
  294. TraceRegFunctionError(err);
  295. return err ;
  296. }
  297. LONG CORegKey::QueryValue ( PCWSTR pchValueName, DWORD& dwResult )
  298. {
  299. DefineFunctionName("CORegKey::QueryValue(DWORD& dwResult)");
  300. LONG err = 0;
  301. DWORD dwData;
  302. if (m_hKey && (S_OK == HrRegQueryDword(m_hKey, pchValueName, &dwData)))
  303. {
  304. dwResult = dwData;
  305. }
  306. else
  307. {
  308. err = ERROR_FILE_NOT_FOUND;
  309. dwResult = -1;
  310. }
  311. TraceRegFunctionError(err);
  312. return err ;
  313. }
  314. LONG CORegKey::QueryValue ( PCWSTR pchValueName, TByteArray& abResult )
  315. {
  316. DefineFunctionName("CORegKey::QueryValue(TByteArray& abResult)");
  317. LONG err = 0 ;
  318. DWORD dwType ;
  319. DWORD cbData ;
  320. BYTE * pabData = NULL ;
  321. do
  322. {
  323. if ( err = PrepareValue( pchValueName, & dwType, & cbData, & pabData ) )
  324. break ;
  325. if ( dwType != REG_BINARY )
  326. {
  327. err = ERROR_INVALID_PARAMETER ;
  328. break ;
  329. }
  330. // Catch exceptions trying to grow the result array
  331. NC_TRY
  332. {
  333. abResult.reserve( cbData ) ;
  334. }
  335. NC_CATCH_ALL
  336. {
  337. err = ERROR_NOT_ENOUGH_MEMORY ;
  338. }
  339. if ( err )
  340. break ;
  341. // Move the data to the result array.
  342. for ( DWORD i = 0 ; i < cbData ; i++ )
  343. {
  344. // abResult[i] = pabData[i] ;
  345. abResult.push_back(pabData[i]) ;
  346. }
  347. }
  348. while ( FALSE ) ;
  349. delete [] pabData ;
  350. TraceRegFunctionError(err);
  351. return err ;
  352. }
  353. LONG CORegKey::QueryValue ( PCWSTR pchValueName, void* pvResult, DWORD cbSize )
  354. {
  355. DefineFunctionName("CORegKey::QueryValue(void* pvResult, DWORD cbSize)");
  356. LONG err = 0 ;
  357. DWORD dwType ;
  358. DWORD cbData ;
  359. BYTE * pabData = NULL ;
  360. do
  361. {
  362. if ( err = PrepareValue( pchValueName, & dwType, & cbData, & pabData ) )
  363. break ;
  364. if ( dwType != REG_BINARY )
  365. {
  366. err = ERROR_INVALID_PARAMETER ;
  367. break ;
  368. }
  369. if ( cbSize < cbData )
  370. {
  371. err = ERROR_MORE_DATA;
  372. break;
  373. }
  374. ::memcpy(pvResult, pabData, cbData);
  375. }
  376. while ( FALSE ) ;
  377. delete [] pabData ;
  378. TraceRegFunctionError(err);
  379. return err ;
  380. }
  381. // Overloaded value setting members.
  382. LONG CORegKey::SetValue ( PCWSTR pchValueName, tstring& strResult )
  383. {
  384. DefineFunctionName("CORegKey::SetValue(tstring& strResult)");
  385. LONG err = 0;
  386. err = ::RegSetValueEx( *this,
  387. pchValueName,
  388. 0,
  389. REG_SZ,
  390. (const BYTE *) strResult.c_str(),
  391. CbOfSzAndTerm (strResult.c_str())) ;
  392. TraceRegFunctionError(err);
  393. return err ;
  394. }
  395. // Overloaded value setting members.
  396. LONG CORegKey::SetValue ( PCWSTR pchValueName, tstring& strResult ,
  397. BOOL fRegExpand)
  398. {
  399. LONG err = 0;
  400. DWORD dwType = fRegExpand ? REG_EXPAND_SZ : REG_SZ;
  401. err = ::RegSetValueEx( *this,
  402. pchValueName,
  403. 0,
  404. dwType,
  405. (const BYTE *) strResult.c_str(),
  406. CbOfSzAndTerm (strResult.c_str()));
  407. return err ;
  408. }
  409. LONG CORegKey::SetValue ( PCWSTR pchValueName, TStringList& strList )
  410. {
  411. DefineFunctionName("CORegKey::SetValue(TStringList& strList)");
  412. LONG err = 0;
  413. DWORD cbSize ;
  414. BYTE * pbData = NULL ;
  415. err = FlattenValue( strList, & cbSize, & pbData ) ;
  416. if ( err == 0 )
  417. {
  418. err = ::RegSetValueEx( *this,
  419. pchValueName,
  420. 0,
  421. REG_MULTI_SZ,
  422. pbData,
  423. cbSize ) ;
  424. }
  425. delete pbData ;
  426. TraceRegFunctionError(err);
  427. return err ;
  428. }
  429. LONG CORegKey::SetValue ( PCWSTR pchValueName, DWORD& dwResult )
  430. {
  431. DefineFunctionName("CORegKey::SetValue(DWORD& dwResult)");
  432. LONG err = 0;
  433. err = ::RegSetValueEx( *this,
  434. pchValueName,
  435. 0,
  436. REG_DWORD,
  437. (const BYTE *) & dwResult,
  438. sizeof dwResult ) ;
  439. TraceRegFunctionError(err);
  440. return err ;
  441. }
  442. LONG CORegKey::SetValue ( PCWSTR pchValueName, TByteArray& abResult )
  443. {
  444. DefineFunctionName("CORegKey::SetValue(TByteArray& abResult)");
  445. LONG err = 0;
  446. DWORD cbSize ;
  447. BYTE * pbData = NULL ;
  448. err = FlattenValue( abResult, & cbSize, & pbData ) ;
  449. if ( err == 0 )
  450. {
  451. err = ::RegSetValueEx( *this,
  452. pchValueName,
  453. 0,
  454. REG_BINARY,
  455. pbData,
  456. cbSize ) ;
  457. }
  458. delete pbData ;
  459. TraceRegFunctionError(err);
  460. return err ;
  461. }
  462. LONG CORegKey::SetValue ( PCWSTR pchValueName, void* pvResult, DWORD cbSize )
  463. {
  464. DefineFunctionName("CORegKey::SetValue(void* pvResult, DWORD cbSize)");
  465. LONG err = 0;
  466. err = ::RegSetValueEx( *this,
  467. pchValueName,
  468. 0,
  469. REG_BINARY,
  470. (const BYTE *)pvResult,
  471. cbSize ) ;
  472. TraceRegFunctionError(err);
  473. return err ;
  474. }
  475. LONG CORegKey::DeleteValue ( PCWSTR pchValueName )
  476. {
  477. DefineFunctionName("CORegKey::DeleteValue");
  478. LONG err = ::RegDeleteValue(m_hKey, pchValueName);
  479. TraceRegFunctionError(err);
  480. return err;
  481. }
  482. LONG CORegKey::FlattenValue (TStringList & strList,
  483. DWORD * pcbSize,
  484. BYTE ** ppbData )
  485. {
  486. Assert(pcbSize);
  487. Assert(ppbData);
  488. DefineFunctionName("CORegKey::FlattenValue(TStringList)");
  489. LONG err = ERROR_NOT_ENOUGH_MEMORY ;
  490. TStringListIter pos ;
  491. tstring* pstr ;
  492. int cbTotal = 0 ;
  493. *ppbData = NULL;
  494. // Walk the list accumulating sizes
  495. for ( pos = strList.begin() ;
  496. pos != strList.end() && (pstr = (tstring *) *pos++); )
  497. {
  498. cbTotal += CbOfSzAndTerm (pstr->c_str());
  499. }
  500. // Allocate and fill a temporary buffer
  501. if (*pcbSize = cbTotal)
  502. {
  503. BYTE * pbData = new BYTE[ *pcbSize ] ;
  504. if(pbData)
  505. {
  506. // Populate the buffer with the strings.
  507. for ( pos = strList.begin() ;
  508. pos != strList.end() && (pstr = (tstring *) *pos++); )
  509. {
  510. int cb = CbOfSzAndTerm (pstr->c_str());
  511. ::memcpy( pbData, pstr->c_str(), cb ) ;
  512. pbData += cb ;
  513. }
  514. err = NOERROR;
  515. *ppbData = pbData;
  516. }
  517. }
  518. TraceRegFunctionError(err);
  519. return err ;
  520. }
  521. LONG CORegKey::FlattenValue (TByteArray & abData,
  522. DWORD * pcbSize,
  523. BYTE ** ppbData )
  524. {
  525. Assert(pcbSize);
  526. Assert(ppbData);
  527. DefineFunctionName("CORegKey::FlattenValue(TByteArray)");
  528. LONG err = ERROR_NOT_ENOUGH_MEMORY ;
  529. DWORD i ;
  530. *ppbData = NULL;
  531. // Allocate and fill a temporary buffer
  532. if (*pcbSize = abData.size())
  533. {
  534. *ppbData = new BYTE[*pcbSize] ;
  535. if(*ppbData)
  536. {
  537. for ( i = 0 ; i < *pcbSize ; i++ )
  538. {
  539. (*ppbData)[i] = abData[i] ;
  540. }
  541. }
  542. err = NOERROR;
  543. }
  544. TraceRegFunctionError(err);
  545. return err ;
  546. }
  547. LONG CORegKey::QueryKeyInfo ( CORegKEY_KEY_INFO * pRegKeyInfo )
  548. {
  549. DefineFunctionName("CORegKey::QueryKeyInfo");
  550. LONG err = 0 ;
  551. pRegKeyInfo->dwClassNameSize = sizeof pRegKeyInfo->chBuff - 1 ;
  552. err = ::RegQueryInfoKeyW( *this,
  553. pRegKeyInfo->chBuff,
  554. & pRegKeyInfo->dwClassNameSize,
  555. NULL,
  556. & pRegKeyInfo->dwNumSubKeys,
  557. & pRegKeyInfo->dwMaxSubKey,
  558. & pRegKeyInfo->dwMaxClass,
  559. & pRegKeyInfo->dwMaxValues,
  560. & pRegKeyInfo->dwMaxValueName,
  561. & pRegKeyInfo->dwMaxValueData,
  562. & pRegKeyInfo->dwSecDesc,
  563. & pRegKeyInfo->ftKey ) ;
  564. TraceRegFunctionError(err);
  565. return err ;
  566. }
  567. CORegKeyIter::CORegKeyIter ( CORegKey & regKey )
  568. : m_rk_iter( regKey ),
  569. m_p_buffer( NULL ),
  570. m_cb_buffer( 0 )
  571. {
  572. DefineFunctionName("CORegKeyIter::CORegKeyIter");
  573. LONG err = 0 ;
  574. CORegKey::CORegKEY_KEY_INFO regKeyInfo ;
  575. Reset() ;
  576. err = regKey.QueryKeyInfo( & regKeyInfo ) ;
  577. if ( err == 0 )
  578. {
  579. NC_TRY
  580. {
  581. m_cb_buffer = regKeyInfo.dwMaxSubKey + sizeof (DWORD) ;
  582. m_p_buffer = new WCHAR [ m_cb_buffer ] ;
  583. }
  584. NC_CATCH_ALL
  585. {
  586. err = ERROR_NOT_ENOUGH_MEMORY ;
  587. }
  588. }
  589. TraceRegFunctionError(err);
  590. }
  591. CORegKeyIter::~CORegKeyIter ()
  592. {
  593. delete [] m_p_buffer ;
  594. }
  595. LONG CORegKeyIter::Next ( tstring * pstrName )
  596. {
  597. DefineFunctionName("CORegKeyIter::Next");
  598. LONG err = 0;
  599. FILETIME ftDummy ;
  600. DWORD dwNameSize = m_cb_buffer ;
  601. err = ::RegEnumKeyEx( m_rk_iter,
  602. m_dw_index,
  603. m_p_buffer,
  604. & dwNameSize,
  605. NULL,
  606. NULL,
  607. NULL,
  608. & ftDummy ) ;
  609. if ( err == 0 )
  610. {
  611. m_dw_index++ ;
  612. NC_TRY
  613. {
  614. *pstrName = m_p_buffer ;
  615. }
  616. NC_CATCH_ALL
  617. {
  618. err = ERROR_NOT_ENOUGH_MEMORY ;
  619. }
  620. }
  621. TraceRegFunctionError(err);
  622. return err ;
  623. }
  624. CORegValueIter::CORegValueIter ( CORegKey & regKey )
  625. : m_rk_iter( regKey ),
  626. m_p_buffer( NULL ),
  627. m_cb_buffer( 0 )
  628. {
  629. DefineFunctionName("CORegValueIter::CORegValueIter");
  630. LONG err = 0 ;
  631. CORegKey::CORegKEY_KEY_INFO regKeyInfo ;
  632. Reset() ;
  633. err = regKey.QueryKeyInfo( & regKeyInfo ) ;
  634. if ( err == 0 )
  635. {
  636. NC_TRY
  637. {
  638. m_cb_buffer = regKeyInfo.dwMaxValueName + sizeof (DWORD) ;
  639. m_p_buffer = new WCHAR [ m_cb_buffer ] ;
  640. }
  641. NC_CATCH_ALL
  642. {
  643. err = ERROR_NOT_ENOUGH_MEMORY ;
  644. }
  645. }
  646. TraceRegFunctionError(err);
  647. }
  648. CORegValueIter::~CORegValueIter ()
  649. {
  650. delete [] m_p_buffer ;
  651. }
  652. LONG CORegValueIter::Next ( tstring * pstrName, DWORD * pdwType )
  653. {
  654. DefineFunctionName("CORegValueIter::Next");
  655. LONG err = 0 ;
  656. DWORD dwNameLength = m_cb_buffer ;
  657. err = ::RegEnumValue( m_rk_iter,
  658. m_dw_index,
  659. m_p_buffer,
  660. & dwNameLength,
  661. NULL,
  662. pdwType,
  663. NULL,
  664. NULL ) ;
  665. if ( err == 0 )
  666. {
  667. m_dw_index++ ;
  668. NC_TRY
  669. {
  670. *pstrName = m_p_buffer ;
  671. }
  672. NC_CATCH_ALL
  673. {
  674. err = ERROR_NOT_ENOUGH_MEMORY ;
  675. }
  676. }
  677. TraceRegFunctionError(err);
  678. return err ;
  679. }