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.

1734 lines
44 KiB

  1. /*++
  2. Copyright (c) 1999-2002 Microsoft Corporation
  3. Module Name:
  4. wrkspace.cpp
  5. Abstract:
  6. This module contains the workspace implementation.
  7. --*/
  8. #include "precomp.hxx"
  9. #pragma hdrstop
  10. // #define DBG_WSP
  11. #define WSP_ALIGN(Size) (((Size) + 7) & ~7)
  12. #define WSP_GROW_BY 1024
  13. #if DBG
  14. #define SCORCH_ENTRY(Entry) \
  15. memset((Entry) + 1, 0xdb, (Entry)->FullSize - sizeof(*(Entry)))
  16. #else
  17. #define SCORCH_ENTRY(Entry)
  18. #endif
  19. ULONG g_WspSwitchKey;
  20. TCHAR g_WspSwitchValue[MAX_PATH];
  21. BOOL g_WspSwitchBufferAvailable = TRUE;
  22. Workspace* g_Workspace;
  23. BOOL g_ExplicitWorkspace;
  24. char* g_WorkspaceKeyNames[] =
  25. {
  26. "",
  27. "Kernel",
  28. "User",
  29. "Dump",
  30. "Remote",
  31. "Explicit",
  32. "File",
  33. };
  34. char* g_WorkspaceDefaultName = "Default";
  35. char* g_WorkspaceKeyDescriptions[] =
  36. {
  37. "Base workspace",
  38. "Kernel mode workspaces",
  39. "User mode workspaces",
  40. "Dump file workspaces",
  41. "Remote client workspaces",
  42. "User-saved workspaces",
  43. "Workspaces in files",
  44. };
  45. Workspace::Workspace(void)
  46. {
  47. m_Flags = 0;
  48. m_Data = NULL;
  49. m_DataLen = 0;
  50. m_DataUsed = 0;
  51. m_Key = WSP_NAME_BASE;
  52. m_Value = NULL;
  53. }
  54. Workspace::~Workspace(void)
  55. {
  56. free(m_Data);
  57. free(m_Value);
  58. }
  59. WSP_ENTRY*
  60. Workspace::Get(WSP_TAG Tag)
  61. {
  62. WSP_ENTRY* Entry = NULL;
  63. while ((Entry = NextEntry(Entry)) != NULL)
  64. {
  65. if (Entry->Tag == Tag)
  66. {
  67. return Entry;
  68. }
  69. }
  70. return NULL;
  71. }
  72. WSP_ENTRY*
  73. Workspace::GetNext(WSP_ENTRY* Entry, WSP_TAG Tag, WSP_TAG TagMask)
  74. {
  75. while ((Entry = NextEntry(Entry)) != NULL)
  76. {
  77. if ((Entry->Tag & TagMask) == Tag)
  78. {
  79. return Entry;
  80. }
  81. }
  82. return NULL;
  83. }
  84. WSP_ENTRY*
  85. Workspace::GetString(WSP_TAG Tag, PSTR Str, ULONG MaxSize)
  86. {
  87. WSP_ENTRY* Entry = Get(Tag);
  88. if (Entry != NULL)
  89. {
  90. if (Entry->DataSize > MaxSize)
  91. {
  92. return NULL;
  93. }
  94. strcpy(Str, WSP_ENTRY_DATA(PSTR, Entry));
  95. }
  96. return Entry;
  97. }
  98. WSP_ENTRY*
  99. Workspace::GetAllocString(WSP_TAG Tag, PSTR* Str)
  100. {
  101. WSP_ENTRY* Entry = Get(Tag);
  102. if (Entry != NULL)
  103. {
  104. *Str = (PSTR)malloc(Entry->DataSize);
  105. if (*Str == NULL)
  106. {
  107. return NULL;
  108. }
  109. strcpy(*Str, WSP_ENTRY_DATA(PSTR, Entry));
  110. }
  111. return Entry;
  112. }
  113. WSP_ENTRY*
  114. Workspace::GetBuffer(WSP_TAG Tag, PVOID Buf, ULONG Size)
  115. {
  116. WSP_ENTRY* Entry = Get(Tag);
  117. if (Entry != NULL)
  118. {
  119. if (Entry->DataSize != Size)
  120. {
  121. return NULL;
  122. }
  123. memcpy(Buf, WSP_ENTRY_DATA(PUCHAR, Entry), Size);
  124. }
  125. return Entry;
  126. }
  127. WSP_ENTRY*
  128. Workspace::Set(WSP_TAG Tag, ULONG Size)
  129. {
  130. WSP_ENTRY* Entry;
  131. ULONG FullSize;
  132. // Compute full rounded size.
  133. FullSize = sizeof(WSP_ENTRY) + WSP_ALIGN(Size);
  134. // Check and see if there's already an entry.
  135. Entry = Get(Tag);
  136. if (Entry != NULL)
  137. {
  138. // If it's already large enough use it and
  139. // pack in remaining data.
  140. if (Entry->FullSize >= FullSize)
  141. {
  142. ULONG Pack = Entry->FullSize - FullSize;
  143. if (Pack > 0)
  144. {
  145. PackData((PUCHAR)Entry + FullSize, Pack);
  146. Entry->FullSize = (USHORT)FullSize;
  147. }
  148. Entry->DataSize = (USHORT)Size;
  149. SCORCH_ENTRY(Entry);
  150. m_Flags |= WSPF_DIRTY_WRITE;
  151. return Entry;
  152. }
  153. // Entry is too small so remove it.
  154. PackData((PUCHAR)Entry, Entry->FullSize);
  155. }
  156. return Add(Tag, Size);
  157. }
  158. WSP_ENTRY*
  159. Workspace::SetString(WSP_TAG Tag, PCSTR Str)
  160. {
  161. ULONG Size = strlen(Str) + 1;
  162. WSP_ENTRY* Entry = Set(Tag, Size);
  163. if (Entry != NULL)
  164. {
  165. memcpy(WSP_ENTRY_DATA(PSTR, Entry), Str, Size);
  166. }
  167. return Entry;
  168. }
  169. WSP_ENTRY*
  170. Workspace::SetStrings(WSP_TAG Tag, ULONG Count, PCSTR* Strs)
  171. {
  172. ULONG i;
  173. ULONG Size = 0;
  174. for (i = 0; i < Count; i++)
  175. {
  176. Size += strlen(Strs[i]) + 1;
  177. }
  178. // Put a double terminator at the very end.
  179. Size++;
  180. WSP_ENTRY* Entry = Set(Tag, Size);
  181. if (Entry != NULL)
  182. {
  183. PSTR Data = WSP_ENTRY_DATA(PSTR, Entry);
  184. for (i = 0; i < Count; i++)
  185. {
  186. Size = strlen(Strs[i]) + 1;
  187. memcpy(Data, Strs[i], Size);
  188. Data += Size;
  189. }
  190. *Data = 0;
  191. }
  192. return Entry;
  193. }
  194. WSP_ENTRY*
  195. Workspace::SetBuffer(WSP_TAG Tag, PVOID Buf, ULONG Size)
  196. {
  197. WSP_ENTRY* Entry = Set(Tag, Size);
  198. if (Entry != NULL)
  199. {
  200. memcpy(WSP_ENTRY_DATA(PUCHAR, Entry), Buf, Size);
  201. }
  202. return Entry;
  203. }
  204. WSP_ENTRY*
  205. Workspace::Add(WSP_TAG Tag, ULONG Size)
  206. {
  207. // Compute full rounded size.
  208. ULONG FullSize = sizeof(WSP_ENTRY) + WSP_ALIGN(Size);
  209. WSP_ENTRY* Entry = AllocateEntry(FullSize);
  210. if (Entry != NULL)
  211. {
  212. Entry->Tag = Tag;
  213. Entry->FullSize = (USHORT)FullSize;
  214. Entry->DataSize = (USHORT)Size;
  215. SCORCH_ENTRY(Entry);
  216. m_Flags |= WSPF_DIRTY_WRITE;
  217. }
  218. return Entry;
  219. }
  220. void
  221. Workspace::DeleteEntry(WSP_ENTRY* Entry)
  222. {
  223. if (ValidEntry(Entry))
  224. {
  225. PackData((PUCHAR)Entry, Entry->FullSize);
  226. }
  227. }
  228. ULONG
  229. Workspace::Delete(WSP_TAG Tag, WSP_TAG TagMask)
  230. {
  231. ULONG Deleted = 0;
  232. WSP_ENTRY* Entry = NextEntry(NULL);
  233. while (Entry != NULL)
  234. {
  235. if ((Entry->Tag & TagMask) == Tag)
  236. {
  237. DeleteEntry(Entry);
  238. Deleted++;
  239. m_Flags |= WSPF_DIRTY_WRITE;
  240. // Check and see if we packed away the last entry.
  241. if (!ValidEntry(Entry))
  242. {
  243. break;
  244. }
  245. }
  246. else
  247. {
  248. Entry = NextEntry(Entry);
  249. }
  250. }
  251. return Deleted;
  252. }
  253. void
  254. Workspace::Empty(void)
  255. {
  256. // Reset used to just the header.
  257. m_DataUsed = sizeof(WSP_HEADER);
  258. // Nothing is dirty now except the write of emptiness.
  259. m_Flags = (m_Flags & ~WSPF_DIRTY_ALL) | WSPF_DIRTY_WRITE;
  260. }
  261. PTSTR
  262. Workspace::GetName(BOOL Verbose)
  263. {
  264. static TCHAR s_Buffer[MAX_PATH];
  265. s_Buffer[0] = 0;
  266. if (Verbose)
  267. {
  268. PSTR Type;
  269. switch(m_Key)
  270. {
  271. case WSP_NAME_FILE:
  272. Type = "File: ";
  273. break;
  274. case WSP_NAME_EXPLICIT:
  275. Type = "Explicit: ";
  276. break;
  277. default:
  278. Type = "Implicit: ";
  279. break;
  280. }
  281. CatString(s_Buffer, Type, DIMA(s_Buffer));
  282. }
  283. if (m_Key != WSP_NAME_FILE && !strcmp(m_Value, g_WorkspaceDefaultName))
  284. {
  285. if (m_Key == WSP_NAME_BASE)
  286. {
  287. CatString(s_Buffer, "base", DIMA(s_Buffer));
  288. }
  289. else
  290. {
  291. CatString(s_Buffer, g_WorkspaceKeyNames[m_Key], DIMA(s_Buffer));
  292. CatString(s_Buffer, " default", DIMA(s_Buffer));
  293. }
  294. }
  295. else
  296. {
  297. CatString(s_Buffer, m_Value, DIMA(s_Buffer));
  298. }
  299. return s_Buffer;
  300. }
  301. HRESULT
  302. Workspace::Create(ULONG Key, PTSTR Value,
  303. Workspace** NewWsp)
  304. {
  305. Workspace* Wsp = new Workspace;
  306. if (Wsp == NULL)
  307. {
  308. return E_OUTOFMEMORY;
  309. }
  310. Wsp->m_Key = Key;
  311. if (Value != NULL)
  312. {
  313. Wsp->m_Value = _tcsdup(Value);
  314. if (Wsp->m_Value == NULL)
  315. {
  316. delete Wsp;
  317. return E_OUTOFMEMORY;
  318. }
  319. }
  320. WSP_ENTRY* Entry;
  321. WSP_HEADER* Header;
  322. // Allocate intial space for the header and eight
  323. // small entries. The workspace grows by large amounts
  324. // so this will immediately allocate a reasonable chunk.
  325. Entry = Wsp->AllocateEntry(sizeof(WSP_HEADER) +
  326. 8 * (sizeof(WSP_ENTRY) + 2 * sizeof(ULONG64)));
  327. if (Entry == NULL)
  328. {
  329. delete Wsp;
  330. return E_OUTOFMEMORY;
  331. }
  332. Header = (WSP_HEADER*)Entry;
  333. Header->Signature = WSP_SIGNATURE;
  334. Header->Version = WSP_VERSION;
  335. // Reset used to just the header.
  336. Wsp->m_DataUsed = sizeof(*Header);
  337. // Start out dirty so the workspace will be written
  338. // out and therefore can be opened later.
  339. Wsp->m_Flags |= WSPF_DIRTY_WRITE;
  340. *NewWsp = Wsp;
  341. return S_OK;
  342. }
  343. HRESULT
  344. Workspace::ReadFromReg(void)
  345. {
  346. HRESULT Status;
  347. HKEY RegKey;
  348. LONG RegStatus;
  349. BOOL InPrimary;
  350. //
  351. // First check and see if the value exists under the
  352. // primary key. If not, check the secondary key.
  353. //
  354. RegKey = OpenKey(TRUE, m_Key, FALSE);
  355. if (RegKey)
  356. {
  357. RegStatus = RegQueryValueEx(RegKey, m_Value, NULL, NULL, NULL, NULL);
  358. if (RegStatus != ERROR_SUCCESS && RegStatus != ERROR_MORE_DATA)
  359. {
  360. RegCloseKey(RegKey);
  361. RegKey = NULL;
  362. }
  363. }
  364. if (RegKey == NULL)
  365. {
  366. RegKey = OpenKey(FALSE, m_Key, FALSE);
  367. if (RegKey == NULL)
  368. {
  369. return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  370. }
  371. InPrimary = FALSE;
  372. }
  373. else
  374. {
  375. InPrimary = TRUE;
  376. }
  377. DWORD Type;
  378. DWORD Size;
  379. Size = 0;
  380. RegStatus = RegQueryValueEx(RegKey, m_Value, NULL, &Type, NULL, &Size);
  381. if (RegStatus != ERROR_SUCCESS && RegStatus != ERROR_MORE_DATA)
  382. {
  383. Status = HRESULT_FROM_WIN32(RegStatus);
  384. goto EH_Key;
  385. }
  386. if (Type != REG_BINARY ||
  387. WSP_ALIGN(Size) != Size)
  388. {
  389. Status = E_INVALIDARG;
  390. goto EH_Key;
  391. }
  392. WSP_ENTRY* Entry;
  393. WSP_HEADER* Header;
  394. Entry = AllocateEntry(Size);
  395. if (Entry == NULL)
  396. {
  397. Status = E_OUTOFMEMORY;
  398. goto EH_Key;
  399. }
  400. Header = (WSP_HEADER*)Entry;
  401. if (RegQueryValueEx(RegKey, m_Value, NULL, &Type, (LPBYTE)Header, &Size) !=
  402. ERROR_SUCCESS ||
  403. Header->Signature != WSP_SIGNATURE ||
  404. Header->Version != WSP_VERSION)
  405. {
  406. Status = E_INVALIDARG;
  407. goto EH_Key;
  408. }
  409. RegCloseKey(RegKey);
  410. //
  411. // If the workspace was read from the secondary key
  412. // migrate it to the primary and remove the secondary
  413. // entry.
  414. //
  415. if (!InPrimary)
  416. {
  417. if (WriteToReg() == S_OK)
  418. {
  419. DeleteReg(FALSE);
  420. }
  421. }
  422. return S_OK;
  423. EH_Key:
  424. RegCloseKey(RegKey);
  425. return Status;
  426. }
  427. HRESULT
  428. Workspace::ReadFromFile(void)
  429. {
  430. HRESULT Status;
  431. HANDLE File;
  432. File = CreateFile(m_Value, GENERIC_READ, FILE_SHARE_READ,
  433. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  434. if (!File || File == INVALID_HANDLE_VALUE)
  435. {
  436. return WIN32_LAST_STATUS();
  437. }
  438. DWORD Size = GetFileSize(File, NULL);
  439. if (Size == INVALID_FILE_SIZE ||
  440. WSP_ALIGN(Size) != Size)
  441. {
  442. Status = E_INVALIDARG;
  443. goto EH_File;
  444. }
  445. WSP_ENTRY* Entry;
  446. WSP_HEADER* Header;
  447. Entry = AllocateEntry(Size);
  448. if (Entry == NULL)
  449. {
  450. Status = E_OUTOFMEMORY;
  451. goto EH_File;
  452. }
  453. Header = (WSP_HEADER*)Entry;
  454. DWORD Done;
  455. if (!ReadFile(File, Header, Size, &Done, NULL) ||
  456. Done != Size ||
  457. Header->Signature != WSP_SIGNATURE ||
  458. Header->Version != WSP_VERSION)
  459. {
  460. Status = E_INVALIDARG;
  461. goto EH_File;
  462. }
  463. CloseHandle(File);
  464. return S_OK;
  465. EH_File:
  466. CloseHandle(File);
  467. return Status;
  468. }
  469. HRESULT
  470. Workspace::Read(ULONG Key, PTSTR Value,
  471. Workspace** NewWsp)
  472. {
  473. // Make sure basic structures preserve alignment.
  474. C_ASSERT(sizeof(WSP_HEADER) == WSP_ALIGN(sizeof(WSP_HEADER)));
  475. C_ASSERT(sizeof(WSP_ENTRY) == WSP_ALIGN(sizeof(WSP_ENTRY)));
  476. C_ASSERT(sizeof(WSP_COMMONWIN_HEADER) ==
  477. WSP_ALIGN(sizeof(WSP_COMMONWIN_HEADER)));
  478. HRESULT Status;
  479. Workspace* Wsp = new Workspace;
  480. if (Wsp == NULL)
  481. {
  482. return E_OUTOFMEMORY;
  483. }
  484. Wsp->m_Key = Key;
  485. if (Value != NULL)
  486. {
  487. Wsp->m_Value = _tcsdup(Value);
  488. if (Wsp->m_Value == NULL)
  489. {
  490. delete Wsp;
  491. return E_OUTOFMEMORY;
  492. }
  493. }
  494. if (Key == WSP_NAME_FILE)
  495. {
  496. Status = Wsp->ReadFromFile();
  497. }
  498. else
  499. {
  500. Status = Wsp->ReadFromReg();
  501. }
  502. if (Status != S_OK)
  503. {
  504. delete Wsp;
  505. }
  506. else
  507. {
  508. *NewWsp = Wsp;
  509. }
  510. return Status;
  511. }
  512. HRESULT
  513. Workspace::ChangeName(ULONG Key, PTSTR Value, BOOL Force)
  514. {
  515. if (!Force)
  516. {
  517. if (Key == WSP_NAME_FILE)
  518. {
  519. if (GetFileAttributes(Value) != -1)
  520. {
  521. return HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
  522. }
  523. }
  524. else
  525. {
  526. HKEY RegKey;
  527. //
  528. // Check and see if a workspace entry already
  529. // exists under the given name. We only need
  530. // to check the primary key as we're only concerned
  531. // with overwriting and writing always occurs
  532. // to the primary key.
  533. //
  534. RegKey = OpenKey(TRUE, Key, FALSE);
  535. if (RegKey != NULL)
  536. {
  537. LONG RegStatus;
  538. RegStatus = RegQueryValueEx(RegKey, Value, NULL, NULL,
  539. NULL, NULL);
  540. RegCloseKey(RegKey);
  541. if (RegStatus == ERROR_SUCCESS || RegStatus == ERROR_MORE_DATA)
  542. {
  543. return HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
  544. }
  545. }
  546. }
  547. }
  548. //
  549. // Swap the workspace name.
  550. //
  551. PTSTR NewValue;
  552. if (Value != NULL)
  553. {
  554. NewValue = _tcsdup(Value);
  555. if (NewValue == NULL)
  556. {
  557. return E_OUTOFMEMORY;
  558. }
  559. }
  560. else
  561. {
  562. NewValue = NULL;
  563. }
  564. delete m_Value;
  565. m_Key = Key;
  566. m_Value = NewValue;
  567. // Need to write data out to the new location.
  568. m_Flags |= WSPF_DIRTY_WRITE;
  569. return S_OK;
  570. }
  571. void
  572. Workspace::UpdateBreakpointInformation(void)
  573. {
  574. HRESULT Status;
  575. Status = g_BpCmdsBuffer->UiLockForRead();
  576. if (Status == S_OK)
  577. {
  578. // Clear old information.
  579. Delete(WSP_GLOBAL_BREAKPOINTS, WSP_TAG_MASK);
  580. // Only save an entry if there are breakpoints.
  581. // Minimum output is a newline and terminator so
  582. // don't count those.
  583. if (g_BpCmdsBuffer->GetDataLen() > 2)
  584. {
  585. PSTR Cmds = (PSTR)g_BpCmdsBuffer->GetDataBuffer();
  586. SetString(WSP_GLOBAL_BREAKPOINTS, Cmds);
  587. }
  588. UnlockStateBuffer(g_BpCmdsBuffer);
  589. }
  590. }
  591. void
  592. Workspace::UpdateWindowInformation(void)
  593. {
  594. // Clear old information.
  595. Delete(DEF_WSP_TAG(WSP_GROUP_WINDOW, 0), WSP_GROUP_MASK);
  596. //
  597. // Record the frame window state.
  598. //
  599. WINDOWPLACEMENT Place;
  600. Place.length = sizeof(Place);
  601. GetWindowPlacement(g_hwndFrame, &Place);
  602. SetBuffer(WSP_WINDOW_FRAME_PLACEMENT, &Place, sizeof(Place));
  603. //
  604. // Persist windows from the bottom of the Z order up
  605. // so that when they're recreated in the same order
  606. // the Z order is also recreated.
  607. //
  608. HWND Win = MDIGetActive(g_hwndMDIClient, NULL);
  609. if (Win == NULL ||
  610. (Win = GetWindow(Win, GW_HWNDLAST)) == NULL)
  611. {
  612. // No windows.
  613. return;
  614. }
  615. while (Win != NULL)
  616. {
  617. PCOMMONWIN_DATA WinData = GetCommonWinData(Win);
  618. if (WinData != NULL)
  619. {
  620. WSP_ENTRY* Entry;
  621. ULONG Size;
  622. Size = WinData->GetWorkspaceSize();
  623. Entry = Add(WSP_WINDOW_COMMONWIN_1,
  624. Size + sizeof(WSP_COMMONWIN_HEADER));
  625. if (Entry != NULL)
  626. {
  627. WSP_COMMONWIN_HEADER* Hdr =
  628. WSP_ENTRY_DATA(WSP_COMMONWIN_HEADER*, Entry);
  629. Hdr->Type = WinData->m_enumType;
  630. Hdr->Reserved = 0;
  631. if (Size > 0)
  632. {
  633. WinData->SetWorkspace((PUCHAR)(Hdr + 1));
  634. }
  635. }
  636. }
  637. Win = GetWindow(Win, GW_HWNDPREV);
  638. }
  639. }
  640. void
  641. Workspace::UpdateLogFileInformation(void)
  642. {
  643. HRESULT Status;
  644. char LogFile[MAX_PATH];
  645. BOOL Append;
  646. ULONG FileLen;
  647. Status = g_pUiControl->GetLogFile(LogFile, sizeof(LogFile), NULL,
  648. &Append);
  649. if (Status != S_OK && Status != E_NOINTERFACE)
  650. {
  651. return;
  652. }
  653. // Clear old information.
  654. Delete(WSP_GLOBAL_LOG_FILE, WSP_TAG_MASK);
  655. if (Status == E_NOINTERFACE)
  656. {
  657. // No log is open.
  658. return;
  659. }
  660. FileLen = strlen(LogFile) + 1;
  661. WSP_ENTRY* Entry = Set(WSP_GLOBAL_LOG_FILE, sizeof(BOOL) + FileLen);
  662. if (Entry != NULL)
  663. {
  664. PSTR Data = WSP_ENTRY_DATA(PSTR, Entry);
  665. *(PBOOL)Data = Append;
  666. strcpy(Data + sizeof(Append), LogFile);
  667. }
  668. }
  669. void
  670. Workspace::UpdatePathInformation(void)
  671. {
  672. HRESULT Status;
  673. char Path[MAX_ENGINE_PATH];
  674. Status = g_pUiSymbols->GetSymbolPath(Path, sizeof(Path), NULL);
  675. if (Status == S_OK)
  676. {
  677. SetString(WSP_GLOBAL_SYMBOL_PATH, Path);
  678. }
  679. Status = g_pUiSymbols->GetImagePath(Path, sizeof(Path), NULL);
  680. if (Status == S_OK)
  681. {
  682. SetString(WSP_GLOBAL_IMAGE_PATH, Path);
  683. }
  684. Status = g_pUiSymbols->GetSourcePath(Path, sizeof(Path), NULL);
  685. if (Status == S_OK)
  686. {
  687. SetString(WSP_GLOBAL_SOURCE_PATH, Path);
  688. }
  689. // Local source path is only set explicitly.
  690. }
  691. void
  692. Workspace::UpdateFilterInformation(void)
  693. {
  694. HRESULT Status;
  695. Status = g_FilterBuffer->UiLockForRead();
  696. if (Status == S_OK)
  697. {
  698. // Clear old information.
  699. Delete(WSP_GLOBAL_FILTERS, WSP_TAG_MASK);
  700. // Only save an entry if there are changes.
  701. // Minimum output is a newline and terminator so
  702. // don't count those.
  703. if (g_FilterWspCmdsOffset < g_FilterBuffer->GetDataLen() - 2)
  704. {
  705. PSTR Cmds = (PSTR)g_FilterBuffer->GetDataBuffer() +
  706. g_FilterWspCmdsOffset;
  707. SetString(WSP_GLOBAL_FILTERS, Cmds);
  708. }
  709. UnlockStateBuffer(g_FilterBuffer);
  710. }
  711. }
  712. void
  713. Workspace::UpdateMruListInformation(void)
  714. {
  715. ULONG Size;
  716. WSP_ENTRY* Entry;
  717. // Clear old information.
  718. Delete(WSP_GLOBAL_MRU_LIST, WSP_TAG_MASK);
  719. Size = GetMruSize();
  720. Entry = Set(WSP_GLOBAL_MRU_LIST, Size);
  721. if (Entry != NULL)
  722. {
  723. WriteMru(WSP_ENTRY_DATA(PUCHAR, Entry));
  724. }
  725. }
  726. void
  727. Workspace::UpdateAliasInformation(void)
  728. {
  729. HRESULT Status;
  730. Status = g_AliasBuffer->UiLockForRead();
  731. if (Status == S_OK)
  732. {
  733. // Clear old information.
  734. Delete(WSP_GLOBAL_ALIASES, WSP_TAG_MASK);
  735. // Only save an entry if there are changes.
  736. // Minimum output is a newline and terminator so
  737. // don't count those.
  738. if (g_AliasBuffer->GetDataLen() > 2)
  739. {
  740. SetString(WSP_GLOBAL_ALIASES,
  741. (PSTR)g_AliasBuffer->GetDataBuffer());
  742. }
  743. UnlockStateBuffer(g_AliasBuffer);
  744. }
  745. }
  746. HRESULT
  747. Workspace::WriteToReg(void)
  748. {
  749. // Writing always occurs to the primary key.
  750. HKEY RegKey = OpenKey(TRUE, m_Key, TRUE);
  751. if (RegKey == NULL)
  752. {
  753. return E_FAIL;
  754. }
  755. LONG Status = RegSetValueEx(RegKey, m_Value, 0, REG_BINARY,
  756. m_Data, m_DataUsed);
  757. RegCloseKey(RegKey);
  758. if (Status != ERROR_SUCCESS)
  759. {
  760. return HRESULT_FROM_WIN32(Status);
  761. }
  762. else
  763. {
  764. m_Flags &= ~WSPF_DIRTY_ALL;
  765. return S_OK;
  766. }
  767. }
  768. HRESULT
  769. Workspace::WriteToFile(void)
  770. {
  771. HRESULT Status;
  772. HANDLE File;
  773. File = CreateFile(m_Value, GENERIC_WRITE, 0,
  774. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  775. if (!File || File == INVALID_HANDLE_VALUE)
  776. {
  777. return WIN32_LAST_STATUS();
  778. }
  779. DWORD Done;
  780. if (!WriteFile(File, m_Data, m_DataUsed, &Done, NULL) ||
  781. Done != m_DataUsed)
  782. {
  783. Status = WIN32_LAST_STATUS();
  784. }
  785. else
  786. {
  787. m_Flags &= ~WSPF_DIRTY_ALL;
  788. Status = S_OK;
  789. }
  790. CloseHandle(File);
  791. return Status;
  792. }
  793. void
  794. Workspace::DeleteReg(BOOL Primary)
  795. {
  796. DeleteRegKey(Primary, m_Key, m_Value);
  797. // We don't want to leave any dirty bits
  798. // on because the workspace would just be written
  799. // out again at the next flush.
  800. m_Flags &= ~WSPF_DIRTY_ALL;
  801. }
  802. void
  803. Workspace::DeleteRegKey(BOOL Primary, ULONG Key, PTSTR Value)
  804. {
  805. HKEY RegKey = OpenKey(Primary, Key, FALSE);
  806. if (RegKey != NULL)
  807. {
  808. RegDeleteValue(RegKey, Value);
  809. RegCloseKey(RegKey);
  810. }
  811. }
  812. HRESULT
  813. Workspace::Flush(BOOL ForceSave, BOOL Cancellable)
  814. {
  815. if (getenv("WINDBG_NO_WORKSPACE_WINDOWS") != NULL)
  816. {
  817. // Window layout saving is suppressed so don't
  818. // consider them dirty.
  819. m_Flags &= ~WSPF_DIRTY_WINDOWS;
  820. }
  821. if ((m_Flags & WSPF_DIRTY_ALL) == 0 ||
  822. (g_QuietMode == QMODE_ALWAYS_NO && !ForceSave))
  823. {
  824. return S_OK;
  825. }
  826. #ifdef DBG_WSP
  827. DebugPrint("Workspace dirty flags %X\n", m_Flags & WSPF_DIRTY_ALL);
  828. #endif
  829. int Answer;
  830. if (g_QuietMode == QMODE_ALWAYS_YES || ForceSave)
  831. {
  832. Answer = IDOK;
  833. }
  834. else
  835. {
  836. Answer = QuestionBox(STR_Save_Workspace,
  837. Cancellable ? MB_YESNOCANCEL : MB_YESNO,
  838. GetName(FALSE));
  839. }
  840. if (Answer == IDNO)
  841. {
  842. return S_OK;
  843. }
  844. else if (Answer == IDCANCEL)
  845. {
  846. Assert(Cancellable);
  847. return S_FALSE;
  848. }
  849. if (m_Flags & WSPF_DIRTY_BREAKPOINTS)
  850. {
  851. UpdateBreakpointInformation();
  852. }
  853. if (m_Flags & WSPF_DIRTY_WINDOWS)
  854. {
  855. UpdateWindowInformation();
  856. }
  857. if (m_Flags & WSPF_DIRTY_LOG_FILE)
  858. {
  859. UpdateLogFileInformation();
  860. }
  861. if (m_Flags & WSPF_DIRTY_PATHS)
  862. {
  863. UpdatePathInformation();
  864. }
  865. if (m_Flags & WSPF_DIRTY_FILTERS)
  866. {
  867. UpdateFilterInformation();
  868. }
  869. if (m_Flags & WSPF_DIRTY_MRU_LIST)
  870. {
  871. UpdateMruListInformation();
  872. }
  873. if (m_Flags & WSPF_DIRTY_ALIASES)
  874. {
  875. UpdateAliasInformation();
  876. }
  877. if (m_Key == WSP_NAME_FILE)
  878. {
  879. return WriteToFile();
  880. }
  881. else
  882. {
  883. return WriteToReg();
  884. }
  885. }
  886. WSP_ENTRY*
  887. Workspace::AllocateEntry(ULONG FullSize)
  888. {
  889. // Sizes must fit in USHORTs. This shouldn't be
  890. // a big problem since workspaces shouldn't have
  891. // huge data items in them.
  892. if (FullSize > 0xffff)
  893. {
  894. return NULL;
  895. }
  896. if (m_DataUsed + FullSize > m_DataLen)
  897. {
  898. ULONG NewLen = m_DataLen;
  899. do
  900. {
  901. NewLen += WSP_GROW_BY;
  902. }
  903. while (m_DataUsed + FullSize > NewLen);
  904. PUCHAR NewData = (PUCHAR)realloc(m_Data, NewLen);
  905. if (NewData == NULL)
  906. {
  907. return NULL;
  908. }
  909. m_Data = NewData;
  910. m_DataLen = NewLen;
  911. }
  912. WSP_ENTRY* Entry = (WSP_ENTRY*)(m_Data + m_DataUsed);
  913. m_DataUsed += FullSize;
  914. return Entry;
  915. }
  916. void
  917. Workspace::GetKeyName(ULONG Key, PSTR KeyName)
  918. {
  919. _tcscpy(KeyName, WSP_REG_KEY);
  920. if (Key > WSP_NAME_BASE)
  921. {
  922. _tcscat(KeyName, "\\");
  923. _tcscat(KeyName, g_WorkspaceKeyNames[Key]);
  924. }
  925. }
  926. HKEY
  927. Workspace::OpenKey(BOOL Primary, ULONG Key, BOOL Create)
  928. {
  929. TCHAR KeyName[MAX_PATH];
  930. HKEY RegKey;
  931. HKEY Base = Primary ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
  932. GetKeyName(Key, KeyName);
  933. if (Create)
  934. {
  935. if (RegCreateKeyEx(Base, KeyName, 0, NULL, 0,
  936. KEY_ALL_ACCESS, NULL, &RegKey,
  937. NULL) == ERROR_SUCCESS)
  938. {
  939. return RegKey;
  940. }
  941. }
  942. else if (RegOpenKeyEx(Base, KeyName, 0, KEY_ALL_ACCESS,
  943. &RegKey) == ERROR_SUCCESS)
  944. {
  945. return RegKey;
  946. }
  947. return NULL;
  948. }
  949. int
  950. Workspace::Apply(ULONG Flags)
  951. {
  952. WSP_ENTRY* Entry;
  953. PUCHAR Data;
  954. BOOL UpdateColors = FALSE;
  955. int SessionStarts;
  956. ULONG MemWins = 0;
  957. RegisterNamesStateBuffer* NameBuf;
  958. #ifdef DBG_WSP
  959. DebugPrint("Applying workspace %s%s%s with:\n",
  960. m_Key == NULL ? "" : m_Key,
  961. m_Key == NULL ? "" : "\\",
  962. m_Value);
  963. #endif
  964. //
  965. // Scan for explicit session start entries first.
  966. // If any are present and a session is active
  967. // fail the apply before anything actually happens.
  968. //
  969. if ((Flags & (WSP_APPLY_AGAIN |
  970. WSP_APPLY_EXPLICIT)) == WSP_APPLY_EXPLICIT &&
  971. g_EngineThreadId)
  972. {
  973. Entry = NULL;
  974. while ((Entry = NextEntry(Entry)) != NULL)
  975. {
  976. switch(Entry->Tag)
  977. {
  978. case WSP_GLOBAL_EXE_COMMAND_LINE:
  979. case WSP_GLOBAL_DUMP_FILE_NAME:
  980. case WSP_GLOBAL_ATTACH_KERNEL_FLAGS:
  981. return -1;
  982. }
  983. }
  984. }
  985. SessionStarts = 0;
  986. Entry = NULL;
  987. while ((Entry = NextEntry(Entry)) != NULL)
  988. {
  989. #ifdef DBG_WSP
  990. DebugPrint(" %04X: Tag: %08X Size %X:%X\n",
  991. (PUCHAR)Entry - m_Data, Entry->Tag,
  992. Entry->DataSize, Entry->FullSize);
  993. #endif
  994. // If this is a reapply only a subset of the
  995. // workspace is applied to prevent duplication
  996. // and problems.
  997. if ((Flags & WSP_APPLY_AGAIN) &&
  998. Entry->Tag != WSP_GLOBAL_BREAKPOINTS &&
  999. Entry->Tag != WSP_GLOBAL_REGISTER_MAP)
  1000. {
  1001. continue;
  1002. }
  1003. if (WSP_TAG_GROUP(Entry->Tag) == WSP_GROUP_COLORS)
  1004. {
  1005. if (SetColor(WSP_TAG_ITEM(Entry->Tag),
  1006. *WSP_ENTRY_DATA(COLORREF*, Entry)))
  1007. {
  1008. UpdateColors = TRUE;
  1009. }
  1010. continue;
  1011. }
  1012. switch(Entry->Tag)
  1013. {
  1014. case WSP_GLOBAL_SYMBOL_PATH:
  1015. g_pUiSymbols->SetSymbolPath(WSP_ENTRY_DATA(PSTR, Entry));
  1016. break;
  1017. case WSP_GLOBAL_IMAGE_PATH:
  1018. g_pUiSymbols->SetImagePath(WSP_ENTRY_DATA(PSTR, Entry));
  1019. break;
  1020. case WSP_GLOBAL_SOURCE_PATH:
  1021. g_pUiSymbols->SetSourcePath(WSP_ENTRY_DATA(PSTR, Entry));
  1022. break;
  1023. case WSP_GLOBAL_WINDOW_OPTIONS:
  1024. g_WinOptions = *WSP_ENTRY_DATA(PULONG, Entry);
  1025. if (g_WinOptions & WOPT_AUTO_ARRANGE)
  1026. {
  1027. Arrange();
  1028. }
  1029. break;
  1030. case WSP_GLOBAL_REGISTER_MAP:
  1031. NameBuf = GetRegisterNames(g_ActualProcType);
  1032. if (NameBuf)
  1033. {
  1034. NameBuf->SetRegisterMap(Entry->DataSize / sizeof(USHORT),
  1035. WSP_ENTRY_DATA(PUSHORT, Entry));
  1036. }
  1037. break;
  1038. case WSP_GLOBAL_PROC_REGISTER_MAP:
  1039. NameBuf = GetRegisterNames(*WSP_ENTRY_DATA(PULONG, Entry));
  1040. if (NameBuf)
  1041. {
  1042. NameBuf->SetRegisterMap((Entry->DataSize - sizeof(ULONG)) /
  1043. sizeof(USHORT),
  1044. (PUSHORT)(WSP_ENTRY_DATA(PULONG,
  1045. Entry) + 1));
  1046. }
  1047. break;
  1048. case WSP_GLOBAL_PROC_FLAGS_REGISTER_MAP:
  1049. NameBuf = GetRegisterNames(*WSP_ENTRY_DATA(PULONG, Entry));
  1050. if (NameBuf)
  1051. {
  1052. NameBuf->m_Flags = *(WSP_ENTRY_DATA(PULONG, Entry) + 1);
  1053. NameBuf->SetRegisterMap((Entry->DataSize - sizeof(ULONG)) /
  1054. sizeof(USHORT),
  1055. (PUSHORT)(WSP_ENTRY_DATA(PULONG,
  1056. Entry) + 2));
  1057. }
  1058. break;
  1059. case WSP_GLOBAL_BREAKPOINTS:
  1060. Assert(Entry->DataSize > 1);
  1061. AddStringMultiCommand(UIC_INVISIBLE_EXECUTE,
  1062. WSP_ENTRY_DATA(PSTR, Entry), FALSE);
  1063. break;
  1064. case WSP_GLOBAL_LOG_FILE:
  1065. Data = WSP_ENTRY_DATA(PUCHAR, Entry);
  1066. g_pUiControl->OpenLogFile((PSTR)Data + sizeof(BOOL), *(PBOOL)Data);
  1067. break;
  1068. case WSP_GLOBAL_LOCAL_SOURCE_PATH:
  1069. if (g_RemoteClient)
  1070. {
  1071. g_pUiLocSymbols->SetSourcePath(WSP_ENTRY_DATA(PSTR, Entry));
  1072. }
  1073. break;
  1074. case WSP_GLOBAL_FILTERS:
  1075. Assert(Entry->DataSize > 1);
  1076. AddStringMultiCommand(UIC_INVISIBLE_EXECUTE,
  1077. WSP_ENTRY_DATA(PSTR, Entry), FALSE);
  1078. break;
  1079. case WSP_GLOBAL_FIXED_LOGFONT:
  1080. g_Fonts[FONT_FIXED].LogFont = *WSP_ENTRY_DATA(LPLOGFONT, Entry);
  1081. CreateIndexedFont(FONT_FIXED, TRUE);
  1082. break;
  1083. case WSP_GLOBAL_TAB_WIDTH:
  1084. SetTabWidth(*WSP_ENTRY_DATA(PULONG, Entry));
  1085. break;
  1086. case WSP_GLOBAL_MRU_LIST:
  1087. Data = WSP_ENTRY_DATA(PUCHAR, Entry);
  1088. ReadMru(Data, Data + Entry->DataSize);
  1089. break;
  1090. case WSP_GLOBAL_REPEAT_COMMANDS:
  1091. if (*WSP_ENTRY_DATA(PULONG, Entry))
  1092. {
  1093. g_pUiControl->
  1094. RemoveEngineOptions(DEBUG_ENGOPT_NO_EXECUTE_REPEAT);
  1095. }
  1096. else
  1097. {
  1098. g_pUiControl->
  1099. AddEngineOptions(DEBUG_ENGOPT_NO_EXECUTE_REPEAT);
  1100. }
  1101. break;
  1102. case WSP_GLOBAL_COM_SETTINGS:
  1103. if (Entry->DataSize <= sizeof(g_ComSettings))
  1104. {
  1105. memcpy(g_ComSettings, WSP_ENTRY_DATA(PSTR, Entry),
  1106. Entry->DataSize);
  1107. PrintAllocString(&g_KernelConnectOptions, 256,
  1108. "com:port=%s,baud=%s", g_ComSettings,
  1109. g_ComSettings + strlen(g_ComSettings) + 1);
  1110. }
  1111. break;
  1112. case WSP_GLOBAL_1394_SETTINGS:
  1113. if (Entry->DataSize <= sizeof(g_1394Settings))
  1114. {
  1115. memcpy(g_1394Settings, WSP_ENTRY_DATA(PSTR, Entry),
  1116. Entry->DataSize);
  1117. PrintAllocString(&g_KernelConnectOptions, 256,
  1118. "1394:channel=%s", g_1394Settings);
  1119. }
  1120. break;
  1121. case WSP_GLOBAL_DISASM_ACTIVATE_SOURCE:
  1122. g_DisasmActivateSource = *WSP_ENTRY_DATA(PULONG, Entry);
  1123. break;
  1124. case WSP_GLOBAL_VIEW_TOOL_BAR:
  1125. CheckMenuItem(g_hmenuMain, IDM_VIEW_TOOLBAR,
  1126. *WSP_ENTRY_DATA(PULONG, Entry) ?
  1127. MF_CHECKED : MF_UNCHECKED);
  1128. Show_Toolbar(*WSP_ENTRY_DATA(PULONG, Entry));
  1129. break;
  1130. case WSP_GLOBAL_VIEW_STATUS_BAR:
  1131. CheckMenuItem(g_hmenuMain, IDM_VIEW_STATUS,
  1132. *WSP_ENTRY_DATA(PULONG, Entry) ?
  1133. MF_CHECKED : MF_UNCHECKED);
  1134. Show_StatusBar(*WSP_ENTRY_DATA(PULONG, Entry));
  1135. break;
  1136. case WSP_GLOBAL_AUTO_CMD_SCROLL:
  1137. g_AutoCmdScroll = *WSP_ENTRY_DATA(PULONG, Entry);
  1138. break;
  1139. case WSP_GLOBAL_SRC_FILE_PATH:
  1140. CopyString(g_SrcFilePath, WSP_ENTRY_DATA(PSTR, Entry),
  1141. DIMA(g_SrcFilePath));
  1142. break;
  1143. case WSP_GLOBAL_EXE_COMMAND_LINE:
  1144. if ((Flags & WSP_APPLY_EXPLICIT) &&
  1145. DupAllocString(&g_DebugCommandLine,
  1146. WSP_ENTRY_DATA(PSTR, Entry)))
  1147. {
  1148. SessionStarts++;
  1149. }
  1150. break;
  1151. case WSP_GLOBAL_EXE_CREATE_FLAGS:
  1152. g_DebugCreateFlags = *WSP_ENTRY_DATA(PULONG, Entry);
  1153. break;
  1154. case WSP_GLOBAL_DUMP_FILE_NAME:
  1155. if ((Flags & WSP_APPLY_EXPLICIT) &&
  1156. DupAllocString(&g_DumpFiles[0],
  1157. WSP_ENTRY_DATA(PSTR, Entry)))
  1158. {
  1159. g_NumDumpFiles = 1;
  1160. SessionStarts++;
  1161. }
  1162. break;
  1163. case WSP_GLOBAL_ATTACH_KERNEL_FLAGS:
  1164. if ((Flags & WSP_APPLY_EXPLICIT))
  1165. {
  1166. g_AttachKernelFlags = *WSP_ENTRY_DATA(PULONG, Entry);
  1167. SessionStarts++;
  1168. }
  1169. break;
  1170. case WSP_GLOBAL_TYPE_OPTIONS:
  1171. {
  1172. g_TypeOptions = *WSP_ENTRY_DATA(PULONG, Entry);
  1173. if (g_pUiSymbols2 != NULL)
  1174. {
  1175. g_pUiSymbols2->SetTypeOptions(g_TypeOptions);
  1176. }
  1177. }
  1178. break;
  1179. case WSP_GLOBAL_DUMP_FILE_PATH:
  1180. CopyString(g_DumpFilePath, WSP_ENTRY_DATA(PSTR, Entry),
  1181. DIMA(g_DumpFilePath));
  1182. break;
  1183. case WSP_GLOBAL_EXE_FILE_PATH:
  1184. CopyString(g_ExeFilePath, WSP_ENTRY_DATA(PSTR, Entry),
  1185. DIMA(g_ExeFilePath));
  1186. break;
  1187. case WSP_GLOBAL_ASSEMBLY_OPTIONS:
  1188. if (g_pUiControl3)
  1189. {
  1190. g_pUiControl3->
  1191. SetAssemblyOptions(*WSP_ENTRY_DATA(PULONG, Entry));
  1192. }
  1193. break;
  1194. case WSP_GLOBAL_EXPRESSION_SYNTAX:
  1195. if (g_pUiControl3)
  1196. {
  1197. g_pUiControl3->
  1198. SetExpressionSyntax(*WSP_ENTRY_DATA(PULONG, Entry));
  1199. }
  1200. break;
  1201. case WSP_GLOBAL_ALIASES:
  1202. Assert(Entry->DataSize > 1);
  1203. AddStringMultiCommand(UIC_INVISIBLE_EXECUTE,
  1204. WSP_ENTRY_DATA(PSTR, Entry), TRUE);
  1205. break;
  1206. case WSP_GLOBAL_PROCESS_START_DIR:
  1207. if (Flags & WSP_APPLY_EXPLICIT)
  1208. {
  1209. DupAllocString(&g_ProcessStartDir,
  1210. WSP_ENTRY_DATA(PSTR, Entry));
  1211. }
  1212. break;
  1213. case WSP_WINDOW_COMMONWIN_1:
  1214. WSP_COMMONWIN_HEADER* Hdr;
  1215. HWND Win;
  1216. PCOMMONWIN_DATA WinData;
  1217. Hdr = WSP_ENTRY_DATA(WSP_COMMONWIN_HEADER*, Entry);
  1218. Win = New_OpenDebugWindow(Hdr->Type, TRUE, MemWins);
  1219. if (Win != NULL &&
  1220. (WinData = GetCommonWinData(Win)) != NULL &&
  1221. Entry->DataSize > sizeof(WSP_COMMONWIN_HEADER))
  1222. {
  1223. Data = (PUCHAR)(Hdr + 1);
  1224. WinData->m_InAutoOp++;
  1225. WinData->ApplyWorkspace1(Data, Data +
  1226. (Entry->DataSize -
  1227. sizeof(WSP_COMMONWIN_HEADER)));
  1228. WinData->m_InAutoOp--;
  1229. }
  1230. // A user can have as many open memory windows as
  1231. // they like, which makes things a little tricky
  1232. // for workspaces as applying stacked workspaces
  1233. // could result in memory windows multiplying out
  1234. // of control if the same set of memory windows
  1235. // is saved in each workspace level. To avoid
  1236. // this and to function more like the other windows
  1237. // we reuse memory windows from any that are
  1238. // already in existence.
  1239. if (Hdr->Type == MEM_WINDOW)
  1240. {
  1241. MemWins++;
  1242. }
  1243. break;
  1244. case WSP_WINDOW_FRAME_PLACEMENT:
  1245. LPWINDOWPLACEMENT Place;
  1246. Place = WSP_ENTRY_DATA(LPWINDOWPLACEMENT, Entry);
  1247. SetWindowPlacement(g_hwndFrame, Place);
  1248. break;
  1249. case WSP_WINDOW_FRAME_TITLE:
  1250. SetTitleExplicitText(WSP_ENTRY_DATA(PSTR, Entry));
  1251. break;
  1252. }
  1253. }
  1254. if (UpdateColors)
  1255. {
  1256. UpdateAllColors();
  1257. }
  1258. return SessionStarts;
  1259. }
  1260. HRESULT
  1261. UiSwitchWorkspace(ULONG Key, PTSTR Value, WSP_CREATE_OPTION Create,
  1262. ULONG Flags, int* SessionStarts)
  1263. {
  1264. if (getenv("WINDBG_NO_WORKSPACE") != NULL)
  1265. {
  1266. return E_NOTIMPL;
  1267. }
  1268. HRESULT Status;
  1269. Workspace* OldWsp;
  1270. Workspace* NewWsp;
  1271. int Starts = 0;
  1272. Status = Workspace::Read(Key, Value, &NewWsp);
  1273. if (Status != S_OK)
  1274. {
  1275. if (Status == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) &&
  1276. Create != WSP_OPEN_EXISTING)
  1277. {
  1278. if (Create == WSP_CREATE_QUERY)
  1279. {
  1280. if (QuestionBox(STR_Create_New_Workspace, MB_OKCANCEL) != IDOK)
  1281. {
  1282. return Status;
  1283. }
  1284. }
  1285. // Workspace does not exist so create a new one.
  1286. Status = Workspace::Create(Key, Value, &NewWsp);
  1287. }
  1288. if (Status != S_OK)
  1289. {
  1290. return Status;
  1291. }
  1292. }
  1293. // We have a new workspace ready to go so flush the old one.
  1294. OldWsp = g_Workspace;
  1295. if (OldWsp != NULL)
  1296. {
  1297. OldWsp->Flush(FALSE, FALSE);
  1298. }
  1299. // Apply the new workspace with no global workspace to
  1300. // avoid writing changes into the workspace as we apply it.
  1301. g_Workspace = NULL;
  1302. if (NewWsp != NULL)
  1303. {
  1304. Starts = NewWsp->Apply(Flags);
  1305. // Clear any window messages queued during the workspace
  1306. // application so that they're processed with no
  1307. // active workspace.
  1308. ProcessPendingMessages();
  1309. }
  1310. if (SessionStarts != NULL)
  1311. {
  1312. *SessionStarts = Starts;
  1313. }
  1314. if (Starts < 0)
  1315. {
  1316. // Apply failed so put the old workspace back.
  1317. g_Workspace = OldWsp;
  1318. return E_FAIL;
  1319. }
  1320. else
  1321. {
  1322. // Apply succeeded to replace the old workspace.
  1323. g_Workspace = NewWsp;
  1324. delete OldWsp;
  1325. return S_OK;
  1326. }
  1327. }
  1328. void
  1329. UiSwitchToExplicitWorkspace(ULONG Key, PTSTR Value)
  1330. {
  1331. HRESULT Status;
  1332. int Starts = 0;
  1333. if ((Status = UiSwitchWorkspace(Key, Value, WSP_OPEN_EXISTING,
  1334. WSP_APPLY_EXPLICIT, &Starts)) != S_OK)
  1335. {
  1336. if (Starts < 0)
  1337. {
  1338. InformationBox(ERR_Workspace_Session_Conflict);
  1339. }
  1340. else
  1341. {
  1342. InformationBox(ERR_Cant_Open_Workspace,
  1343. FormatStatusCode(Status),
  1344. FormatStatus(Status));
  1345. }
  1346. }
  1347. else
  1348. {
  1349. g_ExplicitWorkspace = TRUE;
  1350. if (Starts == 1)
  1351. {
  1352. StartDebugging();
  1353. }
  1354. }
  1355. }
  1356. void
  1357. UiSaveWorkspaceAs(ULONG Key, PTSTR Value)
  1358. {
  1359. HRESULT Status;
  1360. Status = g_Workspace->ChangeName(Key, Value, FALSE);
  1361. if (Status == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
  1362. {
  1363. if (QuestionBox(ERR_Workspace_Already_Exists, MB_YESNO, Value) == IDNO)
  1364. {
  1365. return;
  1366. }
  1367. Status = g_Workspace->ChangeName(Key, Value, TRUE);
  1368. }
  1369. if (Status != S_OK)
  1370. {
  1371. InformationBox(ERR_Cant_Save_Workspace,
  1372. FormatStatusCode(Status), FormatStatus(Status));
  1373. return;
  1374. }
  1375. g_Workspace->Flush(TRUE, FALSE);
  1376. g_ExplicitWorkspace = TRUE;
  1377. }
  1378. HRESULT
  1379. UiDelayedSwitchWorkspace(void)
  1380. {
  1381. Assert(!g_WspSwitchBufferAvailable);
  1382. HRESULT Status = UiSwitchWorkspace(g_WspSwitchKey, g_WspSwitchValue,
  1383. WSP_CREATE_ALWAYS, WSP_APPLY_DEFAULT,
  1384. NULL);
  1385. // Mark the delayed switch buffer as available and
  1386. // wait for acknowledgement.
  1387. g_WspSwitchBufferAvailable = TRUE;
  1388. while (g_WspSwitchValue[0])
  1389. {
  1390. Sleep(10);
  1391. }
  1392. return Status;
  1393. }
  1394. void
  1395. EngSwitchWorkspace(ULONG Key, PTSTR Value)
  1396. {
  1397. // If the user explicitly selected a workspace
  1398. // don't override it due to engine activity.
  1399. if (g_ExplicitWorkspace ||
  1400. g_Exit)
  1401. {
  1402. return;
  1403. }
  1404. // We can't switch workspaces on the engine thread
  1405. // because of the UI work involved. Send the
  1406. // switch over to the UI thread and wait for
  1407. // it to be processed.
  1408. Assert(g_WspSwitchBufferAvailable);
  1409. g_WspSwitchBufferAvailable = FALSE;
  1410. g_WspSwitchKey = Key;
  1411. CopyString(g_WspSwitchValue, Value, DIMA(g_WspSwitchValue));
  1412. PostMessage(g_hwndFrame, WU_SWITCH_WORKSPACE, 0, 0);
  1413. if (g_pDbgClient != NULL)
  1414. {
  1415. // Temporarily disable event callbacks to keep
  1416. // activity at a minimum while we're in this halfway state.
  1417. g_pDbgClient->SetEventCallbacks(NULL);
  1418. while (!g_WspSwitchBufferAvailable)
  1419. {
  1420. if (FAILED(g_pDbgClient->DispatchCallbacks(10)))
  1421. {
  1422. Sleep(10);
  1423. }
  1424. }
  1425. g_pDbgClient->SetEventCallbacks(&g_EventCb);
  1426. }
  1427. else
  1428. {
  1429. while (!g_WspSwitchBufferAvailable)
  1430. {
  1431. Sleep(10);
  1432. }
  1433. }
  1434. // We know that at this point the new workspace cannot be dirty
  1435. // so just clear the dirty flags.
  1436. if (g_Workspace)
  1437. {
  1438. g_Workspace->ClearDirty();
  1439. }
  1440. // Let the UI thread continue.
  1441. g_WspSwitchKey = WSP_NAME_BASE;
  1442. g_WspSwitchValue[0] = 0;
  1443. Sleep(50);
  1444. //
  1445. // Warn the user is the workspace was not be created properly.
  1446. //
  1447. if (!g_Workspace)
  1448. {
  1449. InformationBox(ERR_NULL_Workspace, NULL);
  1450. return;
  1451. }
  1452. }
  1453. PSTR g_WspGlobalNames[] =
  1454. {
  1455. "Symbol path", "Image path", "Source path", "Window menu checks",
  1456. "Register customization", "Breakpoints", "Log file settings",
  1457. "Local source path", "Event filter settings", "Fixed-width font",
  1458. "Tab width", "MRU list", "Repeat commands setting", "COM port settings",
  1459. "1394 settings", "Activate source windows in disassembly mode",
  1460. "Show tool bar", "Show status bar", "Automatically scroll command window",
  1461. "Source open dialog path", "Executable command line",
  1462. "Executable create flags", "Dump file name", "Kernel attach flags",
  1463. "Type options", "Dump open dialog path", "Executable open dialog path",
  1464. "Per-processor register customization", "Assembly/disassembly options",
  1465. "Expression evaluator syntax", "Command window text aliases",
  1466. "Executable start directory", "Per-processor register customization",
  1467. };
  1468. PSTR g_WspWindowNames[] =
  1469. {
  1470. "Child window settings", "WinDBG window settings", "WinDBG window title",
  1471. };
  1472. PSTR
  1473. GetWspTagName(WSP_TAG Tag)
  1474. {
  1475. ULONG Item = WSP_TAG_ITEM(Tag);
  1476. static char Buffer[128];
  1477. switch(WSP_TAG_GROUP(Tag))
  1478. {
  1479. case WSP_GROUP_GLOBAL:
  1480. if (Item < WSP_GLOBAL_COUNT)
  1481. {
  1482. C_ASSERT(DIMA(g_WspGlobalNames) == WSP_GLOBAL_COUNT);
  1483. return g_WspGlobalNames[Item];
  1484. }
  1485. break;
  1486. case WSP_GROUP_WINDOW:
  1487. if (Item < WSP_WINDOW_COUNT)
  1488. {
  1489. C_ASSERT(DIMA(g_WspWindowNames) == WSP_WINDOW_COUNT);
  1490. return g_WspWindowNames[Item];
  1491. }
  1492. break;
  1493. case WSP_GROUP_COLORS:
  1494. INDEXED_COLOR* IdxCol = GetIndexedColor(Item);
  1495. if (IdxCol != NULL)
  1496. {
  1497. sprintf(Buffer, "%s color", IdxCol->Name);
  1498. return Buffer;
  1499. }
  1500. break;
  1501. }
  1502. return "Unknown tag";
  1503. }