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.

1794 lines
45 KiB

  1. /*++
  2. Copyright (c) 1999-2002 Microsoft Corporation
  3. Module Name:
  4. util.cpp
  5. --*/
  6. #include "precomp.hxx"
  7. #pragma hdrstop
  8. //Current Help Id for Open, Merge, Save and Open project dialog box
  9. WORD g_CurHelpId;
  10. // Number of dialog/message boxes currently open
  11. int g_nBoxCount;
  12. BOOL g_fNoPopups;
  13. HWND
  14. MDIGetActive(
  15. HWND hwndParent,
  16. BOOL *lpbMaximized
  17. )
  18. /*++
  19. Routine Description:
  20. Create the command window.
  21. Arguments:
  22. hwndParent - The parent window to the command window. In an MDI document,
  23. this is usually the handle to the MDI client window: g_hwndMDIClient
  24. Return Value:
  25. The return value is the handle to the active MDI child window.
  26. NULL if no MDI window has been created.
  27. --*/
  28. {
  29. Assert(IsWindow(hwndParent));
  30. return (HWND)SendMessage(hwndParent,
  31. WM_MDIGETACTIVE,
  32. 0,
  33. (LPARAM)lpbMaximized
  34. );
  35. }
  36. /*** hGetBoxParent
  37. **
  38. ** Synopsis:
  39. ** hwnd = hGetBoxParent()
  40. **
  41. ** Entry:
  42. ** none
  43. **
  44. ** Returns:
  45. **
  46. ** Description:
  47. ** Gets a suitable parent window handle for an
  48. ** invocation of a message or dialog box.
  49. ** Helper function to util.c functions so declared
  50. ** near.
  51. **
  52. */
  53. HWND
  54. hGetBoxParent()
  55. {
  56. HWND hCurWnd;
  57. int i = 0;
  58. hCurWnd = GetFocus();
  59. if (hCurWnd)
  60. {
  61. while (GetWindowLong(hCurWnd, GWL_STYLE) & WS_CHILD)
  62. {
  63. hCurWnd = GetParent(hCurWnd);
  64. Dbg((++i < 100));
  65. }
  66. }
  67. else
  68. {
  69. hCurWnd = g_hwndFrame;
  70. }
  71. return hCurWnd;
  72. }
  73. /****************************************************************************
  74. FUNCTION: MsgBox
  75. PURPOSE: General purpose message box routine which takes
  76. a pointer to the message text. Provides
  77. program title as caption.
  78. ****************************************************************************/
  79. int
  80. MsgBox(
  81. HWND hwndParent,
  82. PTSTR szText,
  83. UINT wType
  84. )
  85. /*++
  86. Routine Description:
  87. Generial purpose message box routine which takes a pointer to a message
  88. text and prvoides the program title for the caption of the message box.
  89. Arguments:
  90. hwndParament - Supplies the parent window handle for the message box
  91. szText - Supplies a pointer to the message box text.
  92. wType - Supplies the message box type (to specify buttons)
  93. Return Value:
  94. Returns the message box return code
  95. --*/
  96. {
  97. int MsgBoxRet = IDOK;
  98. if (g_fNoPopups)
  99. {
  100. //
  101. // log the string to the command win in case testing
  102. // or when the remote server is running
  103. //
  104. CmdLogFmt (_T("%s\r\n"), szText);
  105. }
  106. else
  107. {
  108. // If windbg is minimized we need to restore
  109. // it so that the message box shows up.
  110. if (hwndParent == g_hwndFrame && IsIconic(hwndParent))
  111. {
  112. ShowWindow(hwndParent, SW_RESTORE);
  113. }
  114. g_nBoxCount++;
  115. MsgBoxRet = MessageBox(hwndParent, szText,
  116. g_MainTitleText, wType);
  117. g_nBoxCount--;
  118. }
  119. return MsgBoxRet;
  120. } /* MsgBox() */
  121. /*** ErrorBox
  122. **
  123. ** Returns:
  124. ** FALSE
  125. **
  126. ** Description:
  127. ** Display an error message box with an "Error" title, an OK
  128. ** button and a Exclamation Icon. First parameter is a
  129. ** reference string in the ressource file. The string
  130. ** can contain printf formatting chars, the arguments
  131. ** follow from the second parameter onwards.
  132. **
  133. */
  134. BOOL
  135. ErrorBox(
  136. HWND hwnd,
  137. UINT type,
  138. int wErrorFormat,
  139. ...
  140. )
  141. {
  142. TCHAR szErrorFormat[MAX_MSG_TXT];
  143. TCHAR szErrorText[MAX_VAR_MSG_TXT]; // size is as big as considered necessary
  144. va_list vargs;
  145. // load format string from resource file
  146. Dbg(LoadString(g_hInst, wErrorFormat, (PTSTR)szErrorFormat, MAX_MSG_TXT));
  147. va_start(vargs, wErrorFormat);
  148. _vstprintf(szErrorText, szErrorFormat, vargs);
  149. va_end(vargs);
  150. if (hwnd == NULL)
  151. {
  152. hwnd = g_hwndFrame;
  153. }
  154. if (type == 0)
  155. {
  156. type = MB_TASKMODAL;
  157. }
  158. MsgBox(g_hwndFrame, (PTSTR)szErrorText, type | MB_OK | MB_ICONINFORMATION);
  159. return FALSE; //Keep it always FALSE please
  160. }
  161. /*** InformationBox
  162. **
  163. ** Description:
  164. ** Display an information message box with an "Information"
  165. ** title, an OK button and an Information Icon.
  166. **
  167. */
  168. void
  169. InformationBox(
  170. WORD wDescript
  171. ...
  172. )
  173. {
  174. TCHAR szFormat[MAX_MSG_TXT];
  175. TCHAR szText[MAX_VAR_MSG_TXT]; // size is as big as considered necessary
  176. va_list vargs;
  177. // load format string from resource file
  178. Dbg(LoadString(g_hInst, wDescript, (PTSTR)szFormat, MAX_MSG_TXT));
  179. // set up szText from passed parameters
  180. va_start(vargs, wDescript);
  181. _vstprintf(szText, szFormat, vargs);
  182. va_end(vargs);
  183. MsgBox(g_hwndFrame, (PTSTR)szText, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
  184. return;
  185. }
  186. /*** QuestionBox
  187. **
  188. ** Synopsis:
  189. ** int = QuestionBox(wCaptionId, wMsgFormat, wType, ...)
  190. **
  191. ** Entry:
  192. **
  193. ** Returns:
  194. ** The result of the message box call
  195. **
  196. ** Description:
  197. ** Display an query box with combination of YES, NO and
  198. ** CANCEL buttons and a question mark Icon.
  199. ** See ErrorBox for discussion.
  200. **
  201. */
  202. int
  203. CDECL
  204. QuestionBox(
  205. WORD wMsgFormat,
  206. UINT wType,
  207. ...
  208. )
  209. {
  210. TCHAR szMsgFormat[MAX_MSG_TXT];
  211. TCHAR szMsgText[MAX_VAR_MSG_TXT];
  212. va_list vargs;
  213. //Load format string from resource file
  214. Dbg(LoadString(g_hInst, wMsgFormat, (PTSTR)szMsgFormat, MAX_MSG_TXT));
  215. //Set up szMsgText from passed parameters
  216. va_start(vargs, wType);
  217. _vstprintf(szMsgText, szMsgFormat, vargs);
  218. va_end(vargs);
  219. return MsgBox(g_hwndFrame, szMsgText,
  220. wType | MB_ICONEXCLAMATION | MB_TASKMODAL);
  221. } /* QuestionBox() */
  222. /****************************************************************************
  223. FUNCTION: QuestionBox2
  224. PURPOSE: Display an query box with combination of YES, NO and
  225. CANCEL buttons and a question mark Icon. The type and
  226. the parent window are adjustable.
  227. RETURNS: MessageBox result
  228. ****************************************************************************/
  229. int
  230. CDECL
  231. QuestionBox2(
  232. HWND hwnd,
  233. WORD wMsgFormat,
  234. UINT wType,
  235. ...
  236. )
  237. {
  238. TCHAR szMsgFormat[MAX_MSG_TXT];
  239. TCHAR szMsgText[MAX_VAR_MSG_TXT];
  240. va_list vargs;
  241. //Load format string from resource file
  242. Dbg(LoadString(g_hInst, wMsgFormat, (PTSTR)szMsgFormat, MAX_MSG_TXT));
  243. //Set up szMsgText from passed parameters
  244. va_start(vargs, wType);
  245. _vstprintf(szMsgText, szMsgFormat, vargs);
  246. va_end(vargs);
  247. return MsgBox(hwnd, szMsgText, wType | MB_ICONEXCLAMATION);
  248. } /* QuestionBox2() */
  249. /*** ShowAssert
  250. **
  251. ** Synopsis:
  252. ** void = ShowAssert(szCond, iLine, szFile)
  253. **
  254. ** Entry:
  255. ** szCond - tokenized form of the failed condition
  256. ** iLine - Line number for the assertion
  257. ** szFile - File for the assertion
  258. **
  259. ** Returns:
  260. ** void
  261. **
  262. ** Description:
  263. ** Prepare and display a Message Box with szCondition, iLine and
  264. ** szFile as fields.
  265. **
  266. */
  267. void
  268. ShowAssert(
  269. PTSTR condition,
  270. UINT line,
  271. PTSTR file
  272. )
  273. {
  274. TCHAR text[MAX_VAR_MSG_TXT];
  275. //Build line, show assertion and exit program
  276. _stprintf(text, _T("- Line:%u, File:%Fs, Condition:%Fs"),
  277. (WPARAM) line, file, condition);
  278. PTSTR szAssertFile = _T("assert.wbg");
  279. HANDLE hFile = NULL;
  280. hFile = CreateFile(szAssertFile,
  281. GENERIC_WRITE,
  282. 0,
  283. NULL,
  284. CREATE_ALWAYS,
  285. FILE_ATTRIBUTE_NORMAL,
  286. NULL
  287. );
  288. if (INVALID_HANDLE_VALUE != hFile)
  289. {
  290. // Write the text out to the file
  291. DWORD dwBytesWritten = 0;
  292. Assert(WriteFile(hFile, text, _tcslen(text), &dwBytesWritten, NULL));
  293. Assert(_tcslen(text) == dwBytesWritten);
  294. CloseHandle(hFile);
  295. }
  296. int Action =
  297. MessageBox(GetDesktopWindow(), text, "Assertion Failure",
  298. MB_ABORTRETRYIGNORE);
  299. if (Action == IDABORT)
  300. {
  301. exit(3);
  302. }
  303. else if (Action == IDRETRY)
  304. {
  305. DebugBreak();
  306. }
  307. } // ShowAssert()
  308. /*** StartDialog
  309. **
  310. ** Synopsis:
  311. ** int = StartDialog(rcDlgNb, dlgProc, lParam)
  312. **
  313. ** Entry:
  314. ** rcDlgNb - Resource number of dialog to be openned
  315. ** dlgProc - Filter procedure for the dialog
  316. ** lParam - Data passed into the dlg proc via LPARAM
  317. **
  318. ** Returns:
  319. ** Result of the dialog box call
  320. **
  321. ** Description:
  322. ** Loads and execute the dialog box 'rcDlgNb' (resource
  323. ** file string number) associated with the dialog
  324. ** function 'dlgProc'
  325. **
  326. */
  327. int
  328. StartDialog(
  329. int rcDlgNb,
  330. DLGPROC dlgProc,
  331. LPARAM lParam
  332. )
  333. {
  334. LRESULT result;
  335. //
  336. //Execute Dialog Box
  337. //
  338. g_nBoxCount++;
  339. result = DialogBoxParam(g_hInst,
  340. MAKEINTRESOURCE(rcDlgNb),
  341. hGetBoxParent(),
  342. dlgProc,
  343. lParam
  344. );
  345. Assert(result != (LRESULT)-1);
  346. g_nBoxCount--;
  347. return (int)result;
  348. }
  349. void
  350. ProcessNonDlgMessage(LPMSG Msg)
  351. {
  352. #if 0
  353. {
  354. DebugPrint("NonDlg msg %X for %p, args %X %X\n",
  355. Msg->message, Msg->hwnd, Msg->wParam, Msg->lParam);
  356. }
  357. #endif
  358. // If a keyboard message is for the MDI , let the MDI client
  359. // take care of it. Otherwise, check to see if it's a normal
  360. // accelerator key (like F3 = find next). Otherwise, just handle
  361. // the message as usual.
  362. if (!TranslateMDISysAccel(g_hwndMDIClient, Msg) &&
  363. !TranslateAccelerator(g_hwndFrame, g_hMainAccTable, Msg))
  364. {
  365. //
  366. // If this is a right-button-down over a child window,
  367. // automatically activate the window's contex menu.
  368. //
  369. if (Msg->message == WM_RBUTTONDOWN &&
  370. IsChild(g_hwndMDIClient, Msg->hwnd))
  371. {
  372. HMENU Menu;
  373. PCOMMONWIN_DATA CmnWin;
  374. POINT ScreenPt;
  375. POINT Pt = {LOWORD(Msg->lParam), HIWORD(Msg->lParam)};
  376. ClientToScreen(Msg->hwnd, &Pt);
  377. ScreenPt = Pt;
  378. ScreenToClient(g_hwndMDIClient, &Pt);
  379. HWND Win = ChildWindowFromPointEx(g_hwndMDIClient, Pt,
  380. CWP_SKIPINVISIBLE);
  381. if (Win != NULL &&
  382. (CmnWin = GetCommonWinData(Win)) != NULL &&
  383. (Menu = CmnWin->GetContextMenu()) != NULL)
  384. {
  385. UINT Item = TrackPopupMenu(Menu, TPM_LEFTALIGN | TPM_TOPALIGN |
  386. TPM_NONOTIFY | TPM_RETURNCMD |
  387. TPM_RIGHTBUTTON,
  388. ScreenPt.x, ScreenPt.y,
  389. 0, Msg->hwnd, NULL);
  390. if (Item)
  391. {
  392. CmnWin->OnContextMenuSelection(Item);
  393. }
  394. return;
  395. }
  396. }
  397. TranslateMessage(Msg);
  398. DispatchMessage(Msg);
  399. }
  400. }
  401. void
  402. ProcessPendingMessages(void)
  403. {
  404. MSG Msg;
  405. // Process all available messages.
  406. while (PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE))
  407. {
  408. if (!GetMessage(&Msg, NULL, 0, 0))
  409. {
  410. g_Exit = TRUE;
  411. break;
  412. }
  413. if (g_FindDialog == NULL ||
  414. !IsDialogMessage(g_FindDialog, &Msg))
  415. {
  416. ProcessNonDlgMessage(&Msg);
  417. }
  418. }
  419. }
  420. /****************************************************************************
  421. FUNCTION: InfoBox
  422. PURPOSE: Opens a Dialog box with a title and accepting
  423. a printf style for text. It's for DEBUGGING USE ONLY
  424. ****************************************************************************/
  425. int
  426. InfoBox(
  427. PTSTR text,
  428. ...
  429. )
  430. {
  431. TCHAR buffer[MAX_MSG_TXT];
  432. va_list vargs;
  433. va_start(vargs, text);
  434. _vstprintf(buffer, text, vargs);
  435. va_end(vargs);
  436. return MsgBox(GetActiveWindow(), buffer, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
  437. }
  438. void
  439. ExitDebugger(PDEBUG_CLIENT Client, ULONG Code)
  440. {
  441. if (Client != NULL)
  442. {
  443. if (g_RemoteClient)
  444. {
  445. // Disconnect from server.
  446. Client->EndSession(DEBUG_END_DISCONNECT);
  447. }
  448. else
  449. {
  450. Client->EndSession(DEBUG_END_PASSIVE);
  451. // Force servers to get cleaned up.
  452. Client->EndSession(DEBUG_END_REENTRANT);
  453. }
  454. }
  455. ExitProcess(Code);
  456. }
  457. // XXX drewb - Is this functionality present in other utilities?
  458. // FatalErrorBox is close. Probably can combine something here.
  459. void
  460. ErrorExit(PDEBUG_CLIENT Client, PCSTR Format, ...)
  461. {
  462. char Message[1024];
  463. va_list Args;
  464. va_start(Args, Format);
  465. _vsnprintf(Message, sizeof(Message), Format, Args);
  466. va_end(Args);
  467. // XXX drewb - Could put up message box.
  468. OutputDebugString(Message);
  469. ExitDebugger(Client, E_FAIL);
  470. }
  471. #define MAX_FORMAT_STRINGS 8
  472. LPSTR
  473. FormatAddr64(
  474. ULONG64 addr
  475. )
  476. /*++
  477. Routine Description:
  478. Format a 64 bit address, showing the high bits or not
  479. according to various flags.
  480. An array of static string buffers is used, returning a different
  481. buffer for each successive call so that it may be used multiple
  482. times in the same printf.
  483. Arguments:
  484. addr - Supplies the value to format
  485. Return Value:
  486. A pointer to the string buffer containing the formatted number
  487. --*/
  488. {
  489. static CHAR strings[MAX_FORMAT_STRINGS][20];
  490. static int next = 0;
  491. LPSTR string;
  492. string = strings[next];
  493. ++next;
  494. if (next >= MAX_FORMAT_STRINGS) {
  495. next = 0;
  496. }
  497. if (g_Ptr64) {
  498. sprintf(string, "%08x`%08x", (ULONG)(addr>>32), (ULONG)addr);
  499. } else {
  500. sprintf(string, "%08x", (ULONG)addr);
  501. }
  502. return string;
  503. }
  504. static BOOL FAddToSearchPath = FALSE;
  505. static BOOL FAddToRootMap = FALSE;
  506. /*
  507. ** AppendFilter
  508. **
  509. ** Description:
  510. ** Append a filter to an existing filters string.
  511. **
  512. */
  513. BOOL
  514. AppendFilter(
  515. WORD filterTextId,
  516. int filterExtId,
  517. PTSTR filterString,
  518. int *len,
  519. int maxLen
  520. )
  521. {
  522. int size;
  523. TCHAR Tmp[MAX_MSG_TXT];
  524. //
  525. // Append filter text
  526. //
  527. Dbg(LoadString(g_hInst, filterTextId, Tmp, MAX_MSG_TXT));
  528. size = _tcslen(Tmp) + 1;
  529. if (*len + size > maxLen)
  530. {
  531. return FALSE;
  532. }
  533. memmove(filterString + *len, Tmp, size);
  534. *len += size;
  535. //
  536. // Append filter extension
  537. //
  538. Dbg(LoadString(g_hInst, filterExtId, Tmp, MAX_MSG_TXT));
  539. size = _tcslen(Tmp) + 1;
  540. if (*len + size > maxLen)
  541. {
  542. return FALSE;
  543. }
  544. memmove(filterString + *len, Tmp, size);
  545. *len += size;
  546. return TRUE;
  547. }
  548. /*
  549. ** InitFilterString
  550. **
  551. ** Description:
  552. ** Initialize file filters for file dialog boxes.
  553. */
  554. void
  555. InitFilterString(
  556. WORD titleId,
  557. PTSTR filter,
  558. int maxLen
  559. )
  560. {
  561. int len = 0;
  562. switch (titleId)
  563. {
  564. case DLG_Browse_CrashDump_Title:
  565. AppendFilter(TYP_File_DUMP, DEF_Ext_DUMP, filter, &len, maxLen);
  566. break;
  567. case DLG_Browse_Executable_Title:
  568. AppendFilter(TYP_File_EXE, DEF_Ext_EXE, filter, &len, maxLen);
  569. break;
  570. case DLG_Browse_LogFile_Title:
  571. AppendFilter(TYP_File_LOG, DEF_Ext_LOG, filter, &len, maxLen);
  572. break;
  573. case DLG_Open_Filebox_Title:
  574. case DLG_Browse_Filebox_Title:
  575. case DLG_Browse_Source_Path_Title:
  576. AppendFilter(TYP_File_SOURCE, DEF_Ext_SOURCE, filter, &len, maxLen);
  577. AppendFilter(TYP_File_INCLUDE, DEF_Ext_INCLUDE, filter, &len, maxLen);
  578. AppendFilter(TYP_File_ASMSRC, DEF_Ext_ASMSRC, filter, &len, maxLen);
  579. AppendFilter(TYP_File_INC, DEF_Ext_INC, filter, &len, maxLen);
  580. AppendFilter(TYP_File_RC, DEF_Ext_RC, filter, &len, maxLen);
  581. AppendFilter(TYP_File_DLG, DEF_Ext_DLG, filter, &len, maxLen);
  582. AppendFilter(TYP_File_DEF, DEF_Ext_DEF, filter, &len, maxLen);
  583. AppendFilter(TYP_File_MAK, DEF_Ext_MAK, filter, &len, maxLen);
  584. break;
  585. case DLG_Browse_DbugDll_Title:
  586. AppendFilter(TYP_File_DLL, DEF_Ext_DLL, filter, &len, maxLen);
  587. break;
  588. case DLG_Browse_Symbol_Path_Title:
  589. AppendFilter(TYP_File_Symbols, DEF_Ext_Symbols, filter, &len, maxLen);
  590. AppendFilter(TYP_File_EXE, DEF_Ext_EXE, filter, &len, maxLen);
  591. AppendFilter(TYP_File_DLL, DEF_Ext_DLL, filter, &len, maxLen);
  592. break;
  593. case DLG_Browse_Image_Path_Title:
  594. AppendFilter(TYP_File_EXE, DEF_Ext_EXE, filter, &len, maxLen);
  595. AppendFilter(TYP_File_DLL, DEF_Ext_DLL, filter, &len, maxLen);
  596. break;
  597. case DLG_Write_Text_File_Title:
  598. AppendFilter(TYP_File_TXT, DEF_Ext_TXT, filter, &len, maxLen);
  599. break;
  600. case DLG_Open_Workspace_File_Title:
  601. case DLG_Save_Workspace_File_Title:
  602. AppendFilter(TYP_File_Workspace, DEF_Ext_Workspace,
  603. filter, &len, maxLen);
  604. break;
  605. default:
  606. Assert(FALSE);
  607. break;
  608. }
  609. AppendFilter(TYP_File_ALL, DEF_Ext_ALL, filter, &len, maxLen);
  610. filter[len] = _T('\0');
  611. }
  612. BOOL
  613. StartFileDlg(
  614. HWND hwnd,
  615. int titleId,
  616. int defExtId,
  617. int helpId,
  618. int templateId,
  619. PTSTR InitialDir,
  620. PTSTR fileName,
  621. DWORD* pFlags,
  622. LPOFNHOOKPROC lpfnHook
  623. )
  624. /*++
  625. Routine Description:
  626. This function is used by windbg to open the set of common file handling
  627. dialog boxes.
  628. Arguments:
  629. hwnd - Supplies the wnd to hook the dialog box to
  630. titleId - Supplies the string resource of the title
  631. defExtId - Supplies The default extension resource string
  632. helpId - Supplies the help number for the dialog box
  633. templateId - Supplies the dialog resource number if non-zero
  634. fileName - Supplies the default file name
  635. pFiles - Supplies a pointer to flags
  636. lpfnHook - Supplies the address of a hook procedure for the dialog
  637. Return Value:
  638. The result of the dialog box call (usually TRUE for OK and FALSE for
  639. cancel)
  640. --*/
  641. {
  642. #define filtersMaxSize 350
  643. OPENFILENAME_NT4 OpenFileName = {0};
  644. TCHAR title[MAX_MSG_TXT];
  645. TCHAR defExt[MAX_MSG_TXT];
  646. BOOL result;
  647. TCHAR filters[filtersMaxSize];
  648. LPOFNHOOKPROC lpDlgHook = NULL;
  649. HCURSOR hSaveCursor;
  650. TCHAR files[_MAX_PATH + 8];
  651. TCHAR szExt[_MAX_EXT + 8];
  652. TCHAR szBase[_MAX_PATH + 8];
  653. int indx;
  654. TCHAR fname[_MAX_FNAME];
  655. TCHAR ext[_MAX_EXT];
  656. PTSTR LocalInitialDir = NULL;
  657. *pFlags |= (OFN_EXPLORER | OFN_NOCHANGEDIR);
  658. if (InitialDir == NULL || !InitialDir[0])
  659. {
  660. DWORD retval = GetCurrentDirectory(NULL, NULL);
  661. InitialDir = (PTSTR)calloc(retval, sizeof(TCHAR) );
  662. if (InitialDir == NULL)
  663. {
  664. return FALSE;
  665. }
  666. GetCurrentDirectory(retval, InitialDir);
  667. LocalInitialDir = InitialDir;
  668. }
  669. if (DLG_Browse_Filebox_Title == titleId)
  670. {
  671. _tsplitpath( fileName, NULL, NULL, fname, ext );
  672. _tmakepath( files, NULL, NULL, fname, ext );
  673. }
  674. else
  675. {
  676. _tcscpy(files, fileName);
  677. }
  678. //
  679. // Set the Hour glass cursor
  680. //
  681. hSaveCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  682. InitFilterString((WORD)titleId, (PTSTR)filters, (int)filtersMaxSize);
  683. Dbg(LoadString(g_hInst, titleId, (PTSTR)title, MAX_MSG_TXT));
  684. Dbg(LoadString(g_hInst, defExtId, (PTSTR)defExt, MAX_MSG_TXT));
  685. if (templateId)
  686. {
  687. //
  688. // Build dialog box Name
  689. //
  690. *pFlags |= OFN_ENABLETEMPLATE;
  691. OpenFileName.lpTemplateName = MAKEINTRESOURCE(templateId);
  692. }
  693. else
  694. {
  695. *pFlags |= OFN_EXPLORER;
  696. }
  697. //
  698. // Make instance for _T('dlgProc')
  699. //
  700. if (lpfnHook)
  701. {
  702. lpDlgHook = lpfnHook;
  703. *pFlags |= OFN_ENABLEHOOK;
  704. }
  705. g_CurHelpId = (WORD) helpId;
  706. OpenFileName.lStructSize = sizeof(OpenFileName);
  707. OpenFileName.hwndOwner = hwnd;
  708. OpenFileName.hInstance = g_hInst;
  709. OpenFileName.lpstrFilter = (PTSTR)filters;
  710. OpenFileName.lpstrCustomFilter = NULL;
  711. OpenFileName.nMaxCustFilter = 0;
  712. OpenFileName.nFilterIndex = 1;
  713. OpenFileName.lpstrFile = files;
  714. OpenFileName.nMaxFile = _MAX_PATH;
  715. OpenFileName.lpstrFileTitle = NULL;
  716. OpenFileName.lpstrInitialDir = InitialDir;
  717. OpenFileName.lpstrTitle = (PTSTR)title;
  718. OpenFileName.Flags = *pFlags;
  719. OpenFileName.lpstrDefExt = (PTSTR)NULL;
  720. OpenFileName.lCustData = 0L;
  721. OpenFileName.lpfnHook = lpDlgHook;
  722. g_nBoxCount++;
  723. switch (titleId)
  724. {
  725. case DLG_Open_Filebox_Title:
  726. _tcscat(OpenFileName.lpstrFile, defExt);
  727. // fall thru
  728. case DLG_Browse_Executable_Title:
  729. case DLG_Browse_CrashDump_Title:
  730. case DLG_Browse_Symbol_Path_Title:
  731. case DLG_Browse_Source_Path_Title:
  732. case DLG_Browse_Image_Path_Title:
  733. case DLG_Open_Workspace_File_Title:
  734. result = GetOpenFileName((LPOPENFILENAME)&OpenFileName);
  735. break;
  736. case DLG_Browse_LogFile_Title:
  737. if (fileName)
  738. {
  739. _tcscpy(OpenFileName.lpstrFile, fileName);
  740. }
  741. else
  742. {
  743. *OpenFileName.lpstrFile = 0;
  744. }
  745. result = GetOpenFileName((LPOPENFILENAME)&OpenFileName);
  746. break;
  747. case DLG_Browse_DbugDll_Title:
  748. *(OpenFileName.lpstrFile) = _T('\0');
  749. result = GetOpenFileName((LPOPENFILENAME)&OpenFileName);
  750. break;
  751. case DLG_Browse_Filebox_Title:
  752. _tsplitpath (files, (PTSTR)NULL, (PTSTR)NULL, (PTSTR)szBase, szExt);
  753. indx = matchExt (szExt, filters);
  754. if (indx != -1)
  755. {
  756. OpenFileName.nFilterIndex = indx;
  757. }
  758. _tcscat(title, szBase);
  759. if (*szExt)
  760. {
  761. _tcscat(title, szExt);
  762. }
  763. FAddToSearchPath = FALSE;
  764. FAddToRootMap = FALSE;
  765. result = GetOpenFileName((LPOPENFILENAME)&OpenFileName);
  766. //
  767. // Check to see if the use said to add a file to the browse path.
  768. // If so then add it to the front of the path
  769. //
  770. /*if (FAddToSearchPath)
  771. {
  772. AddToSearchPath(OpenFileName.lpstrFile);
  773. }
  774. else if (FAddToRootMap)
  775. {
  776. RootSetMapped(fileName, OpenFileName.lpstrFile);
  777. }*/
  778. break;
  779. case DLG_Write_Text_File_Title:
  780. case DLG_Save_Workspace_File_Title:
  781. OpenFileName.lpstrDefExt = defExt;
  782. *(OpenFileName.lpstrFile) = _T('\0');
  783. _tcscat(OpenFileName.lpstrFile, defExt);
  784. result = GetSaveFileName((LPOPENFILENAME)&OpenFileName);
  785. break;
  786. default:
  787. Assert(FALSE);
  788. free(LocalInitialDir);
  789. return FALSE;
  790. }
  791. g_nBoxCount--;
  792. if (result && titleId == DLG_Open_Filebox_Title)
  793. {
  794. KNOWN_EXT ExtType = RecognizeExtension(OpenFileName.lpstrFile);
  795. if (ExtType != KNOWN_EXT_COUNT)
  796. {
  797. if (QuestionBox(STR_May_Not_Be_Source, MB_YESNO) != IDYES)
  798. {
  799. result = 0;
  800. }
  801. }
  802. }
  803. if (result)
  804. {
  805. _tcscpy(fileName, OpenFileName.lpstrFile);
  806. switch(titleId)
  807. {
  808. case DLG_Open_Filebox_Title:
  809. AddFileToMru(FILE_USE_SOURCE, fileName);
  810. break;
  811. case DLG_Browse_Symbol_Path_Title:
  812. case DLG_Browse_Source_Path_Title:
  813. case DLG_Browse_Image_Path_Title:
  814. // Return only the path.
  815. if (OpenFileName.nFileOffset > 0)
  816. {
  817. fileName[OpenFileName.nFileOffset - 1] = 0;
  818. }
  819. break;
  820. }
  821. //
  822. // Get the output of flags
  823. //
  824. *pFlags = OpenFileName.Flags;
  825. }
  826. //
  827. //Restore cursor
  828. //
  829. SetCursor(hSaveCursor);
  830. free(LocalInitialDir);
  831. return result;
  832. } /* StartFileDlg() */
  833. /*** matchExt
  834. **
  835. ** Synopsis:
  836. ** int = matchExt (queryExtension, sourceList)
  837. **
  838. ** Entry:
  839. **
  840. ** Returns: 1-based index of pairwise substring for which the second
  841. ** element (i.e., the extension list), contains the target
  842. ** extension. If there is no match, we return -1.
  843. **
  844. ** Description:
  845. ** Searches extension lists for the Open/Save/Browse common
  846. ** dialogs to try to match a filter to the input filename's
  847. ** extension.
  848. ** (Open File, Save File, Merge File and Open Project)
  849. **
  850. ** Implementation note: Our thinking looks like this:
  851. **
  852. ** We are given a sequence of null-terminated strings which
  853. ** are text/extension pairs. We return the pairwise 1-based
  854. ** index of the first pair for which the second element has an
  855. ** exact match for the target extension. (Everything, by the
  856. ** way, is compared without case sensitivity.) We picture the
  857. ** source sequence, then, to be an array whose elements are pairs
  858. ** of strings (we will call the pairs 'left' and 'right').
  859. **
  860. ** Just to complicate things, we allow the '.right' pair elements to
  861. ** be strings like "*.c;*.cpp;*.cxx", where we our query might be
  862. ** any one of the three (minus the leading asterisk). Fortunately,
  863. ** _tcstok() will break things apart for us (see the 'delims[]' array
  864. ** in the code for the delimiters we have chosen).
  865. **
  866. ** Assuming there is a match in there somewhere, our invariant
  867. ** for locating the first one will be:
  868. **
  869. ** Exists(k):
  870. ** ForAll(i) : 0 <= i < k
  871. ** : queryExtension \not IS_IN source[i].right
  872. ** \and
  873. ** queryExtension IS_IN source[k].right
  874. **
  875. ** where we define IS_IN to be a membership predicate (using _tcstok()
  876. ** and _tcsicmp() in the implementation, eh?):
  877. **
  878. ** x IS_IN y
  879. ** <=>
  880. ** Exists (t:token) : (t \in y) \and (x == t).
  881. **
  882. ** The guard for our main loop, then, comes from the search for the
  883. ** queryExtension within the tokens inside successive '.right' elements.
  884. ** We choose to continue as long as there is no current token in the
  885. ** pair's right side that contains the query.
  886. **
  887. ** (We have the pragmatic concern that the value may not be there, so we
  888. ** augment the loop guard with the condition that we have not yet
  889. ** exhausted the source. This is straightforward to add to the
  890. ** invariant, but it causes a lot of clutter that does help our
  891. ** comprehension at all, so we just stick it in the guard without
  892. ** formal justification.)
  893. */
  894. int
  895. matchExt(
  896. PTSTR queryExtension,
  897. PTSTR sourceList
  898. )
  899. {
  900. int answer;
  901. int idxPair = 1; // a 1-based index!
  902. PTSTR tokenMatch = 0;
  903. TCHAR delims[] = _T("*,; ") ; // Given a typical string: "*.c;*.cpp;*.cxx",
  904. // _tcstok() would produce three tokens:
  905. // ".c", ".cpp", and ".cxx".
  906. while (*sourceList != 0 && tokenMatch == 0)
  907. {
  908. while (*sourceList != _T('\0'))
  909. { sourceList++; } // skip first string of pair
  910. sourceList++; // and increment beyond NULL
  911. if (*sourceList != _T('\0'))
  912. {
  913. PTSTR work = _tcsdup (sourceList); // copy to poke holes in
  914. tokenMatch = _tcstok (work, delims);
  915. while (tokenMatch && _tcsicmp (tokenMatch, queryExtension))
  916. {
  917. tokenMatch = _tcstok (0, delims);
  918. }
  919. free (work);
  920. }
  921. if (tokenMatch == 0) // no match: need to move to next pair
  922. {
  923. while (*sourceList != _T('\0'))
  924. { sourceList++; } // skip second string of pair
  925. sourceList++; // and increment beyond NULL
  926. idxPair++;
  927. }
  928. }
  929. answer = (tokenMatch != 0) ? idxPair : (-1);
  930. return (answer);
  931. }
  932. /*** DlgFile
  933. **
  934. ** Synopsis:
  935. ** bool = DlgFile(hDlg, message, wParam, lParam)
  936. **
  937. ** Entry:
  938. **
  939. ** Returns:
  940. **
  941. ** Description:
  942. ** Processes messages for file dialog boxes
  943. ** Those dialogs are not called directly but are called
  944. ** by the DlgFile function which contains all basic
  945. ** elements for Dialogs Files Operations Handling.
  946. ** (Open File, Save File, Merge File and Open Project)
  947. **
  948. ** See OFNHookProc
  949. */
  950. UINT_PTR
  951. APIENTRY
  952. DlgFile(
  953. HWND hDlg,
  954. UINT uMsg,
  955. WPARAM wParam,
  956. LPARAM lParam
  957. )
  958. {
  959. switch (uMsg)
  960. {
  961. case WM_NOTIFY:
  962. {
  963. LPOFNOTIFY lpon = (LPOFNOTIFY) lParam;
  964. //
  965. // Determine what happened/why we are being notified
  966. //
  967. switch (lpon->hdr.code)
  968. {
  969. case CDN_HELP:
  970. // Help button pushed
  971. Dbg(HtmlHelp(hDlg,g_HelpFileName, HH_HELP_CONTEXT,
  972. g_CurHelpId));
  973. break;
  974. }
  975. }
  976. break;
  977. }
  978. return FALSE;
  979. } /* DlgFile() */
  980. UINT_PTR
  981. APIENTRY
  982. GetOpenFileNameHookProc(
  983. HWND hDlg,
  984. UINT msg,
  985. WPARAM wParam,
  986. LPARAM lParam
  987. )
  988. /*++
  989. Routine Description:
  990. This routine is handle the Add Directory To radio buttons in the
  991. browser source file dialog box.
  992. Arguments:
  993. hDlg - Supplies the handle to current dialog
  994. msg - Supplies the message to be processed
  995. wParam - Supplies info about the message
  996. lParam - Supplies info about the message
  997. Return Value:
  998. TRUE if we replaced default processing of the message, FALSE otherwise
  999. --*/
  1000. {
  1001. /*
  1002. switch( msg ) {
  1003. case WM_INITDIALOG:
  1004. return TRUE;
  1005. case WM_NOTIFY:
  1006. {
  1007. LPOFNOTIFY lpon = (LPOFNOTIFY) lParam;
  1008. switch(lpon->hdr.code) {
  1009. case CDN_FILEOK:
  1010. FAddToSearchPath = (IsDlgButtonChecked( hDlg, IDC_CHECK_ADD_SRC_ROOT_MAPPING) == BST_CHECKED);
  1011. return 0;
  1012. }
  1013. }
  1014. }
  1015. return DlgFile(hDlg, msg, wParam, lParam);
  1016. */
  1017. return 0;
  1018. } /* GetOpenFileNameHookProc() */
  1019. void
  1020. Internal_Activate(
  1021. HWND hwndPrev,
  1022. HWND hwndCur,
  1023. HWND hwndNew,
  1024. int nPosition
  1025. )
  1026. /*++
  1027. Routine Description:
  1028. Places a window in the specified Z order position.
  1029. Arguments:
  1030. hwndPrev - Window prior to hwndCur. Can be NULL.
  1031. hwndCur - Currently active window, topmost in Z order. Can be NULL.
  1032. hwndNew - The window to be placed in the new Z order.
  1033. nPosition - Where the window is to be place in the Z order.
  1034. 1 - topmost
  1035. 2 - 2nd place (behind topmost)
  1036. 3 - 3rd place, etc....
  1037. Return Value:
  1038. None
  1039. --*/
  1040. {
  1041. // Sanity check. Make sure the programmer
  1042. // specified a 1, 2, or 3. We are strict in order to
  1043. // keep it readable.
  1044. Assert(1 <= nPosition && nPosition <= 3);
  1045. Assert(hwndNew);
  1046. switch (nPosition)
  1047. {
  1048. case 1:
  1049. // Make it topmost
  1050. SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndNew, 0);
  1051. break;
  1052. case 2:
  1053. // Try to place it 2nd in Z order
  1054. if (NULL == hwndCur)
  1055. {
  1056. // We don't have a topmost window,
  1057. // so make this one the topmost window
  1058. SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndNew, 0);
  1059. }
  1060. else
  1061. {
  1062. // Place it in 2nd
  1063. SetWindowPos(hwndNew, hwndCur, 0, 0, 0, 0,
  1064. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  1065. // Give the topmost most focus again and activate UI visual clues.
  1066. SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndCur, 0);
  1067. }
  1068. break;
  1069. case 3:
  1070. // Try to place it 3rd in Z order
  1071. if (NULL == hwndCur)
  1072. {
  1073. // We don't have a topmost window,
  1074. // so make this one the topmost window
  1075. SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndNew, 0);
  1076. }
  1077. else
  1078. {
  1079. // Is there a window 2nd in the Z order?
  1080. if (NULL == hwndPrev)
  1081. {
  1082. // No window 2nd in Z order. Then simply place it after the
  1083. // topmost window.
  1084. hwndPrev = hwndCur;
  1085. }
  1086. // Place it
  1087. SetWindowPos(hwndNew, hwndPrev, 0, 0, 0, 0,
  1088. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  1089. // Give the topmost most focus again and activate UI visual clues.
  1090. SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndCur, 0);
  1091. }
  1092. break;
  1093. default:
  1094. // Sanity check, the programmer missed a case
  1095. Assert(0);
  1096. }
  1097. }
  1098. void
  1099. ReorderChildren(
  1100. HWND hwndPrev,
  1101. HWND hwndCur,
  1102. HWND hwndNew,
  1103. BOOL bUserActivated
  1104. )
  1105. {
  1106. PCOMMONWIN_DATA pCur_WinData = NULL;
  1107. PCOMMONWIN_DATA pNew_WinData = NULL;
  1108. PCOMMONWIN_DATA pPrev_WinData = NULL;
  1109. if (hwndCur)
  1110. {
  1111. pCur_WinData = GetCommonWinData(hwndCur);
  1112. }
  1113. pNew_WinData = GetCommonWinData(hwndNew);
  1114. Assert(pNew_WinData);
  1115. if (!pNew_WinData)
  1116. {
  1117. return;
  1118. }
  1119. if (hwndPrev)
  1120. {
  1121. pPrev_WinData = GetCommonWinData(hwndPrev);
  1122. }
  1123. //
  1124. // Handle the case where the window activation
  1125. // was requested by the debugger itself and not the
  1126. // user.
  1127. //
  1128. switch (pNew_WinData->m_enumType)
  1129. {
  1130. default:
  1131. Internal_Activate(hwndPrev, hwndCur, hwndNew, bUserActivated ? 2 : 1);
  1132. break;
  1133. case DISASM_WINDOW:
  1134. case DOC_WINDOW:
  1135. if (GetSrcMode_StatusBar())
  1136. {
  1137. // Src mode
  1138. if (pCur_WinData != NULL &&
  1139. (DISASM_WINDOW == pCur_WinData->m_enumType ||
  1140. DOC_WINDOW == pCur_WinData->m_enumType))
  1141. {
  1142. // We can take the place of another doc/asm wind
  1143. // Place 1st in z-order
  1144. Internal_Activate(hwndPrev, hwndCur, hwndNew, 1);
  1145. }
  1146. else
  1147. {
  1148. if (pPrev_WinData != NULL &&
  1149. (DOC_WINDOW == pPrev_WinData->m_enumType ||
  1150. DISASM_WINDOW == pPrev_WinData->m_enumType))
  1151. {
  1152. // Don't have a window in 2nd place, or if we do it
  1153. // is a src or asm window, and we can hide it.
  1154. // Place 2nd in Z-order
  1155. Internal_Activate(hwndPrev, hwndCur, hwndNew, 2);
  1156. }
  1157. else
  1158. {
  1159. // Place 3rd in Z-order
  1160. Internal_Activate(hwndPrev, hwndCur, hwndNew, 3);
  1161. }
  1162. }
  1163. }
  1164. else
  1165. {
  1166. WIN_TYPES Type = pCur_WinData != NULL ?
  1167. pCur_WinData->m_enumType : MINVAL_WINDOW;
  1168. // Asm mode
  1169. // Which is currently the topmost window.
  1170. switch (Type)
  1171. {
  1172. case DOC_WINDOW:
  1173. // Place 1st in z-order
  1174. Internal_Activate(hwndPrev, hwndCur, hwndNew, 1);
  1175. break;
  1176. case DISASM_WINDOW:
  1177. if (DOC_WINDOW == pNew_WinData->m_enumType)
  1178. {
  1179. if (pPrev_WinData == NULL ||
  1180. DOC_WINDOW != pPrev_WinData->m_enumType)
  1181. {
  1182. // We have a window in second place that isn't a doc
  1183. // window (locals, watch, ...).
  1184. Internal_Activate(hwndPrev, hwndCur, hwndNew, 3);
  1185. }
  1186. else
  1187. {
  1188. // Either don't have any windows in second place, or
  1189. // we have a window in second place that is a doc
  1190. // window. We can take its place.
  1191. //
  1192. // Place 2nd in z-order
  1193. Internal_Activate(hwndPrev, hwndCur, hwndNew, 2);
  1194. }
  1195. }
  1196. else
  1197. {
  1198. // Should never happen. The case of disasm being activated
  1199. // when it is currently active should ahve already been
  1200. // taken care of.
  1201. Dbg(0);
  1202. }
  1203. break;
  1204. default:
  1205. if ((pPrev_WinData != NULL &&
  1206. DISASM_WINDOW == pPrev_WinData->m_enumType) &&
  1207. DOC_WINDOW == pNew_WinData->m_enumType)
  1208. {
  1209. // window (locals, watch, ...).
  1210. Internal_Activate(hwndPrev, hwndCur, hwndNew, 3);
  1211. }
  1212. else
  1213. {
  1214. // Place 2nd in z-order
  1215. Internal_Activate(hwndPrev, hwndCur, hwndNew, 2);
  1216. }
  1217. break;
  1218. }
  1219. }
  1220. break;
  1221. }
  1222. }
  1223. void
  1224. ActivateMDIChild(
  1225. HWND hwndNew,
  1226. BOOL bUserActivated
  1227. )
  1228. /*++
  1229. Routine Description:
  1230. Used to activate a specified window. Automatically uses the hwndActive
  1231. variable to determine the currently active window.
  1232. Arguments:
  1233. hwndNew - The window to be placed in the new Z order.
  1234. bUserActivated - Indicates whether this action was initiated by the
  1235. user or by windbg. The value is to determine the Z order of
  1236. any windows that are opened.
  1237. --*/
  1238. {
  1239. if (hwndNew == NULL)
  1240. {
  1241. Assert(hwndNew);
  1242. return;
  1243. }
  1244. HWND hwndPrev = NULL;
  1245. HWND hwndCur = MDIGetActive(g_hwndMDIClient, NULL);
  1246. if (!hwndCur || bUserActivated || hwndCur == hwndNew)
  1247. {
  1248. // Nothing else was open. So we make this one the
  1249. // topmost window.
  1250. //
  1251. // Or the user requested that this window be made
  1252. // the topmost window, and we obey.
  1253. //
  1254. // Or we are re-activating the current window.
  1255. Internal_Activate(NULL, hwndCur, hwndNew, 1);
  1256. return;
  1257. }
  1258. // See is we have 3 or more windows open
  1259. hwndPrev = GetNextWindow(hwndCur, GW_HWNDNEXT);
  1260. ReorderChildren(hwndPrev, hwndCur, hwndNew, bUserActivated);
  1261. }
  1262. void
  1263. AppendTextToAnEditControl(
  1264. HWND hwnd,
  1265. PTSTR pszNewText
  1266. )
  1267. {
  1268. Assert(hwnd);
  1269. Assert(pszNewText);
  1270. CHARRANGE chrrgCurrent = {0};
  1271. CHARRANGE chrrgAppend = {0};
  1272. // Get the current selection
  1273. SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) &chrrgCurrent);
  1274. // Set the selection to the very end of the edit control
  1275. chrrgAppend.cpMin = chrrgAppend.cpMax = GetWindowTextLength(hwnd);
  1276. SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &chrrgCurrent);
  1277. // Append the text
  1278. SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) pszNewText);
  1279. // Restore previous selection
  1280. SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &chrrgCurrent);
  1281. }
  1282. VOID
  1283. CopyToClipboard(
  1284. PSTR str,
  1285. BOOL ExpandLf
  1286. )
  1287. {
  1288. if (!str)
  1289. {
  1290. return;
  1291. }
  1292. ULONG Len = strlen(str) + 1;
  1293. if (ExpandLf)
  1294. {
  1295. // Rather than bother to count the actual number
  1296. // of linefeeds that need to be expanded, just
  1297. // allocate twice as much memory as necessary. There's
  1298. // only one thing on the clipboard at a time and
  1299. // the things copied here are relatively small so this
  1300. // isn't a problem.
  1301. Len *= 2;
  1302. }
  1303. HANDLE Mem = GlobalAlloc(GMEM_MOVEABLE, Len);
  1304. if (Mem == NULL)
  1305. {
  1306. return;
  1307. }
  1308. PSTR Text = (PSTR)GlobalLock(Mem);
  1309. if (Text == NULL)
  1310. {
  1311. GlobalFree(Mem);
  1312. return;
  1313. }
  1314. if (ExpandLf)
  1315. {
  1316. PSTR Rd, Wr;
  1317. Rd = str;
  1318. Wr = Text;
  1319. while (*Rd)
  1320. {
  1321. if (*Rd == '\n')
  1322. {
  1323. *Wr++ = '\r';
  1324. }
  1325. *Wr++ = *Rd++;
  1326. }
  1327. *Wr = 0;
  1328. }
  1329. else
  1330. {
  1331. strcpy(Text, str);
  1332. }
  1333. GlobalUnlock(Mem);
  1334. if (OpenClipboard(NULL))
  1335. {
  1336. EmptyClipboard();
  1337. if (SetClipboardData(CF_TEXT, Mem) == NULL)
  1338. {
  1339. GlobalFree(Mem);
  1340. }
  1341. CloseClipboard();
  1342. }
  1343. }
  1344. void
  1345. SetAllocString(PSTR* Str, PSTR New)
  1346. {
  1347. if (*Str != NULL)
  1348. {
  1349. free(*Str);
  1350. }
  1351. *Str = New;
  1352. }
  1353. BOOL
  1354. DupAllocString(PSTR* Str, PSTR New)
  1355. {
  1356. PSTR NewStr = (PSTR)malloc(strlen(New) + 1);
  1357. if (NewStr == NULL)
  1358. {
  1359. return FALSE;
  1360. }
  1361. strcpy(NewStr, New);
  1362. SetAllocString(Str, NewStr);
  1363. return TRUE;
  1364. }
  1365. BOOL
  1366. PrintAllocString(PSTR* Str, int Len, PCSTR Format, ...)
  1367. {
  1368. PSTR NewStr = (PSTR)malloc(Len);
  1369. if (NewStr == NULL)
  1370. {
  1371. return FALSE;
  1372. }
  1373. va_list Args;
  1374. va_start(Args, Format);
  1375. if (_vsnprintf(NewStr, Len, Format, Args) < 1)
  1376. {
  1377. NewStr[Len - 1] = 0;
  1378. }
  1379. va_end(Args);
  1380. SetAllocString(Str, NewStr);
  1381. return TRUE;
  1382. }
  1383. HMENU
  1384. CreateContextMenuFromToolbarButtons(ULONG NumButtons,
  1385. TBBUTTON* Buttons,
  1386. ULONG IdBias)
  1387. {
  1388. ULONG i;
  1389. HMENU Menu;
  1390. Menu = CreatePopupMenu();
  1391. if (Menu == NULL)
  1392. {
  1393. return Menu;
  1394. }
  1395. for (i = 0; i < NumButtons; i++)
  1396. {
  1397. MENUITEMINFO Item;
  1398. ZeroMemory(&Item, sizeof(Item));
  1399. Item.cbSize = sizeof(Item);
  1400. Item.fMask = MIIM_TYPE;
  1401. if (Buttons->fsStyle & BTNS_SEP)
  1402. {
  1403. Item.fType = MFT_SEPARATOR;
  1404. }
  1405. else
  1406. {
  1407. Item.fMask |= MIIM_ID;
  1408. Item.fType = MFT_STRING;
  1409. Item.wID = (WORD)(Buttons->idCommand + IdBias);
  1410. Item.dwTypeData = (LPSTR)Buttons->iString;
  1411. }
  1412. if (!InsertMenuItem(Menu, i, TRUE, &Item))
  1413. {
  1414. DestroyMenu(Menu);
  1415. return NULL;
  1416. }
  1417. Buttons++;
  1418. }
  1419. DrawMenuBar(g_hwndFrame);
  1420. return Menu;
  1421. }
  1422. HWND
  1423. AddButtonBand(HWND Bar, PTSTR Text, PTSTR SizingText, UINT Id)
  1424. {
  1425. HWND Button;
  1426. HDC Dc;
  1427. RECT Rect;
  1428. Button = CreateWindowEx(0, "BUTTON", Text, WS_VISIBLE | WS_CHILD,
  1429. 0, 0, 0, 0,
  1430. Bar, (HMENU)(UINT_PTR)Id, g_hInst, NULL);
  1431. if (Button == NULL)
  1432. {
  1433. return NULL;
  1434. }
  1435. Rect.left = 0;
  1436. Rect.top = 0;
  1437. SendMessage(Button, WM_SETFONT, (WPARAM)g_Fonts[FONT_VARIABLE].Font, 0);
  1438. Dc = GetDC(Button);
  1439. if (Dc != NULL)
  1440. {
  1441. SIZE Size;
  1442. GetTextExtentPoint32(Dc, SizingText, strlen(SizingText), &Size);
  1443. Rect.right = Size.cx;
  1444. Rect.bottom = Size.cy;
  1445. ReleaseDC(Button, Dc);
  1446. }
  1447. else
  1448. {
  1449. Rect.right = strlen(Text) * g_Fonts[FONT_FIXED].Metrics.tmAveCharWidth;
  1450. Rect.bottom = g_Fonts[FONT_FIXED].Metrics.tmHeight;
  1451. }
  1452. REBARBANDINFO BandInfo;
  1453. BandInfo.cbSize = sizeof(BandInfo);
  1454. BandInfo.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE;
  1455. BandInfo.fStyle = RBBS_FIXEDSIZE;
  1456. BandInfo.hwndChild = Button;
  1457. BandInfo.cxMinChild = Rect.right - Rect.left +
  1458. 4 * GetSystemMetrics(SM_CXEDGE);
  1459. BandInfo.cyMinChild = Rect.bottom - Rect.top +
  1460. 2 * GetSystemMetrics(SM_CYEDGE);
  1461. SendMessage(Bar, RB_INSERTBAND, -1, (LPARAM)&BandInfo);
  1462. return Button;
  1463. }
  1464. KNOWN_EXT
  1465. RecognizeExtension(PTSTR Path)
  1466. {
  1467. PSTR Scan;
  1468. //
  1469. // Find the extension.
  1470. //
  1471. Scan = Path + strlen(Path);
  1472. for (;;)
  1473. {
  1474. if (Scan == Path)
  1475. {
  1476. return KNOWN_EXT_COUNT;
  1477. }
  1478. if (*--Scan == '.')
  1479. {
  1480. Scan++;
  1481. break;
  1482. }
  1483. }
  1484. if (!_stricmp(Scan, "dmp") ||
  1485. !_stricmp(Scan, "mdmp"))
  1486. {
  1487. return EXT_DUMP;
  1488. }
  1489. else if (!_stricmp(Scan, "exe"))
  1490. {
  1491. return EXT_EXE;
  1492. }
  1493. return KNOWN_EXT_COUNT;
  1494. }