mirror of https://github.com/tongzx/nt5src
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.
1631 lines
40 KiB
1631 lines
40 KiB
/*++
|
|
|
|
Copyright (c) 1999-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
util.cpp
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.hxx"
|
|
#pragma hdrstop
|
|
|
|
//Current Help Id for Open, Merge, Save and Open project dialog box
|
|
WORD g_CurHelpId;
|
|
|
|
// Number of dialog/message boxes currently open
|
|
int g_nBoxCount;
|
|
|
|
BOOL g_fNoPopups;
|
|
|
|
|
|
HWND
|
|
MDIGetActive(
|
|
HWND hwndParent,
|
|
BOOL *lpbMaximized
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Create the command window.
|
|
|
|
Arguments:
|
|
|
|
hwndParent - The parent window to the command window. In an MDI document,
|
|
this is usually the handle to the MDI client window: g_hwndMDIClient
|
|
|
|
Return Value:
|
|
|
|
The return value is the handle to the active MDI child window.
|
|
|
|
NULL if no MDI window has been created.
|
|
|
|
--*/
|
|
{
|
|
Assert(IsWindow(hwndParent));
|
|
return (HWND)SendMessage(hwndParent,
|
|
WM_MDIGETACTIVE,
|
|
0,
|
|
(LPARAM)lpbMaximized
|
|
);
|
|
}
|
|
|
|
|
|
/*** hGetBoxParent
|
|
**
|
|
** Synopsis:
|
|
** hwnd = hGetBoxParent()
|
|
**
|
|
** Entry:
|
|
** none
|
|
**
|
|
** Returns:
|
|
**
|
|
** Description:
|
|
** Gets a suitable parent window handle for an
|
|
** invocation of a message or dialog box.
|
|
** Helper function to util.c functions so declared
|
|
** near.
|
|
**
|
|
*/
|
|
|
|
HWND
|
|
hGetBoxParent()
|
|
{
|
|
HWND hCurWnd;
|
|
int i = 0;
|
|
|
|
hCurWnd = GetFocus();
|
|
if (hCurWnd)
|
|
{
|
|
while (GetWindowLong(hCurWnd, GWL_STYLE) & WS_CHILD)
|
|
{
|
|
hCurWnd = GetParent(hCurWnd);
|
|
Dbg((++i < 100));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hCurWnd = g_hwndFrame;
|
|
}
|
|
|
|
return hCurWnd;
|
|
}
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: MsgBox
|
|
|
|
PURPOSE: General purpose message box routine which takes
|
|
a pointer to the message text. Provides
|
|
program title as caption.
|
|
|
|
****************************************************************************/
|
|
|
|
int
|
|
MsgBox(
|
|
HWND hwndParent,
|
|
PTSTR szText,
|
|
UINT wType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generial purpose message box routine which takes a pointer to a message
|
|
text and prvoides the program title for the caption of the message box.
|
|
|
|
Arguments:
|
|
|
|
hwndParament - Supplies the parent window handle for the message box
|
|
szText - Supplies a pointer to the message box text.
|
|
wType - Supplies the message box type (to specify buttons)
|
|
|
|
Return Value:
|
|
|
|
Returns the message box return code
|
|
|
|
--*/
|
|
|
|
{
|
|
int MsgBoxRet = IDOK;
|
|
|
|
if (g_fNoPopups)
|
|
{
|
|
//
|
|
// log the string to the command win in case testing
|
|
// or when the remote server is running
|
|
//
|
|
CmdLogFmt (_T("%s\r\n"), szText);
|
|
}
|
|
else
|
|
{
|
|
g_nBoxCount++;
|
|
MsgBoxRet = MessageBox(hwndParent, szText,
|
|
g_MainTitleText, wType);
|
|
g_nBoxCount--;
|
|
}
|
|
|
|
return MsgBoxRet;
|
|
} /* MsgBox() */
|
|
|
|
/*** ErrorBox
|
|
**
|
|
** Returns:
|
|
** FALSE
|
|
**
|
|
** Description:
|
|
** Display an error message box with an "Error" title, an OK
|
|
** button and a Exclamation Icon. First parameter is a
|
|
** reference string in the ressource file. The string
|
|
** can contain printf formatting chars, the arguments
|
|
** follow from the second parameter onwards.
|
|
**
|
|
*/
|
|
|
|
BOOL
|
|
ErrorBox(
|
|
HWND hwnd,
|
|
UINT type,
|
|
int wErrorFormat,
|
|
...
|
|
)
|
|
{
|
|
TCHAR szErrorFormat[MAX_MSG_TXT];
|
|
TCHAR szErrorText[MAX_VAR_MSG_TXT]; // size is as big as considered necessary
|
|
va_list vargs;
|
|
|
|
// load format string from resource file
|
|
Dbg(LoadString(g_hInst, wErrorFormat, (PTSTR)szErrorFormat, MAX_MSG_TXT));
|
|
|
|
va_start(vargs, wErrorFormat);
|
|
_vstprintf(szErrorText, szErrorFormat, vargs);
|
|
va_end(vargs);
|
|
|
|
if (hwnd == NULL)
|
|
{
|
|
hwnd = g_hwndFrame;
|
|
}
|
|
|
|
if (type == 0)
|
|
{
|
|
type = MB_TASKMODAL;
|
|
}
|
|
|
|
MsgBox(g_hwndFrame, (PTSTR)szErrorText, type | MB_OK | MB_ICONINFORMATION);
|
|
return FALSE; //Keep it always FALSE please
|
|
}
|
|
|
|
|
|
/*** InformationBox
|
|
**
|
|
** Description:
|
|
** Display an information message box with an "Information"
|
|
** title, an OK button and an Information Icon.
|
|
**
|
|
*/
|
|
|
|
void
|
|
InformationBox(
|
|
WORD wDescript
|
|
...
|
|
)
|
|
{
|
|
TCHAR szFormat[MAX_MSG_TXT];
|
|
TCHAR szText[MAX_VAR_MSG_TXT]; // size is as big as considered necessary
|
|
va_list vargs;
|
|
|
|
// load format string from resource file
|
|
Dbg(LoadString(g_hInst, wDescript, (PTSTR)szFormat, MAX_MSG_TXT));
|
|
|
|
// set up szText from passed parameters
|
|
va_start(vargs, wDescript);
|
|
_vstprintf(szText, szFormat, vargs);
|
|
va_end(vargs);
|
|
|
|
MsgBox(g_hwndFrame, (PTSTR)szText, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
|
|
|
|
return;
|
|
}
|
|
|
|
/*** QuestionBox
|
|
**
|
|
** Synopsis:
|
|
** int = QuestionBox(wCaptionId, wMsgFormat, wType, ...)
|
|
**
|
|
** Entry:
|
|
**
|
|
** Returns:
|
|
** The result of the message box call
|
|
**
|
|
** Description:
|
|
** Display an query box with combination of YES, NO and
|
|
** CANCEL buttons and a question mark Icon.
|
|
** See ErrorBox for discussion.
|
|
**
|
|
*/
|
|
|
|
int
|
|
CDECL
|
|
QuestionBox(
|
|
WORD wMsgFormat,
|
|
UINT wType,
|
|
...
|
|
)
|
|
{
|
|
TCHAR szMsgFormat[MAX_MSG_TXT];
|
|
TCHAR szMsgText[MAX_VAR_MSG_TXT];
|
|
va_list vargs;
|
|
|
|
//Load format string from resource file
|
|
Dbg(LoadString(g_hInst, wMsgFormat, (PTSTR)szMsgFormat, MAX_MSG_TXT));
|
|
|
|
//Set up szMsgText from passed parameters
|
|
va_start(vargs, wType);
|
|
_vstprintf(szMsgText, szMsgFormat, vargs);
|
|
va_end(vargs);
|
|
|
|
return MsgBox(g_hwndFrame, szMsgText,
|
|
wType | MB_ICONEXCLAMATION | MB_TASKMODAL);
|
|
} /* QuestionBox() */
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: QuestionBox2
|
|
|
|
PURPOSE: Display an query box with combination of YES, NO and
|
|
CANCEL buttons and a question mark Icon. The type and
|
|
the parent window are adjustable.
|
|
|
|
RETURNS: MessageBox result
|
|
|
|
****************************************************************************/
|
|
int
|
|
CDECL
|
|
QuestionBox2(
|
|
HWND hwnd,
|
|
WORD wMsgFormat,
|
|
UINT wType,
|
|
...
|
|
)
|
|
{
|
|
TCHAR szMsgFormat[MAX_MSG_TXT];
|
|
TCHAR szMsgText[MAX_VAR_MSG_TXT];
|
|
va_list vargs;
|
|
|
|
//Load format string from resource file
|
|
Dbg(LoadString(g_hInst, wMsgFormat, (PTSTR)szMsgFormat, MAX_MSG_TXT));
|
|
|
|
//Set up szMsgText from passed parameters
|
|
va_start(vargs, wType);
|
|
_vstprintf(szMsgText, szMsgFormat, vargs);
|
|
va_end(vargs);
|
|
|
|
return MsgBox(hwnd, szMsgText, wType | MB_ICONEXCLAMATION);
|
|
} /* QuestionBox2() */
|
|
|
|
|
|
/*** ShowAssert
|
|
**
|
|
** Synopsis:
|
|
** void = ShowAssert(szCond, iLine, szFile)
|
|
**
|
|
** Entry:
|
|
** szCond - tokenized form of the failed condition
|
|
** iLine - Line number for the assertion
|
|
** szFile - File for the assertion
|
|
**
|
|
** Returns:
|
|
** void
|
|
**
|
|
** Description:
|
|
** Prepare and display a Message Box with szCondition, iLine and
|
|
** szFile as fields.
|
|
**
|
|
*/
|
|
void
|
|
ShowAssert(
|
|
PTSTR condition,
|
|
UINT line,
|
|
PTSTR file
|
|
)
|
|
{
|
|
TCHAR text[MAX_VAR_MSG_TXT];
|
|
|
|
//Build line, show assertion and exit program
|
|
|
|
_stprintf(text, _T("- Line:%u, File:%Fs, Condition:%Fs"),
|
|
(WPARAM) line, file, condition);
|
|
|
|
TCHAR szBuffer[_MAX_PATH];
|
|
PTSTR pszBuffer;
|
|
PTSTR szAssertFile = _T("assert.wbg");
|
|
HANDLE hFile = NULL;
|
|
|
|
hFile = CreateFile(szAssertFile,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
if (INVALID_HANDLE_VALUE != hFile)
|
|
{
|
|
// Write the text out to the file
|
|
DWORD dwBytesWritten = 0;
|
|
|
|
Assert(WriteFile(hFile, text, _tcslen(text), &dwBytesWritten, NULL));
|
|
Assert(_tcslen(text) == dwBytesWritten);
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
int Action =
|
|
MessageBox(GetDesktopWindow(), text, "Assertion Failure",
|
|
MB_ABORTRETRYIGNORE);
|
|
if (Action == IDABORT)
|
|
{
|
|
exit(3);
|
|
}
|
|
else if (Action == IDRETRY)
|
|
{
|
|
DebugBreak();
|
|
}
|
|
} // ShowAssert()
|
|
|
|
|
|
/*** StartDialog
|
|
**
|
|
** Synopsis:
|
|
** int = StartDialog(rcDlgNb, dlgProc, lParam)
|
|
**
|
|
** Entry:
|
|
** rcDlgNb - Resource number of dialog to be openned
|
|
** dlgProc - Filter procedure for the dialog
|
|
** lParam - Data passed into the dlg proc via LPARAM
|
|
**
|
|
** Returns:
|
|
** Result of the dialog box call
|
|
**
|
|
** Description:
|
|
** Loads and execute the dialog box 'rcDlgNb' (resource
|
|
** file string number) associated with the dialog
|
|
** function 'dlgProc'
|
|
**
|
|
*/
|
|
|
|
int
|
|
StartDialog(
|
|
int rcDlgNb,
|
|
DLGPROC dlgProc,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
LRESULT result;
|
|
|
|
//
|
|
//Execute Dialog Box
|
|
//
|
|
|
|
g_nBoxCount++;
|
|
result = DialogBoxParam(g_hInst,
|
|
MAKEINTRESOURCE(rcDlgNb),
|
|
hGetBoxParent(),
|
|
dlgProc,
|
|
lParam
|
|
);
|
|
Assert(result != (LRESULT)-1);
|
|
g_nBoxCount--;
|
|
|
|
return (int)result;
|
|
}
|
|
|
|
|
|
void
|
|
ProcessNonDlgMessage(LPMSG Msg)
|
|
{
|
|
#if 0
|
|
{
|
|
DebugPrint("NonDlg msg %X for %p, args %X %X\n",
|
|
Msg->message, Msg->hwnd, Msg->wParam, Msg->lParam);
|
|
}
|
|
#endif
|
|
|
|
// If a keyboard message is for the MDI , let the MDI client
|
|
// take care of it. Otherwise, check to see if it's a normal
|
|
// accelerator key (like F3 = find next). Otherwise, just handle
|
|
// the message as usual.
|
|
if (!TranslateMDISysAccel(g_hwndMDIClient, Msg) &&
|
|
!TranslateAccelerator(g_hwndFrame, g_hMainAccTable, Msg))
|
|
{
|
|
//
|
|
// If this is a right-button-down over a child window,
|
|
// automatically activate the window's contex menu.
|
|
//
|
|
if (Msg->message == WM_RBUTTONDOWN &&
|
|
IsChild(g_hwndMDIClient, Msg->hwnd))
|
|
{
|
|
HMENU Menu;
|
|
PCOMMONWIN_DATA CmnWin;
|
|
POINT ScreenPt;
|
|
|
|
POINT Pt = {LOWORD(Msg->lParam), HIWORD(Msg->lParam)};
|
|
ClientToScreen(Msg->hwnd, &Pt);
|
|
ScreenPt = Pt;
|
|
ScreenToClient(g_hwndMDIClient, &Pt);
|
|
|
|
HWND Win = ChildWindowFromPointEx(g_hwndMDIClient, Pt,
|
|
CWP_SKIPINVISIBLE);
|
|
if (Win != NULL &&
|
|
(CmnWin = GetCommonWinData(Win)) != NULL &&
|
|
(Menu = CmnWin->GetContextMenu()) != NULL)
|
|
{
|
|
UINT Item = TrackPopupMenu(Menu, TPM_LEFTALIGN | TPM_TOPALIGN |
|
|
TPM_NONOTIFY | TPM_RETURNCMD |
|
|
TPM_RIGHTBUTTON,
|
|
ScreenPt.x, ScreenPt.y,
|
|
0, Msg->hwnd, NULL);
|
|
if (Item)
|
|
{
|
|
CmnWin->OnContextMenuSelection(Item);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
TranslateMessage(Msg);
|
|
DispatchMessage(Msg);
|
|
}
|
|
}
|
|
|
|
void
|
|
ProcessPendingMessages(void)
|
|
{
|
|
MSG Msg;
|
|
|
|
// Process all available messages.
|
|
while (PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE))
|
|
{
|
|
if (!GetMessage(&Msg, NULL, 0, 0))
|
|
{
|
|
g_Exit = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (g_FindDialog == NULL ||
|
|
!IsDialogMessage(g_FindDialog, &Msg))
|
|
{
|
|
ProcessNonDlgMessage(&Msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION: InfoBox
|
|
|
|
PURPOSE: Opens a Dialog box with a title and accepting
|
|
a printf style for text. It's for DEBUGGING USE ONLY
|
|
|
|
****************************************************************************/
|
|
int
|
|
InfoBox(
|
|
PTSTR text,
|
|
...
|
|
)
|
|
{
|
|
TCHAR buffer[MAX_MSG_TXT];
|
|
va_list vargs;
|
|
|
|
va_start(vargs, text);
|
|
_vstprintf(buffer, text, vargs);
|
|
va_end(vargs);
|
|
return MsgBox(GetActiveWindow(), buffer, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
|
|
}
|
|
|
|
|
|
void
|
|
ExitDebugger(PDEBUG_CLIENT Client, ULONG Code)
|
|
{
|
|
if (Client != NULL && !g_RemoteClient)
|
|
{
|
|
Client->EndSession(DEBUG_END_PASSIVE);
|
|
// Force servers to get cleaned up.
|
|
Client->EndSession(DEBUG_END_REENTRANT);
|
|
}
|
|
|
|
ExitProcess(Code);
|
|
}
|
|
|
|
// XXX drewb - Is this functionality present in other utilities?
|
|
// FatalErrorBox is close. Probably can combine something here.
|
|
void
|
|
ErrorExit(PDEBUG_CLIENT Client, PCSTR Format, ...)
|
|
{
|
|
char Message[1024];
|
|
va_list Args;
|
|
|
|
va_start(Args, Format);
|
|
_vsnprintf(Message, sizeof(Message), Format, Args);
|
|
va_end(Args);
|
|
|
|
// XXX drewb - Could put up message box.
|
|
OutputDebugString(Message);
|
|
|
|
ExitDebugger(Client, E_FAIL);
|
|
}
|
|
|
|
#define MAX_FORMAT_STRINGS 8
|
|
LPSTR
|
|
FormatAddr64(
|
|
ULONG64 addr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Format a 64 bit address, showing the high bits or not
|
|
according to various flags.
|
|
|
|
An array of static string buffers is used, returning a different
|
|
buffer for each successive call so that it may be used multiple
|
|
times in the same printf.
|
|
|
|
Arguments:
|
|
|
|
addr - Supplies the value to format
|
|
|
|
Return Value:
|
|
|
|
A pointer to the string buffer containing the formatted number
|
|
|
|
--*/
|
|
{
|
|
static CHAR strings[MAX_FORMAT_STRINGS][18];
|
|
static int next = 0;
|
|
LPSTR string;
|
|
|
|
string = strings[next];
|
|
++next;
|
|
if (next >= MAX_FORMAT_STRINGS) {
|
|
next = 0;
|
|
}
|
|
if (g_Ptr64) {
|
|
sprintf(string, "%08x`%08x", (ULONG)(addr>>32), (ULONG)addr);
|
|
} else {
|
|
sprintf(string, "%08x", (ULONG)addr);
|
|
}
|
|
return string;
|
|
}
|
|
|
|
|
|
static BOOL FAddToSearchPath = FALSE;
|
|
static BOOL FAddToRootMap = FALSE;
|
|
|
|
/*
|
|
** AppendFilter
|
|
**
|
|
** Description:
|
|
** Append a filter to an existing filters string.
|
|
**
|
|
*/
|
|
|
|
BOOL
|
|
AppendFilter(
|
|
WORD filterTextId,
|
|
int filterExtId,
|
|
PTSTR filterString,
|
|
int *len,
|
|
int maxLen
|
|
)
|
|
{
|
|
int size;
|
|
TCHAR Tmp[MAX_MSG_TXT];
|
|
|
|
//
|
|
// Append filter text
|
|
//
|
|
|
|
Dbg(LoadString(g_hInst, filterTextId, Tmp, MAX_MSG_TXT));
|
|
size = _tcslen(Tmp) + 1;
|
|
if (*len + size > maxLen)
|
|
{
|
|
return FALSE;
|
|
}
|
|
memmove(filterString + *len, Tmp, size);
|
|
*len += size;
|
|
|
|
//
|
|
// Append filter extension
|
|
//
|
|
|
|
Dbg(LoadString(g_hInst, filterExtId, Tmp, MAX_MSG_TXT));
|
|
size = _tcslen(Tmp) + 1;
|
|
if (*len + size > maxLen)
|
|
{
|
|
return FALSE;
|
|
}
|
|
memmove(filterString + *len, Tmp, size);
|
|
*len += size;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
** InitFilterString
|
|
**
|
|
** Description:
|
|
** Initialize file filters for file dialog boxes.
|
|
*/
|
|
|
|
void
|
|
InitFilterString(
|
|
WORD titleId,
|
|
PTSTR filter,
|
|
int maxLen
|
|
)
|
|
{
|
|
int len = 0;
|
|
|
|
switch (titleId) {
|
|
case DLG_Browse_CrashDump_Title:
|
|
AppendFilter(TYP_File_DUMP, DEF_Ext_DUMP, filter, &len, maxLen);
|
|
break;
|
|
|
|
case DLG_Browse_Executable_Title:
|
|
AppendFilter(TYP_File_EXE, DEF_Ext_EXE, filter, &len, maxLen);
|
|
break;
|
|
|
|
case DLG_Browse_LogFile_Title:
|
|
AppendFilter(TYP_File_LOG, DEF_Ext_LOG, filter, &len, maxLen);
|
|
break;
|
|
|
|
case DLG_Open_Filebox_Title:
|
|
case DLG_Browse_Filebox_Title:
|
|
AppendFilter(TYP_File_SOURCE, DEF_Ext_SOURCE, filter, &len, maxLen);
|
|
AppendFilter(TYP_File_INCLUDE, DEF_Ext_INCLUDE, filter, &len, maxLen);
|
|
AppendFilter(TYP_File_ASMSRC, DEF_Ext_ASMSRC, filter, &len, maxLen);
|
|
AppendFilter(TYP_File_INC, DEF_Ext_INC, filter, &len, maxLen);
|
|
AppendFilter(TYP_File_RC, DEF_Ext_RC, filter, &len, maxLen);
|
|
AppendFilter(TYP_File_DLG, DEF_Ext_DLG, filter, &len, maxLen);
|
|
AppendFilter(TYP_File_DEF, DEF_Ext_DEF, filter, &len, maxLen);
|
|
AppendFilter(TYP_File_MAK, DEF_Ext_MAK, filter, &len, maxLen);
|
|
break ;
|
|
|
|
case DLG_Browse_DbugDll_Title:
|
|
AppendFilter(TYP_File_DLL, DEF_Ext_DLL, filter, &len, maxLen);
|
|
break;
|
|
|
|
default:
|
|
Assert(FALSE);
|
|
break;
|
|
}
|
|
|
|
AppendFilter(TYP_File_ALL, DEF_Ext_ALL, filter, &len, maxLen);
|
|
filter[len] = _T('\0');
|
|
}
|
|
|
|
BOOL
|
|
StartFileDlg(
|
|
HWND hwnd,
|
|
int titleId,
|
|
int defExtId,
|
|
int helpId,
|
|
int templateId,
|
|
PTSTR InitialDir,
|
|
PTSTR fileName,
|
|
DWORD* pFlags,
|
|
LPOFNHOOKPROC lpfnHook
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used by windbg to open the set of common file handling
|
|
dialog boxes.
|
|
|
|
Arguments:
|
|
|
|
hwnd - Supplies the wnd to hook the dialog box to
|
|
|
|
titleId - Supplies the string resource of the title
|
|
|
|
defExtId - Supplies The default extension resource string
|
|
|
|
helpId - Supplies the help number for the dialog box
|
|
|
|
templateId - Supplies the dialog resource number if non-zero
|
|
|
|
fileName - Supplies the default file name
|
|
|
|
pFiles - Supplies a pointer to flags
|
|
|
|
lpfnHook - Supplies the address of a hook procedure for the dialog
|
|
|
|
Return Value:
|
|
|
|
The result of the dialog box call (usually TRUE for OK and FALSE for
|
|
cancel)
|
|
|
|
--*/
|
|
|
|
{
|
|
#define filtersMaxSize 350
|
|
|
|
OPENFILENAME_NT4 OpenFileName = {0};
|
|
TCHAR title[MAX_MSG_TXT];
|
|
TCHAR defExt[MAX_MSG_TXT];
|
|
BOOL result;
|
|
TCHAR filters[filtersMaxSize];
|
|
LPOFNHOOKPROC lpDlgHook = NULL;
|
|
HCURSOR hSaveCursor;
|
|
TCHAR files[_MAX_PATH + 8];
|
|
TCHAR szExt[_MAX_EXT + 8];
|
|
TCHAR szBase[_MAX_PATH + 8];
|
|
int indx;
|
|
TCHAR ch;
|
|
TCHAR fname[_MAX_FNAME];
|
|
TCHAR ext[_MAX_EXT];
|
|
PTSTR LocalInitialDir = NULL;
|
|
|
|
*pFlags |= (OFN_EXPLORER | OFN_NOCHANGEDIR);
|
|
|
|
if (InitialDir == NULL || !InitialDir[0])
|
|
{
|
|
DWORD retval = GetCurrentDirectory(NULL, NULL);
|
|
InitialDir = (PTSTR)calloc(retval, sizeof(TCHAR) );
|
|
if (InitialDir == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
GetCurrentDirectory(retval, InitialDir);
|
|
LocalInitialDir = InitialDir;
|
|
}
|
|
|
|
if (DLG_Browse_Filebox_Title == titleId)
|
|
{
|
|
_tsplitpath( fileName, NULL, NULL, fname, ext );
|
|
_tmakepath( files, NULL, NULL, fname, ext );
|
|
}
|
|
else
|
|
{
|
|
_tcscpy(files, fileName);
|
|
}
|
|
|
|
//
|
|
// Set the Hour glass cursor
|
|
//
|
|
|
|
hSaveCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
InitFilterString((WORD)titleId, (PTSTR)filters, (int)filtersMaxSize);
|
|
Dbg(LoadString(g_hInst, titleId, (PTSTR)title, MAX_MSG_TXT));
|
|
Dbg(LoadString(g_hInst, defExtId, (PTSTR)defExt, MAX_MSG_TXT));
|
|
if (templateId)
|
|
{
|
|
//
|
|
// Build dialog box Name
|
|
//
|
|
|
|
*pFlags |= OFN_ENABLETEMPLATE;
|
|
OpenFileName.lpTemplateName = MAKEINTRESOURCE(templateId);
|
|
}
|
|
else
|
|
{
|
|
*pFlags |= OFN_EXPLORER;
|
|
}
|
|
|
|
//
|
|
// Make instance for _T('dlgProc')
|
|
//
|
|
|
|
if (lpfnHook)
|
|
{
|
|
lpDlgHook = lpfnHook;
|
|
|
|
*pFlags |= OFN_ENABLEHOOK;
|
|
}
|
|
|
|
g_CurHelpId = (WORD) helpId;
|
|
OpenFileName.lStructSize = sizeof(OpenFileName);
|
|
OpenFileName.hwndOwner = hwnd;
|
|
OpenFileName.hInstance = g_hInst;
|
|
OpenFileName.lpstrFilter = (PTSTR)filters;
|
|
OpenFileName.lpstrCustomFilter = NULL;
|
|
OpenFileName.nMaxCustFilter = 0;
|
|
OpenFileName.nFilterIndex = 1;
|
|
OpenFileName.lpstrFile = files;
|
|
OpenFileName.nMaxFile = _MAX_PATH;
|
|
OpenFileName.lpstrFileTitle = NULL;
|
|
OpenFileName.lpstrInitialDir = InitialDir;
|
|
OpenFileName.lpstrTitle = (PTSTR)title;
|
|
OpenFileName.Flags = *pFlags;
|
|
OpenFileName.lpstrDefExt = (PTSTR)NULL;
|
|
OpenFileName.lCustData = 0L;
|
|
OpenFileName.lpfnHook = lpDlgHook;
|
|
|
|
g_nBoxCount++;
|
|
|
|
switch (titleId)
|
|
{
|
|
case DLG_Open_Filebox_Title:
|
|
_tcscat(OpenFileName.lpstrFile, defExt);
|
|
// fall thru
|
|
case DLG_Browse_Executable_Title:
|
|
case DLG_Browse_CrashDump_Title:
|
|
result = GetOpenFileName((LPOPENFILENAME)&OpenFileName) ;
|
|
break ;
|
|
|
|
case DLG_Browse_LogFile_Title:
|
|
if (fileName)
|
|
{
|
|
_tcscpy(OpenFileName.lpstrFile, fileName);
|
|
}
|
|
else
|
|
{
|
|
*OpenFileName.lpstrFile = 0;
|
|
}
|
|
result = GetOpenFileName((LPOPENFILENAME)&OpenFileName) ;
|
|
break;
|
|
|
|
case DLG_Browse_DbugDll_Title:
|
|
*(OpenFileName.lpstrFile) = _T('\0');
|
|
result = GetOpenFileName((LPOPENFILENAME)&OpenFileName) ;
|
|
break ;
|
|
|
|
case DLG_Browse_Filebox_Title:
|
|
_tsplitpath (files, (PTSTR)NULL, (PTSTR)NULL, (PTSTR)szBase, szExt);
|
|
indx = matchExt (szExt, filters);
|
|
|
|
if (indx != -1)
|
|
{
|
|
OpenFileName.nFilterIndex = indx;
|
|
}
|
|
|
|
_tcscat(title, szBase);
|
|
if (*szExt)
|
|
{
|
|
_tcscat(title, szExt);
|
|
}
|
|
|
|
FAddToSearchPath = FALSE;
|
|
FAddToRootMap = FALSE;
|
|
|
|
result = GetOpenFileName((LPOPENFILENAME)&OpenFileName) ;
|
|
|
|
//
|
|
// Check to see if the use said to add a file to the browse path.
|
|
// If so then add it to the front of the path
|
|
//
|
|
|
|
/*if (FAddToSearchPath)
|
|
{
|
|
AddToSearchPath(OpenFileName.lpstrFile);
|
|
}
|
|
else if (FAddToRootMap)
|
|
{
|
|
RootSetMapped(fileName, OpenFileName.lpstrFile);
|
|
}*/
|
|
break;
|
|
|
|
default:
|
|
Assert(FALSE);
|
|
free(LocalInitialDir);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
g_nBoxCount--;
|
|
|
|
if (result)
|
|
{
|
|
_tcscpy(fileName, OpenFileName.lpstrFile);
|
|
if (titleId == DLG_Open_Filebox_Title)
|
|
{
|
|
AddFileToMru(FILE_USE_SOURCE, fileName);
|
|
}
|
|
|
|
//
|
|
// Get the output of flags
|
|
//
|
|
|
|
*pFlags = OpenFileName.Flags ;
|
|
}
|
|
|
|
//
|
|
//Restore cursor
|
|
//
|
|
|
|
SetCursor(hSaveCursor);
|
|
|
|
free(LocalInitialDir);
|
|
return result;
|
|
} /* StartFileDlg() */
|
|
|
|
/*** matchExt
|
|
**
|
|
** Synopsis:
|
|
** int = matchExt (queryExtension, sourceList)
|
|
**
|
|
** Entry:
|
|
**
|
|
** Returns: 1-based index of pairwise substring for which the second
|
|
** element (i.e., the extension list), contains the target
|
|
** extension. If there is no match, we return -1.
|
|
**
|
|
** Description:
|
|
** Searches extension lists for the Open/Save/Browse common
|
|
** dialogs to try to match a filter to the input filename's
|
|
** extension.
|
|
** (Open File, Save File, Merge File and Open Project)
|
|
**
|
|
** Implementation note: Our thinking looks like this:
|
|
**
|
|
** We are given a sequence of null-terminated strings which
|
|
** are text/extension pairs. We return the pairwise 1-based
|
|
** index of the first pair for which the second element has an
|
|
** exact match for the target extension. (Everything, by the
|
|
** way, is compared without case sensitivity.) We picture the
|
|
** source sequence, then, to be an array whose elements are pairs
|
|
** of strings (we will call the pairs 'left' and 'right').
|
|
**
|
|
** Just to complicate things, we allow the '.right' pair elements to
|
|
** be strings like "*.c;*.cpp;*.cxx", where we our query might be
|
|
** any one of the three (minus the leading asterisk). Fortunately,
|
|
** _tcstok() will break things apart for us (see the 'delims[]' array
|
|
** in the code for the delimiters we have chosen).
|
|
**
|
|
** Assuming there is a match in there somewhere, our invariant
|
|
** for locating the first one will be:
|
|
**
|
|
** Exists(k):
|
|
** ForAll(i) : 0 <= i < k
|
|
** : queryExtension \not IS_IN source[i].right
|
|
** \and
|
|
** queryExtension IS_IN source[k].right
|
|
**
|
|
** where we define IS_IN to be a membership predicate (using _tcstok()
|
|
** and _tcsicmp() in the implementation, eh?):
|
|
**
|
|
** x IS_IN y
|
|
** <=>
|
|
** Exists (t:token) : (t \in y) \and (x == t).
|
|
**
|
|
** The guard for our main loop, then, comes from the search for the
|
|
** queryExtension within the tokens inside successive '.right' elements.
|
|
** We choose to continue as long as there is no current token in the
|
|
** pair's right side that contains the query.
|
|
**
|
|
** (We have the pragmatic concern that the value may not be there, so we
|
|
** augment the loop guard with the condition that we have not yet
|
|
** exhausted the source. This is straightforward to add to the
|
|
** invariant, but it causes a lot of clutter that does help our
|
|
** comprehension at all, so we just stick it in the guard without
|
|
** formal justification.)
|
|
*/
|
|
|
|
int
|
|
matchExt(
|
|
PTSTR queryExtension,
|
|
PTSTR sourceList
|
|
)
|
|
{
|
|
int answer;
|
|
int idxPair = 1; // a 1-based index!
|
|
PTSTR tokenMatch = 0;
|
|
|
|
TCHAR delims[] = _T("*,; ") ; // Given a typical string: "*.c;*.cpp;*.cxx",
|
|
// _tcstok() would produce three tokens:
|
|
// ".c", ".cpp", and ".cxx".
|
|
|
|
while (*sourceList != 0 && tokenMatch == 0)
|
|
{
|
|
while (*sourceList != _T('\0'))
|
|
{ sourceList++; } // skip first string of pair
|
|
sourceList++; // and increment beyond NULL
|
|
|
|
if (*sourceList != _T('\0'))
|
|
{
|
|
PTSTR work = _tcsdup (sourceList); // copy to poke holes in
|
|
|
|
tokenMatch = _tcstok (work, delims);
|
|
|
|
while (tokenMatch && _tcsicmp (tokenMatch, queryExtension))
|
|
{
|
|
tokenMatch = _tcstok (0, delims);
|
|
}
|
|
|
|
free (work);
|
|
}
|
|
|
|
if (tokenMatch == 0) // no match: need to move to next pair
|
|
{
|
|
while (*sourceList != _T('\0'))
|
|
{ sourceList++; } // skip second string of pair
|
|
sourceList++; // and increment beyond NULL
|
|
|
|
idxPair++;
|
|
}
|
|
}
|
|
|
|
answer = (tokenMatch != 0) ? idxPair : (-1);
|
|
|
|
return (answer);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*** DlgFile
|
|
**
|
|
** Synopsis:
|
|
** bool = DlgFile(hDlg, message, wParam, lParam)
|
|
**
|
|
** Entry:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Description:
|
|
** Processes messages for file dialog boxes
|
|
** Those dialogs are not called directly but are called
|
|
** by the DlgFile function which contains all basic
|
|
** elements for Dialogs Files Operations Handling.
|
|
** (Open File, Save File, Merge File and Open Project)
|
|
**
|
|
** See OFNHookProc
|
|
*/
|
|
|
|
UINT_PTR
|
|
APIENTRY
|
|
DlgFile(
|
|
HWND hDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_NOTIFY:
|
|
{
|
|
LPOFNOTIFY lpon = (LPOFNOTIFY) lParam;
|
|
|
|
//
|
|
// Determine what happened/why we are being notified
|
|
//
|
|
switch (lpon->hdr.code)
|
|
{
|
|
case CDN_HELP:
|
|
// Help button pushed
|
|
Dbg(HtmlHelp(hDlg,g_HelpFileName, HH_HELP_CONTEXT,
|
|
g_CurHelpId));
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
} /* DlgFile() */
|
|
|
|
|
|
UINT_PTR
|
|
APIENTRY
|
|
GetOpenFileNameHookProc(
|
|
HWND hDlg,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is handle the Add Directory To radio buttons in the
|
|
browser source file dialog box.
|
|
|
|
Arguments:
|
|
|
|
hDlg - Supplies the handle to current dialog
|
|
msg - Supplies the message to be processed
|
|
wParam - Supplies info about the message
|
|
lParam - Supplies info about the message
|
|
|
|
Return Value:
|
|
|
|
TRUE if we replaced default processing of the message, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
/*
|
|
|
|
switch( msg ) {
|
|
case WM_INITDIALOG:
|
|
return TRUE;
|
|
|
|
case WM_NOTIFY:
|
|
{
|
|
LPOFNOTIFY lpon = (LPOFNOTIFY) lParam;
|
|
|
|
switch(lpon->hdr.code) {
|
|
case CDN_FILEOK:
|
|
FAddToSearchPath = (IsDlgButtonChecked( hDlg, IDC_CHECK_ADD_SRC_ROOT_MAPPING) == BST_CHECKED);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return DlgFile(hDlg, msg, wParam, lParam);
|
|
*/
|
|
return 0;
|
|
} /* GetOpenFileNameHookProc() */
|
|
|
|
|
|
void
|
|
Internal_Activate(
|
|
HWND hwndCur,
|
|
HWND hwndNew,
|
|
int nPosition
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Places a window in the specified Z order position.
|
|
|
|
Arguments:
|
|
|
|
hwndCur - Currently active window, topmost in Z order. Can be NULL.
|
|
|
|
hwndNew - The window to be placed in the new Z order.
|
|
|
|
nPosition - Where the window is to be place in the Z order.
|
|
1 - topmost
|
|
2 - 2nd place (behind topmost)
|
|
3 - 3rd place, etc....
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
// Sanity check. Make sure the programmer
|
|
// specified a 1, 2, or 3. We are strict in order to
|
|
// keep it readable.
|
|
Assert(1 <= nPosition && nPosition <= 3);
|
|
Assert(hwndNew);
|
|
|
|
switch (nPosition) {
|
|
case 1:
|
|
// Make it topmost
|
|
SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndNew, 0);
|
|
break;
|
|
|
|
case 2:
|
|
// Try to place it 2nd in Z order
|
|
if (NULL == hwndCur) {
|
|
// We don't have a topmost window, so make this one the topmost window
|
|
SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndNew, 0);
|
|
} else {
|
|
// Place it in 2nd
|
|
SetWindowPos(hwndNew, hwndCur, 0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
// Give the topmost most focus again and activate UI visual clues.
|
|
SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndCur, 0);
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
// Try to place it 3rd in Z order
|
|
if (NULL == hwndCur) {
|
|
// We don't have a topmost window, so make this one the topmost window
|
|
SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndNew, 0);
|
|
} else {
|
|
// Is there a window 2nd in the Z order?
|
|
HWND hwndPlaceAfter = GetNextWindow(hwndCur, GW_HWNDNEXT);
|
|
|
|
if (NULL == hwndPlaceAfter) {
|
|
// No window 2nd in Z order. Then simply place it after the
|
|
// topmost window.
|
|
hwndPlaceAfter = hwndCur;
|
|
}
|
|
|
|
// Place it
|
|
SetWindowPos(hwndNew, hwndPlaceAfter, 0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
// Give the topmost most focus again and activate UI visual clues.
|
|
SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndCur, 0);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// Sanity check, the programmer missed a case
|
|
Assert(0);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ActivateMDIChild(
|
|
HWND hwndNew,
|
|
BOOL bUserActivated
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Used to activate a specified window. Automatically uses the hwndActive
|
|
variable to determine the currently active window.
|
|
|
|
Arguments:
|
|
hwndNew - The window to be placed in the new Z order.
|
|
bUserActivated - Indicates whether this action was initiated by the
|
|
user or by windbg. The value is to determine the Z order of
|
|
any windows that are opened.
|
|
--*/
|
|
{
|
|
if (hwndNew == NULL)
|
|
{
|
|
Assert(hwndNew);
|
|
return;
|
|
}
|
|
|
|
HWND hwndPrev = NULL;
|
|
PCOMMONWIN_DATA pCur_WinData = NULL;
|
|
PCOMMONWIN_DATA pNew_WinData = NULL;
|
|
PCOMMONWIN_DATA pPrev_WinData = NULL;
|
|
|
|
HWND hwndCur = MDIGetActive(g_hwndMDIClient, NULL);
|
|
|
|
if (!hwndCur || bUserActivated || hwndCur == hwndNew)
|
|
{
|
|
// Nothing else was open. So we make this one the
|
|
// topmost window.
|
|
//
|
|
// Or the user requested that this window be made
|
|
// the topmost window, and we obey.
|
|
//
|
|
// Or we are re-activating the current window.
|
|
Internal_Activate(hwndCur, hwndNew, 1);
|
|
return;
|
|
}
|
|
|
|
// See is we have 3 or more windows open
|
|
hwndPrev = GetNextWindow(hwndCur, GW_HWNDNEXT);
|
|
|
|
if (hwndCur)
|
|
{
|
|
pCur_WinData = GetCommonWinData(hwndCur);
|
|
}
|
|
|
|
pNew_WinData = GetCommonWinData(hwndNew);
|
|
Assert(pNew_WinData);
|
|
if (!pNew_WinData)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (hwndPrev)
|
|
{
|
|
pPrev_WinData = GetCommonWinData(hwndPrev);
|
|
}
|
|
|
|
//
|
|
// Handle the case where the window activation
|
|
// was requested by the debugger itself and not the
|
|
// user.
|
|
//
|
|
|
|
switch (pNew_WinData->m_enumType)
|
|
{
|
|
default:
|
|
Internal_Activate(hwndCur, hwndNew, bUserActivated ? 2 : 1);
|
|
break;
|
|
|
|
case DISASM_WINDOW:
|
|
case DOC_WINDOW:
|
|
if (GetSrcMode_StatusBar())
|
|
{
|
|
// Src mode
|
|
|
|
if (pCur_WinData != NULL &&
|
|
(DISASM_WINDOW == pCur_WinData->m_enumType ||
|
|
DOC_WINDOW == pCur_WinData->m_enumType))
|
|
{
|
|
// We can take the place of another doc/asm wind
|
|
// Place 1st in z-order
|
|
Internal_Activate(hwndCur, hwndNew, 1);
|
|
}
|
|
else
|
|
{
|
|
if (pPrev_WinData != NULL &&
|
|
(DOC_WINDOW == pPrev_WinData->m_enumType ||
|
|
DISASM_WINDOW == pPrev_WinData->m_enumType))
|
|
{
|
|
// Don't have a window in 2nd place, or if we do it
|
|
// is a src or asm window, and we can hide it.
|
|
// Place 2nd in Z-order
|
|
Internal_Activate(hwndCur, hwndNew, 2);
|
|
}
|
|
else
|
|
{
|
|
// Place 3rd in Z-order
|
|
Internal_Activate(hwndCur, hwndNew, 3);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WIN_TYPES Type = pCur_WinData != NULL ?
|
|
pCur_WinData->m_enumType : MINVAL_WINDOW;
|
|
|
|
// Asm mode
|
|
|
|
// Which is currently the topmost window.
|
|
switch (Type)
|
|
{
|
|
case DOC_WINDOW:
|
|
// Place 1st in z-order
|
|
Internal_Activate(hwndCur, hwndNew, 1);
|
|
break;
|
|
|
|
case DISASM_WINDOW:
|
|
if (DOC_WINDOW == pNew_WinData->m_enumType)
|
|
{
|
|
if (pPrev_WinData == NULL ||
|
|
DOC_WINDOW != pPrev_WinData->m_enumType)
|
|
{
|
|
// We have a window in second place that isn't a doc
|
|
// window (locals, watch, ...).
|
|
Internal_Activate(hwndCur, hwndNew, 3);
|
|
}
|
|
else
|
|
{
|
|
// Either don't have any windows in second place, or
|
|
// we have a window in second place that is a doc
|
|
// window. We can take its place.
|
|
//
|
|
// Place 2nd in z-order
|
|
Internal_Activate(hwndCur, hwndNew, 2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Should never happen. The case of disasm being activated
|
|
// when it is currently active should ahve already been
|
|
// taken care of.
|
|
Dbg(0);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ((pPrev_WinData != NULL &&
|
|
DISASM_WINDOW == pPrev_WinData->m_enumType) &&
|
|
DOC_WINDOW == pNew_WinData->m_enumType)
|
|
{
|
|
// window (locals, watch, ...).
|
|
Internal_Activate(hwndCur, hwndNew, 3);
|
|
}
|
|
else
|
|
{
|
|
// Place 2nd in z-order
|
|
Internal_Activate(hwndCur, hwndNew, 2);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
AppendTextToAnEditControl(
|
|
HWND hwnd,
|
|
PTSTR pszNewText
|
|
)
|
|
{
|
|
Assert(hwnd);
|
|
Assert(pszNewText);
|
|
|
|
CHARRANGE chrrgCurrent = {0};
|
|
CHARRANGE chrrgAppend = {0};
|
|
|
|
// Get the current selection
|
|
SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) &chrrgCurrent);
|
|
|
|
// Set the selection to the very end of the edit control
|
|
chrrgAppend.cpMin = chrrgAppend.cpMax = GetWindowTextLength(hwnd);
|
|
SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &chrrgCurrent);
|
|
// Append the text
|
|
SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) pszNewText);
|
|
|
|
// Restore previous selection
|
|
SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &chrrgCurrent);
|
|
}
|
|
|
|
|
|
VOID
|
|
CopyToClipboard(
|
|
PSTR str
|
|
)
|
|
{
|
|
if (!str)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ULONG Len = strlen(str)+1;
|
|
HANDLE Mem = GlobalAlloc(GMEM_MOVEABLE, Len);
|
|
if (Mem == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
PSTR Text = (PSTR)GlobalLock(Mem);
|
|
if (Text == NULL)
|
|
{
|
|
GlobalFree(Mem);
|
|
return;
|
|
}
|
|
|
|
strcpy(Text, str);
|
|
|
|
GlobalUnlock(Mem);
|
|
|
|
if (OpenClipboard(NULL))
|
|
{
|
|
EmptyClipboard();
|
|
if (SetClipboardData(CF_TEXT, Mem) == NULL)
|
|
{
|
|
GlobalFree(Mem);
|
|
}
|
|
|
|
CloseClipboard();
|
|
}
|
|
}
|
|
|
|
void
|
|
SetAllocString(PSTR* Str, PSTR New)
|
|
{
|
|
if (*Str != NULL)
|
|
{
|
|
free(*Str);
|
|
}
|
|
*Str = New;
|
|
}
|
|
|
|
BOOL
|
|
DupAllocString(PSTR* Str, PSTR New)
|
|
{
|
|
PSTR NewStr = (PSTR)malloc(strlen(New) + 1);
|
|
if (NewStr == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(NewStr, New);
|
|
SetAllocString(Str, NewStr);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
PrintAllocString(PSTR* Str, int Len, PCSTR Format, ...)
|
|
{
|
|
PSTR NewStr = (PSTR)malloc(Len);
|
|
if (NewStr == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
va_list Args;
|
|
|
|
va_start(Args, Format);
|
|
_vsnprintf(NewStr, Len, Format, Args);
|
|
va_end(Args);
|
|
|
|
SetAllocString(Str, NewStr);
|
|
return TRUE;
|
|
}
|
|
|
|
HMENU
|
|
CreateContextMenuFromToolbarButtons(ULONG NumButtons,
|
|
TBBUTTON* Buttons,
|
|
ULONG IdBias)
|
|
{
|
|
ULONG i;
|
|
HMENU Menu;
|
|
|
|
Menu = CreatePopupMenu();
|
|
if (Menu == NULL)
|
|
{
|
|
return Menu;
|
|
}
|
|
|
|
for (i = 0; i < NumButtons; i++)
|
|
{
|
|
MENUITEMINFO Item;
|
|
|
|
ZeroMemory(&Item, sizeof(Item));
|
|
Item.cbSize = sizeof(Item);
|
|
Item.fMask = MIIM_TYPE;
|
|
if (Buttons->fsStyle & BTNS_SEP)
|
|
{
|
|
Item.fType = MFT_SEPARATOR;
|
|
}
|
|
else
|
|
{
|
|
Item.fMask |= MIIM_ID;
|
|
Item.fType = MFT_STRING;
|
|
Item.wID = (WORD)(Buttons->idCommand + IdBias);
|
|
Item.dwTypeData = (LPSTR)Buttons->iString;
|
|
}
|
|
|
|
if (!InsertMenuItem(Menu, i, TRUE, &Item))
|
|
{
|
|
DestroyMenu(Menu);
|
|
return NULL;
|
|
}
|
|
|
|
Buttons++;
|
|
}
|
|
|
|
DrawMenuBar(g_hwndFrame);
|
|
return Menu;
|
|
}
|
|
|
|
HWND
|
|
AddButtonBand(HWND Bar, PTSTR Text, PTSTR SizingText, UINT Id)
|
|
{
|
|
HWND Button;
|
|
HDC Dc;
|
|
RECT Rect;
|
|
|
|
Button = CreateWindowEx(0, "BUTTON", Text, WS_VISIBLE | WS_CHILD,
|
|
0, 0, 0, 0,
|
|
Bar, (HMENU)(UINT_PTR)Id, g_hInst, NULL);
|
|
if (Button == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
Rect.left = 0;
|
|
Rect.top = 0;
|
|
|
|
SendMessage(Button, WM_SETFONT, (WPARAM)g_Fonts[FONT_VARIABLE].Font, 0);
|
|
Dc = GetDC(Button);
|
|
if (Dc != NULL)
|
|
{
|
|
SIZE Size;
|
|
|
|
GetTextExtentPoint32(Dc, SizingText, strlen(SizingText), &Size);
|
|
Rect.right = Size.cx;
|
|
Rect.bottom = Size.cy;
|
|
ReleaseDC(Button, Dc);
|
|
}
|
|
else
|
|
{
|
|
Rect.right = strlen(Text) * g_Fonts[FONT_FIXED].Metrics.tmAveCharWidth;
|
|
Rect.bottom = g_Fonts[FONT_FIXED].Metrics.tmHeight;
|
|
}
|
|
|
|
REBARBANDINFO BandInfo;
|
|
BandInfo.cbSize = sizeof(BandInfo);
|
|
BandInfo.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE;
|
|
BandInfo.fStyle = RBBS_FIXEDSIZE;
|
|
BandInfo.hwndChild = Button;
|
|
BandInfo.cxMinChild = Rect.right - Rect.left +
|
|
4 * GetSystemMetrics(SM_CXEDGE);
|
|
BandInfo.cyMinChild = Rect.bottom - Rect.top +
|
|
2 * GetSystemMetrics(SM_CYEDGE);
|
|
SendMessage(Bar, RB_INSERTBAND, -1, (LPARAM)&BandInfo);
|
|
|
|
return Button;
|
|
}
|