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.

1251 lines
28 KiB

  1. /*++
  2. Copyright (C) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. utils.cpp
  5. Abstract:
  6. This module implements some utilities classes
  7. Author:
  8. William Hsieh (williamh) created
  9. Revision History:
  10. --*/
  11. #include "devmgr.h"
  12. const TCHAR* const DEVMGR_DATAWINDOW_CASS_NAME = TEXT("DevMgrDataWindowClass");
  13. //
  14. // CPropSheetData implementation
  15. //
  16. // Every device or class has a CPropSheetData as a member.
  17. // When m_hWnd contains a valid window handle, it indicates the device/class
  18. // has a active property sheet. This helps us to do this:
  19. // (1). We are sure that there is only one property sheet can be created
  20. // for the device/class at time in a single console no matter how many
  21. // IComponents(snapins, windows) are running in the same console.
  22. // For example, when users asks for the properties for the device/class
  23. // we can bring the active one to the foreground without creating a
  24. // new one.
  25. // (2). We can warn the user that a removal of the device is not allowed
  26. // when the device has an active property sheet.
  27. // (3). We can warn the user that there are property sheets active
  28. // when a "refresh" is requsted.
  29. CPropSheetData::CPropSheetData()
  30. {
  31. memset(&m_psh, 0, sizeof(m_psh));
  32. m_MaxPages = 0;
  33. m_lConsoleHandle = 0;
  34. m_hWnd = NULL;
  35. }
  36. // This function creates(or initialize) the propery sheet data header.
  37. //
  38. // INPUT: hInst -- the module instance handle
  39. // hwndParent -- parent window handle
  40. // MaxPages -- max pages allowed for this property sheet.
  41. // lConsoleHandle -- MMC property change notify handle.
  42. //
  43. // OUTPUT: TRUE if succeeded.
  44. // FALSE if failed(mostly, memory allocation error). GetLastError
  45. // will report the error code.
  46. //
  47. BOOL
  48. CPropSheetData::Create(
  49. HINSTANCE hInst,
  50. HWND hwndParent,
  51. UINT MaxPages,
  52. LONG_PTR lConsoleHandle
  53. )
  54. {
  55. // nobody should try to create the property sheet while it is
  56. // still alive.
  57. ASSERT (NULL == m_hWnd);
  58. if (MaxPages > 64 || NULL == hInst)
  59. {
  60. SetLastError(ERROR_INVALID_PARAMETER);
  61. return FALSE;
  62. }
  63. // if not page array is allocated or the existing
  64. // array is too small, allocate a new array.
  65. if (!m_psh.phpage || m_MaxPages < MaxPages)
  66. {
  67. if (m_MaxPages)
  68. {
  69. ASSERT(m_psh.phpage);
  70. delete [] m_psh.phpage;
  71. m_psh.phpage = NULL;
  72. }
  73. m_psh.phpage = new HPROPSHEETPAGE[MaxPages];
  74. m_MaxPages = MaxPages;
  75. }
  76. // initialize the header
  77. m_psh.nPages = 0;
  78. m_psh.dwSize = sizeof(m_psh);
  79. m_psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
  80. m_psh.hwndParent = hwndParent;
  81. m_psh.hInstance = hInst;
  82. m_psh.pszCaption = NULL;
  83. m_lConsoleHandle = lConsoleHandle;
  84. return TRUE;
  85. }
  86. // This function inserts the given HPROPSHEETPAGE to the
  87. // specific location.
  88. //
  89. // INPUT: hPage -- the page to be inserted.
  90. // Position -- the location to be inserted.
  91. // Position < 0, then append the page
  92. //
  93. // OUTPUT: TRUE if the page is inserted successfully.
  94. // FALSE if the page is not inserted. GetLastError will
  95. // return the error code.
  96. //
  97. BOOL
  98. CPropSheetData::InsertPage(
  99. HPROPSHEETPAGE hPage,
  100. int Position
  101. )
  102. {
  103. if (NULL == hPage || (Position > 0 && (UINT)Position >= m_MaxPages))
  104. {
  105. SetLastError(ERROR_INVALID_PARAMETER);
  106. return FALSE;
  107. }
  108. // make sure we have space for a new page.
  109. if (m_psh.nPages >= m_MaxPages)
  110. {
  111. SetLastError(ERROR_BUFFER_OVERFLOW);
  112. return FALSE;
  113. }
  114. if (Position < 0 || (UINT)Position >= m_psh.nPages)
  115. {
  116. // append the page. This also include the very first page.
  117. // Most pages are appened.
  118. m_psh.phpage[m_psh.nPages++] = hPage;
  119. }
  120. else
  121. {
  122. ASSERT(m_psh.nPages);
  123. // move the page around so that we
  124. // can insert the new page to the
  125. // specific location.
  126. // At this moment, we know we have space to accomodate the
  127. // new page(so we can assume that &m_psh.phpage[m_psh.nPage]
  128. // is valid. Also, we are here because there is at least one
  129. // pages in the array.
  130. for (int i = m_psh.nPages; i > Position; i--)
  131. m_psh.phpage[i] = m_psh.phpage[i - 1];
  132. m_psh.phpage[Position] = hPage;
  133. m_psh.nPages++;
  134. }
  135. return TRUE;
  136. }
  137. //
  138. // This function receives notification from its attached
  139. // property pages about their window(dialog) creation
  140. // It takes a chance to record the property sheet window handle
  141. // which we can use to dismiss the property sheet or bring it
  142. // to the foreground.
  143. // INPUT:
  144. // hWnd -- the property page's window handle
  145. //
  146. // OUTPUT:
  147. // NONE
  148. //
  149. void
  150. CPropSheetData::PageCreateNotify(HWND hWnd)
  151. {
  152. ASSERT(hWnd);
  153. hWnd = ::GetParent(hWnd);
  154. if (!m_hWnd)
  155. m_hWnd = hWnd;
  156. }
  157. //
  158. // This function receives notification from its attached
  159. // property pages about their window(dialog) destroy.
  160. // When all attached pages are gone, this function
  161. // reset its internal states and free memory allocation
  162. // WARNING!!!! Do not delete the object when the attached
  163. // window handle counts reaches 0 because we can be reused --
  164. // the reason we have a separate Create functions.
  165. //
  166. // INPUT:
  167. // hWnd -- the property page's window handle
  168. //
  169. // OUTPUT:
  170. // NONE
  171. //
  172. void
  173. CPropSheetData::PageDestroyNotify(HWND hWnd)
  174. {
  175. //
  176. m_hWnd = NULL;
  177. delete [] m_psh.phpage;
  178. m_psh.phpage = NULL;
  179. m_MaxPages = 0;
  180. memset(&m_psh, 0, sizeof(m_psh));
  181. if (m_lConsoleHandle)
  182. MMCFreeNotifyHandle(m_lConsoleHandle);
  183. m_lConsoleHandle = 0;
  184. if (!m_listProvider.IsEmpty())
  185. {
  186. POSITION pos = m_listProvider.GetHeadPosition();
  187. while (NULL != pos)
  188. {
  189. delete m_listProvider.GetNext(pos);
  190. }
  191. m_listProvider.RemoveAll();
  192. }
  193. }
  194. CPropSheetData::~CPropSheetData()
  195. {
  196. if (m_lConsoleHandle)
  197. MMCFreeNotifyHandle(m_lConsoleHandle);
  198. if (!m_listProvider.IsEmpty())
  199. {
  200. POSITION pos = m_listProvider.GetHeadPosition();
  201. while (NULL != pos)
  202. {
  203. delete m_listProvider.GetNext(pos);
  204. }
  205. m_listProvider.RemoveAll();
  206. }
  207. if (m_psh.phpage)
  208. delete [] m_psh.phpage;
  209. }
  210. BOOL
  211. CPropSheetData::PropertyChangeNotify(
  212. long lParam
  213. )
  214. {
  215. if (m_lConsoleHandle)
  216. {
  217. MMCPropertyChangeNotify(m_lConsoleHandle, lParam);
  218. return TRUE;
  219. }
  220. return FALSE;
  221. }
  222. //
  223. // CDialog implementation
  224. //
  225. INT_PTR CALLBACK
  226. CDialog::DialogWndProc(
  227. HWND hDlg,
  228. UINT uMsg,
  229. WPARAM wParam,
  230. LPARAM lParam
  231. )
  232. {
  233. CDialog* pThis = (CDialog *) GetWindowLongPtr(hDlg, DWLP_USER);
  234. BOOL Result;
  235. switch (uMsg)
  236. {
  237. case WM_INITDIALOG:
  238. {
  239. pThis = (CDialog *)lParam;
  240. ASSERT(pThis);
  241. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pThis);
  242. pThis->m_hDlg = hDlg;
  243. Result = pThis->OnInitDialog();
  244. break;
  245. }
  246. case WM_COMMAND:
  247. if (pThis) {
  248. pThis->OnCommand(wParam, lParam);
  249. }
  250. Result = FALSE;
  251. break;
  252. case WM_NOTIFY:
  253. if (pThis) {
  254. Result = pThis->OnNotify((LPNMHDR)lParam);
  255. } else {
  256. Result = FALSE;
  257. }
  258. break;
  259. case WM_DESTROY:
  260. if (pThis) {
  261. Result = pThis->OnDestroy();
  262. } else {
  263. Result = FALSE;
  264. }
  265. break;
  266. case WM_HELP:
  267. if (pThis) {
  268. pThis->OnHelp((LPHELPINFO)lParam);
  269. }
  270. Result = FALSE;
  271. break;
  272. case WM_CONTEXTMENU:
  273. if (pThis) {
  274. pThis->OnContextMenu((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
  275. }
  276. Result = FALSE;
  277. break;
  278. default:
  279. Result = FALSE;
  280. break;
  281. }
  282. return Result;
  283. }
  284. //
  285. // class String implementation
  286. //
  287. String::String()
  288. {
  289. m_pData = new StringData;
  290. if (!m_pData)
  291. throw &g_MemoryException;
  292. }
  293. String::String(
  294. const String& strSrc
  295. )
  296. {
  297. m_pData = strSrc.m_pData;
  298. m_pData->AddRef();
  299. }
  300. String::String(
  301. int Len
  302. )
  303. {
  304. StringData* pNewData = new StringData;
  305. TCHAR* ptszNew = new TCHAR[Len + 1];
  306. if (pNewData && ptszNew)
  307. {
  308. pNewData->Len = 0;
  309. pNewData->ptsz = ptszNew;
  310. m_pData = pNewData;
  311. }
  312. else
  313. {
  314. delete pNewData;
  315. delete [] ptszNew;
  316. throw &g_MemoryException;
  317. }
  318. }
  319. String::String(
  320. LPCTSTR lptsz
  321. )
  322. {
  323. int Len = lstrlen(lptsz);
  324. StringData* pNewData = new StringData;
  325. TCHAR* ptszNew = new TCHAR[Len + 1];
  326. if (pNewData && ptszNew)
  327. {
  328. lstrcpy(ptszNew, lptsz);
  329. pNewData->Len = Len;
  330. pNewData->ptsz = ptszNew;
  331. m_pData = pNewData;
  332. }
  333. else
  334. {
  335. delete pNewData;
  336. delete [] ptszNew;
  337. throw &g_MemoryException;
  338. }
  339. }
  340. void
  341. String::Empty()
  342. {
  343. if (m_pData->Len)
  344. {
  345. StringData* pNewData = new StringData;
  346. if (pNewData)
  347. {
  348. m_pData->Release();
  349. m_pData = pNewData;
  350. }
  351. else
  352. {
  353. throw &g_MemoryException;
  354. }
  355. }
  356. }
  357. String&
  358. String::operator=(
  359. const String& strSrc
  360. )
  361. {
  362. // look out for aliasings !!!!
  363. if (this != &strSrc)
  364. {
  365. // add the reference count first before release the old one
  366. // in case our string data is the same as strSrc's.
  367. strSrc.m_pData->AddRef();
  368. m_pData->Release();
  369. m_pData = strSrc.m_pData;
  370. }
  371. return *this;
  372. }
  373. String&
  374. String::operator=(
  375. LPCTSTR ptsz
  376. )
  377. {
  378. // if we are pointing to the same string,
  379. // do nothing
  380. if (ptsz == m_pData->ptsz)
  381. return *this;
  382. //
  383. // str = NULL --> empty the string
  384. //
  385. if (!ptsz)
  386. {
  387. Empty();
  388. return *this;
  389. }
  390. // a new assignment, allocate a new string data
  391. StringData* pNewData = new StringData;
  392. int len = lstrlen(ptsz);
  393. TCHAR* ptszNew = new TCHAR[len + 1];
  394. if (pNewData && ptszNew)
  395. {
  396. lstrcpy(ptszNew, ptsz);
  397. pNewData->Len = len;
  398. pNewData->ptsz = ptszNew;
  399. m_pData->Release();
  400. m_pData = pNewData;
  401. }
  402. else
  403. {
  404. //memory allocation failure
  405. delete pNewData;
  406. delete [] ptszNew;
  407. throw g_MemoryException;
  408. }
  409. return *this;
  410. }
  411. String&
  412. String::operator+=(
  413. const String& strSrc
  414. )
  415. {
  416. if (strSrc.GetLength())
  417. {
  418. int TotalLen = m_pData->Len + strSrc.GetLength();
  419. StringData* pNewData = new StringData;
  420. TCHAR* ptszNew = new TCHAR[TotalLen + 1];
  421. if (pNewData && ptszNew)
  422. {
  423. lstrcpy(ptszNew, m_pData->ptsz);
  424. lstrcat(ptszNew, (LPCTSTR)strSrc);
  425. pNewData->Len = TotalLen;
  426. pNewData->ptsz = ptszNew;
  427. m_pData->Release();
  428. m_pData = pNewData;
  429. }
  430. else
  431. {
  432. delete pNewData;
  433. delete [] ptszNew;
  434. throw &g_MemoryException;
  435. }
  436. }
  437. return *this;
  438. }
  439. String&
  440. String::operator+=(
  441. LPCTSTR ptsz
  442. )
  443. {
  444. if (ptsz)
  445. {
  446. int len = lstrlen(ptsz);
  447. if (len)
  448. {
  449. StringData* pNewData = new StringData;
  450. TCHAR* ptszNew = new TCHAR[len + m_pData->Len + 1];
  451. if (ptszNew && pNewData)
  452. {
  453. lstrcpy(ptszNew, m_pData->ptsz);
  454. lstrcat(ptszNew, ptsz);
  455. pNewData->Len = len + m_pData->Len;
  456. pNewData->ptsz = ptszNew;
  457. m_pData->Release();
  458. m_pData = pNewData;
  459. }
  460. else
  461. {
  462. delete pNewData;
  463. delete [] ptszNew;
  464. throw &g_MemoryException;
  465. }
  466. }
  467. }
  468. return *this;
  469. }
  470. TCHAR&
  471. String::operator[](
  472. int Index
  473. )
  474. {
  475. ASSERT(Index < m_pData->Len);
  476. // make a separate copy of the string data
  477. TCHAR* ptszNew = new TCHAR[m_pData->Len + 1];
  478. StringData* pNewData = new StringData;
  479. if (ptszNew && pNewData)
  480. {
  481. lstrcpy(ptszNew, m_pData->ptsz);
  482. pNewData->ptsz = ptszNew;
  483. pNewData->Len = m_pData->Len;
  484. m_pData->Release();
  485. m_pData = pNewData;
  486. return ptszNew[Index];
  487. }
  488. else
  489. {
  490. delete pNewData;
  491. delete [] ptszNew;
  492. throw &g_MemoryException;
  493. return m_pData->ptsz[Index];
  494. }
  495. }
  496. String::operator LPTSTR()
  497. {
  498. StringData* pNewData = new StringData;
  499. if (pNewData)
  500. {
  501. if (m_pData->Len)
  502. {
  503. TCHAR* ptszNew = new TCHAR[m_pData->Len + 1];
  504. if (ptszNew)
  505. {
  506. lstrcpy(ptszNew, m_pData->ptsz);
  507. pNewData->ptsz = ptszNew;
  508. }
  509. else
  510. {
  511. throw &g_MemoryException;
  512. delete pNewData;
  513. return NULL;
  514. }
  515. }
  516. pNewData->Len = m_pData->Len;
  517. m_pData->Release();
  518. m_pData = pNewData;
  519. return m_pData->ptsz;
  520. }
  521. else
  522. {
  523. throw &g_MemoryException ;
  524. return NULL;
  525. }
  526. }
  527. //
  528. // This is a friend function to String
  529. // Remember that we can NOT return a reference or a pointer.
  530. // This function must return "by-value"
  531. String
  532. operator+(
  533. const String& str1,
  534. const String& str2
  535. )
  536. {
  537. int TotalLen = str1.GetLength() + str2.GetLength();
  538. String strThis(TotalLen);
  539. lstrcpy(strThis.m_pData->ptsz, str1);
  540. lstrcat(strThis.m_pData->ptsz, str2);
  541. strThis.m_pData->Len = TotalLen;
  542. return strThis;
  543. }
  544. BOOL
  545. String::LoadString(
  546. HINSTANCE hInstance,
  547. int ResourceId
  548. )
  549. {
  550. // we have no idea how long the string will be.
  551. // The strategy here is to allocate a stack-based buffer which
  552. // is large enough for most cases. If the buffer is too small,
  553. // we then use heap-based buffer and increment the buffer size
  554. // on each try.
  555. TCHAR tszTemp[256];
  556. long FinalSize, BufferSize;
  557. BufferSize = ARRAYLEN(tszTemp);
  558. TCHAR* HeapBuffer = NULL;
  559. // first try
  560. FinalSize = ::LoadString(hInstance, ResourceId, tszTemp, BufferSize);
  561. //
  562. // LoadString returns the size of the string it loaded, not including the
  563. // NULL termiated char. So if the returned len is one less then the
  564. // provided buffer size, our buffer is too small.
  565. //
  566. if (FinalSize < (BufferSize - 1))
  567. {
  568. // we got what we want
  569. HeapBuffer = tszTemp;
  570. }
  571. else
  572. {
  573. // the stack based buffer is too small, we have to switch to heap
  574. // based.
  575. BufferSize = ARRAYLEN(tszTemp);
  576. // should 32k chars big enough????
  577. while (BufferSize < 0x8000)
  578. {
  579. BufferSize += 256;
  580. // make sure there is no memory leak
  581. ASSERT(NULL == HeapBuffer);
  582. // allocate a new buffer
  583. HeapBuffer = new TCHAR[BufferSize];
  584. if (HeapBuffer)
  585. {
  586. // got a new buffer, another try...
  587. FinalSize = ::LoadString(hInstance, ResourceId, HeapBuffer,
  588. BufferSize);
  589. if (FinalSize < (BufferSize - 1))
  590. {
  591. //got it!
  592. break;
  593. }
  594. }
  595. else
  596. {
  597. throw &g_MemoryException;
  598. }
  599. // discard the buffer
  600. delete [] HeapBuffer;
  601. HeapBuffer = NULL;
  602. }
  603. }
  604. if (HeapBuffer)
  605. {
  606. TCHAR* ptszNew = new TCHAR[FinalSize + 1];
  607. StringData* pNewData = new StringData;
  608. if (pNewData && ptszNew)
  609. {
  610. lstrcpy(ptszNew, HeapBuffer);
  611. // release the old string data because we will have a new one
  612. m_pData->Release();
  613. m_pData = pNewData;
  614. m_pData->ptsz = ptszNew;
  615. m_pData->Len = FinalSize;
  616. if (HeapBuffer != tszTemp) {
  617. delete [] HeapBuffer;
  618. }
  619. return TRUE;
  620. }
  621. else
  622. {
  623. delete [] ptszNew;
  624. delete pNewData;
  625. if (HeapBuffer != tszTemp) {
  626. delete [] HeapBuffer;
  627. }
  628. throw &g_MemoryException;
  629. }
  630. }
  631. return FALSE;
  632. }
  633. //
  634. // This function creates an full-qualified machine name for the
  635. // local computer.
  636. //
  637. BOOL
  638. String::GetComputerName()
  639. {
  640. TCHAR tszTemp[MAX_PATH];
  641. // the GetComputerName api only return the name only.
  642. // we must prepend the UNC signature.
  643. tszTemp[0] = _T('\\');
  644. tszTemp[1] = _T('\\');
  645. ULONG NameLength = ARRAYLEN(tszTemp) - 2;
  646. if (::GetComputerName(tszTemp + 2, &NameLength))
  647. {
  648. int Len = lstrlen(tszTemp);
  649. StringData* pNewData = new StringData;
  650. TCHAR* ptszNew = new TCHAR[Len + 1];
  651. if (pNewData && ptszNew)
  652. {
  653. pNewData->Len = Len;
  654. lstrcpy(ptszNew, tszTemp);
  655. pNewData->ptsz = ptszNew;
  656. m_pData->Release();
  657. m_pData = pNewData;
  658. return TRUE;
  659. }
  660. else
  661. {
  662. delete pNewData;
  663. delete []ptszNew;
  664. throw &g_MemoryException;
  665. }
  666. }
  667. return FALSE;
  668. }
  669. BOOL
  670. String::GetSystemWindowsDirectory()
  671. {
  672. TCHAR tszTemp[MAX_PATH];
  673. if (::GetSystemWindowsDirectory(tszTemp, ARRAYLEN(tszTemp))) {
  674. int Len = lstrlen(tszTemp);
  675. StringData* pNewData = new StringData;
  676. TCHAR* ptszNew = new TCHAR[Len + 1];
  677. if (pNewData && ptszNew) {
  678. pNewData->Len = Len;
  679. lstrcpy(ptszNew, tszTemp);
  680. pNewData->ptsz = ptszNew;
  681. m_pData->Release();
  682. m_pData = pNewData;
  683. return TRUE;
  684. } else {
  685. delete pNewData;
  686. delete []ptszNew;
  687. throw &g_MemoryException;
  688. }
  689. }
  690. return FALSE;
  691. }
  692. void
  693. String::Format(
  694. LPCTSTR FormatString,
  695. ...
  696. )
  697. {
  698. // according to wsprintf specification, the max buffer size is
  699. // 1024
  700. TCHAR* pBuffer = new TCHAR[1024];
  701. if (pBuffer)
  702. {
  703. va_list arglist;
  704. va_start(arglist, FormatString);
  705. int len;
  706. len = wvsprintf(pBuffer, FormatString, arglist);
  707. va_end(arglist);
  708. if (len)
  709. {
  710. TCHAR* ptszNew = new TCHAR[len + 1];
  711. StringData* pNewData = new StringData;
  712. if (pNewData && ptszNew)
  713. {
  714. pNewData->Len = len;
  715. lstrcpy(ptszNew, pBuffer);
  716. pNewData->ptsz = ptszNew;
  717. m_pData->Release();
  718. m_pData = pNewData;
  719. delete [] pBuffer;
  720. return;
  721. }
  722. else
  723. {
  724. delete [] pBuffer;
  725. delete [] ptszNew;
  726. delete [] pNewData;
  727. throw &g_MemoryException;
  728. }
  729. }
  730. }
  731. throw &g_MemoryException;
  732. }
  733. //
  734. // templates
  735. //
  736. template <class T>
  737. inline void ContructElements(T* pElements, int Count)
  738. {
  739. ASSERT(Count > 0);
  740. memset((void*)pElements, Count * sizeof(T));
  741. for (; Count; pElments++, Count--)
  742. {
  743. // call the class's ctor
  744. // note the placement.
  745. new((void*)pElements) T;
  746. }
  747. }
  748. //
  749. // CCommandLine implementation
  750. //
  751. // code adapted from C startup code -- see stdargv.c
  752. // It walks through the given CmdLine and calls ParseParam
  753. // when an argument is encountered.
  754. // An argument must in this format:
  755. // </command arg_to_command> or <-command arg_to_command>
  756. void
  757. CCommandLine::ParseCommandLine(
  758. LPCTSTR CmdLine
  759. )
  760. {
  761. LPCTSTR p;
  762. LPTSTR args, pDst;
  763. BOOL bInQuote;
  764. BOOL bCopyTheChar;
  765. int nSlash;
  766. p = CmdLine;
  767. args = new TCHAR[lstrlen(CmdLine) + 1];
  768. if (!args)
  769. return;
  770. for (;;)
  771. {
  772. // skip blanks
  773. while (_T(' ') == *p || _T('\t') == *p)
  774. p++;
  775. // nothing left, bail
  776. if (_T('\0') == *p)
  777. break;
  778. // 2N backslashes + '\"' ->N backslashes plus string delimiter
  779. // 2N + 1 baclslashes + '\"' ->N backslashes plus literal '\"'
  780. // N backslashes -> N backslashes
  781. nSlash = 0;
  782. bInQuote = FALSE;
  783. pDst = args;
  784. for (;;)
  785. {
  786. bCopyTheChar = TRUE;
  787. //count how may backslashes
  788. while(_T('\\') == *p)
  789. {
  790. p++;
  791. nSlash++;
  792. }
  793. if (_T('\"') == *p)
  794. {
  795. if (0 == (nSlash % 2))
  796. {
  797. // 2N backslashes plus '\"' ->N baskslashes plus
  798. // delimiter
  799. if (bInQuote)
  800. // double quote inside quoted string
  801. // skip the first and copy the second.
  802. if (_T('\"') == p[1])
  803. p++;
  804. else
  805. bCopyTheChar = FALSE;
  806. else
  807. bCopyTheChar = FALSE;
  808. // toggle quoted status
  809. bInQuote = !bInQuote;
  810. }
  811. nSlash /= 2;
  812. }
  813. while (nSlash)
  814. {
  815. *pDst++ = _T('\\');
  816. nSlash--;
  817. }
  818. if (_T('\0') == *p || (!bInQuote && (_T(' ') == *p || _T('\t') == *p)))
  819. {
  820. break;
  821. }
  822. // copy char to args
  823. if (bCopyTheChar)
  824. {
  825. *pDst++ = *p;
  826. }
  827. p++;
  828. }
  829. // we have a complete argument now. Null terminates it and
  830. // let the derived class parse the argument.
  831. *pDst = _T('\0');
  832. // skip blanks to see if this is the last argument
  833. while (_T(' ') == *p || _T('\t') == *p)
  834. p++;
  835. BOOL bFlag;
  836. bFlag = (_T('/') == *args || _T('-') == *args);
  837. pDst = (bFlag) ? args + 1 : args;
  838. ParseParam(pDst, bFlag, _T('\0') == *p);
  839. }
  840. delete [] args;
  841. }
  842. //
  843. // CSafeRegistry implementation
  844. //
  845. BOOL
  846. CSafeRegistry::Open(
  847. HKEY hKeyAncestor,
  848. LPCTSTR KeyName,
  849. REGSAM Access
  850. )
  851. {
  852. DWORD LastError;
  853. // we shouldn't has a valid key -- or memory leak
  854. // Also, a key name must be provided -- or open nothing
  855. ASSERT(!m_hKey && KeyName);
  856. LastError = ::RegOpenKeyEx(hKeyAncestor, KeyName, 0, Access, &m_hKey);
  857. SetLastError(LastError);
  858. return ERROR_SUCCESS == LastError;
  859. }
  860. BOOL
  861. CSafeRegistry::Create(
  862. HKEY hKeyAncestor,
  863. LPCTSTR KeyName,
  864. REGSAM Access,
  865. DWORD* pDisposition,
  866. DWORD Options,
  867. LPSECURITY_ATTRIBUTES pSecurity
  868. )
  869. {
  870. ASSERT(KeyName && !m_hKey);
  871. DWORD Disposition;
  872. DWORD LastError;
  873. LastError = ::RegCreateKeyEx(hKeyAncestor, KeyName, 0, TEXT(""),
  874. Options, Access, pSecurity,
  875. &m_hKey, &Disposition
  876. );
  877. SetLastError(LastError);
  878. if (ERROR_SUCCESS == LastError && pDisposition)
  879. {
  880. *pDisposition = Disposition;
  881. }
  882. if (ERROR_SUCCESS != LastError)
  883. m_hKey = NULL;
  884. return ERROR_SUCCESS == LastError;
  885. }
  886. BOOL
  887. CSafeRegistry::SetValue(
  888. LPCTSTR ValueName,
  889. DWORD Type,
  890. const PBYTE pData,
  891. DWORD DataLen
  892. )
  893. {
  894. ASSERT(m_hKey);
  895. DWORD LastError;
  896. LastError = ::RegSetValueEx(m_hKey, ValueName, 0, Type, pData, DataLen);
  897. SetLastError(LastError);
  898. return ERROR_SUCCESS == LastError;
  899. }
  900. BOOL
  901. CSafeRegistry::SetValue(
  902. LPCTSTR ValueName,
  903. LPCTSTR Value
  904. )
  905. {
  906. return SetValue(ValueName,
  907. REG_SZ,
  908. (PBYTE)Value,
  909. (lstrlen(Value) + 1) * sizeof(TCHAR)
  910. );
  911. }
  912. BOOL
  913. CSafeRegistry::GetValue(
  914. LPCTSTR ValueName,
  915. DWORD* pType,
  916. const PBYTE pData,
  917. DWORD* pDataLen
  918. )
  919. {
  920. ASSERT(m_hKey);
  921. DWORD LastError;
  922. LastError = ::RegQueryValueEx(m_hKey, ValueName, NULL, pType, pData,
  923. pDataLen);
  924. SetLastError(LastError);
  925. return ERROR_SUCCESS == LastError;
  926. }
  927. BOOL
  928. CSafeRegistry::GetValue(
  929. LPCTSTR ValueName,
  930. String& str
  931. )
  932. {
  933. DWORD Type, Size;
  934. PBYTE Buffer = NULL;
  935. Size = 0;
  936. BOOL Result = FALSE;
  937. // check size before Type because when the size is zero, type contains
  938. // undefined data.
  939. if (GetValue(ValueName, &Type, NULL, &Size) && Size && REG_SZ == Type)
  940. {
  941. // we do not want to throw an exception here.
  942. // so guard it
  943. try
  944. {
  945. BufferPtr<BYTE> BufferPtr(Size);
  946. Result = GetValue(ValueName, &Type, BufferPtr, &Size);
  947. if (Result)
  948. str = (LPCTSTR)(BYTE*)BufferPtr;
  949. }
  950. catch(CMemoryException* e)
  951. {
  952. e->Delete();
  953. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  954. Result = FALSE;
  955. }
  956. }
  957. return Result;
  958. }
  959. BOOL
  960. CSafeRegistry::EnumerateSubkey(
  961. DWORD Index,
  962. LPTSTR Buffer,
  963. DWORD* BufferSize
  964. )
  965. {
  966. DWORD LastError;
  967. FILETIME LastWrite;
  968. LastError = ::RegEnumKeyEx(m_hKey, Index, Buffer, BufferSize,
  969. NULL, NULL, NULL, &LastWrite);
  970. SetLastError(LastError);
  971. return ERROR_SUCCESS == LastError;
  972. }
  973. BOOL
  974. CSafeRegistry::DeleteValue(
  975. LPCTSTR ValueName
  976. )
  977. {
  978. ASSERT(m_hKey);
  979. DWORD LastError = ::RegDeleteValue(m_hKey, ValueName);
  980. SetLastError(LastError);
  981. return ERROR_SUCCESS == LastError;
  982. }
  983. BOOL
  984. CSafeRegistry::DeleteSubkey(
  985. LPCTSTR SubkeyName
  986. )
  987. {
  988. ASSERT(m_hKey);
  989. CSafeRegistry regSubkey;
  990. TCHAR KeyName[MAX_PATH];
  991. FILETIME LastWrite;
  992. DWORD KeyNameLen;
  993. while (TRUE)
  994. {
  995. KeyNameLen = ARRAYLEN(KeyName);
  996. // always uses index 0(the first subkey)
  997. if (!regSubkey.Open(m_hKey, SubkeyName, KEY_WRITE | KEY_ENUMERATE_SUB_KEYS) ||
  998. ERROR_SUCCESS != ::RegEnumKeyEx(regSubkey, 0, KeyName,
  999. &KeyNameLen, NULL, NULL, NULL,
  1000. &LastWrite) ||
  1001. !regSubkey.DeleteSubkey(KeyName))
  1002. {
  1003. break;
  1004. }
  1005. // close the key so that we will re-open it on each loop
  1006. // -- we have deleted one subkey and without closing
  1007. // the key, the index to RegEnumKeyEx will be confusing
  1008. regSubkey.Close();
  1009. }
  1010. // now delete the subkey
  1011. ::RegDeleteKey(m_hKey, SubkeyName);
  1012. return TRUE;
  1013. }
  1014. //
  1015. //CLogFile::Log implementation
  1016. //
  1017. BOOL
  1018. CLogFile::Log(
  1019. LPCTSTR Text
  1020. )
  1021. {
  1022. DWORD BytesWritten;
  1023. if (Text && m_hFile)
  1024. {
  1025. int Size = lstrlen(Text);
  1026. #ifdef UNICODE
  1027. BufferPtr<CHAR> Buffer(Size * sizeof(WCHAR));
  1028. Size = WideCharToMultiByte(CP_ACP, 0, Text, Size, Buffer, Size*sizeof(WCHAR), NULL, NULL);
  1029. return WriteFile(m_hFile, Buffer, Size, &BytesWritten, NULL);
  1030. #else
  1031. retrun WriteFile(m_hFile, Text, Size, &BytesWritten, NULL);
  1032. #endif
  1033. }
  1034. return TRUE;
  1035. }
  1036. //
  1037. // CLogFile::Logf implementation
  1038. //
  1039. BOOL
  1040. CLogFile::Logf(
  1041. LPCTSTR Format,
  1042. ...
  1043. )
  1044. {
  1045. if (m_hFile)
  1046. {
  1047. // according to wsprintf specification, the max buffer size is
  1048. // 1024
  1049. TCHAR Buffer[1024];
  1050. va_list arglist;
  1051. va_start(arglist, Format);
  1052. wvsprintf(Buffer, Format, arglist);
  1053. va_end(arglist);
  1054. return Log(Buffer);
  1055. }
  1056. return TRUE;
  1057. }
  1058. //
  1059. // CLogFile::LogLastError implementation
  1060. //
  1061. BOOL
  1062. CLogFile::LogLastError(
  1063. LPCTSTR FunctionName
  1064. )
  1065. {
  1066. if (m_hFile && FunctionName)
  1067. {
  1068. TCHAR szMsg[MAX_PATH];
  1069. FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
  1070. NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
  1071. szMsg, ARRAYLEN(szMsg), NULL);
  1072. Logf(TEXT("%s: error(%ld) : %s\n"), FunctionName, GetLastError(), szMsg);
  1073. }
  1074. return TRUE;
  1075. }