1632 lines
40 KiB
C++
1632 lines
40 KiB
C++
/*++
|
||
|
||
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;
|
||
}
|