1108 lines
30 KiB
C
1108 lines
30 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1990-1998, Microsoft Corporation All rights reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
dlgs.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains the common functions for the Win32 common dialogs.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
// precompiled headers
|
||
|
#include "precomp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include "util.h"
|
||
|
//
|
||
|
// Global Variables.
|
||
|
//
|
||
|
|
||
|
extern BOOL bInitializing;
|
||
|
extern DWORD g_tlsiExtError;
|
||
|
|
||
|
//
|
||
|
// Function Prototypes.
|
||
|
//
|
||
|
|
||
|
LONG
|
||
|
RgbInvertRgb(
|
||
|
LONG rgbOld);
|
||
|
|
||
|
const struct _ERRORMAP
|
||
|
{
|
||
|
DWORD dwCommDlgError;
|
||
|
DWORD dwWin32Error;
|
||
|
} ERRORMAP[] =
|
||
|
{
|
||
|
{ CDERR_INITIALIZATION , ERROR_INVALID_PARAMETER},
|
||
|
{ PDERR_INITFAILURE , ERROR_INVALID_PARAMETER},
|
||
|
{ CDERR_STRUCTSIZE , ERROR_INVALID_PARAMETER},
|
||
|
{ CDERR_NOTEMPLATE , ERROR_INVALID_PARAMETER},
|
||
|
{ CDERR_NOHINSTANCE , ERROR_INVALID_PARAMETER},
|
||
|
{ CDERR_NOHOOK , ERROR_INVALID_PARAMETER},
|
||
|
{ CDERR_MEMALLOCFAILURE , ERROR_OUTOFMEMORY},
|
||
|
{ CDERR_LOCKRESFAILURE , ERROR_INVALID_HANDLE},
|
||
|
{ CDERR_DIALOGFAILURE , E_FAIL},
|
||
|
{ PDERR_SETUPFAILURE , ERROR_INVALID_PARAMETER},
|
||
|
{ PDERR_RETDEFFAILURE , ERROR_INVALID_PARAMETER},
|
||
|
{ FNERR_BUFFERTOOSMALL , ERROR_INSUFFICIENT_BUFFER},
|
||
|
{ FRERR_BUFFERLENGTHZERO, ERROR_INSUFFICIENT_BUFFER},
|
||
|
{ FNERR_INVALIDFILENAME , ERROR_INVALID_NAME},
|
||
|
{ PDERR_NODEFAULTPRN , E_FAIL},
|
||
|
{ CFERR_NOFONTS , E_FAIL},
|
||
|
{ CFERR_MAXLESSTHANMIN , ERROR_INVALID_PARAMETER},
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// StoreExtendedError
|
||
|
//
|
||
|
// Stores an extended error code for the next call to
|
||
|
// CommDlgExtendedError.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void StoreExtendedError(
|
||
|
DWORD dwError)
|
||
|
{
|
||
|
int i;
|
||
|
for (i=0; i < ARRAYSIZE(ERRORMAP); i++)
|
||
|
{
|
||
|
if (ERRORMAP[i].dwCommDlgError == dwError)
|
||
|
{
|
||
|
SetLastError(ERRORMAP[i].dwWin32Error);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
TlsSetValue(g_tlsiExtError, UlongToPtr(dwError));
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetStoredExtendedError
|
||
|
//
|
||
|
// Retieves the stored extended error code.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
DWORD GetStoredExtendedError(void)
|
||
|
{
|
||
|
DWORD dwError;
|
||
|
|
||
|
dwError = PtrToUlong(TlsGetValue(g_tlsiExtError));
|
||
|
|
||
|
return (dwError);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// CommDlgExtendedError
|
||
|
//
|
||
|
// Provides additional information about dialog failure.
|
||
|
// This should be called immediately after failure.
|
||
|
//
|
||
|
// Returns: LO word - error code
|
||
|
// HI word - error specific info
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
DWORD WINAPI CommDlgExtendedError()
|
||
|
{
|
||
|
return (GetStoredExtendedError());
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// HourGlass
|
||
|
//
|
||
|
// Turn hourglass on or off.
|
||
|
//
|
||
|
// bOn - specifies ON or OFF
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
VOID HourGlass(
|
||
|
BOOL bOn)
|
||
|
{
|
||
|
//
|
||
|
// Change cursor to hourglass.
|
||
|
//
|
||
|
if (!bInitializing)
|
||
|
{
|
||
|
if (!bMouse)
|
||
|
{
|
||
|
ShowCursor(bCursorLock = bOn);
|
||
|
}
|
||
|
SetCursor(LoadCursor(NULL, bOn ? IDC_WAIT : IDC_ARROW));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// LoadAlterBitmap
|
||
|
//
|
||
|
// Loads a bitmap given its name and gives all the pixels that are
|
||
|
// a certain color a new color.
|
||
|
//
|
||
|
// Returns: NULL - failed
|
||
|
// handle to the bitmap loaded - success
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
HBITMAP WINAPI LoadAlterBitmap(
|
||
|
int id,
|
||
|
DWORD rgbReplace,
|
||
|
DWORD rgbInstead)
|
||
|
{
|
||
|
LPBITMAPINFOHEADER qbihInfo;
|
||
|
HDC hdcScreen;
|
||
|
BOOL fFound;
|
||
|
HANDLE hresLoad;
|
||
|
HANDLE hres;
|
||
|
LPLONG qlng;
|
||
|
DWORD *qlngReplace; // points to bits that are replaced
|
||
|
LPBYTE qbBits;
|
||
|
HANDLE hbmp;
|
||
|
LPBITMAPINFOHEADER lpBitmapInfo;
|
||
|
UINT cbBitmapSize;
|
||
|
|
||
|
hresLoad = FindResource(g_hinst, MAKEINTRESOURCE(id), RT_BITMAP);
|
||
|
if (hresLoad == HNULL)
|
||
|
{
|
||
|
return (HNULL);
|
||
|
}
|
||
|
hres = LoadResource(g_hinst, hresLoad);
|
||
|
if (hres == HNULL)
|
||
|
{
|
||
|
return (HNULL);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Lock the bitmap data and make a copy of it for the mask and the
|
||
|
// bitmap.
|
||
|
//
|
||
|
cbBitmapSize = SizeofResource(g_hinst, hresLoad);
|
||
|
lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hres);
|
||
|
|
||
|
qbihInfo = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, cbBitmapSize);
|
||
|
|
||
|
if ((lpBitmapInfo == NULL) || (qbihInfo == NULL))
|
||
|
{
|
||
|
return (NULL);
|
||
|
}
|
||
|
|
||
|
memcpy((TCHAR *)qbihInfo, (TCHAR *)lpBitmapInfo, cbBitmapSize);
|
||
|
|
||
|
//
|
||
|
// Get a pointer into the color table of the bitmaps, cache the
|
||
|
// number of bits per pixel.
|
||
|
//
|
||
|
rgbReplace = RgbInvertRgb(rgbReplace);
|
||
|
rgbInstead = RgbInvertRgb(rgbInstead);
|
||
|
|
||
|
qlng = (LPLONG)((LPSTR)(qbihInfo) + qbihInfo->biSize);
|
||
|
|
||
|
fFound = FALSE;
|
||
|
while (!fFound)
|
||
|
{
|
||
|
if (*qlng == (LONG)rgbReplace)
|
||
|
{
|
||
|
fFound = TRUE;
|
||
|
qlngReplace = (DWORD *)qlng;
|
||
|
*qlng = (LONG)rgbInstead;
|
||
|
}
|
||
|
qlng++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// First skip over the header structure.
|
||
|
//
|
||
|
qbBits = (LPBYTE)(qbihInfo + 1);
|
||
|
|
||
|
//
|
||
|
// Skip the color table entries, if any.
|
||
|
//
|
||
|
qbBits += (1 << (qbihInfo->biBitCount)) * sizeof(RGBQUAD);
|
||
|
|
||
|
//
|
||
|
// Create a color bitmap compatible with the display device.
|
||
|
//
|
||
|
hdcScreen = GetDC(HNULL);
|
||
|
if (hdcScreen != HNULL)
|
||
|
{
|
||
|
hbmp = CreateDIBitmap( hdcScreen,
|
||
|
qbihInfo,
|
||
|
(LONG)CBM_INIT,
|
||
|
qbBits,
|
||
|
(LPBITMAPINFO)qbihInfo,
|
||
|
DIB_RGB_COLORS );
|
||
|
ReleaseDC(HNULL, hdcScreen);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Reset color bits to original value.
|
||
|
//
|
||
|
*qlngReplace = (LONG)rgbReplace;
|
||
|
|
||
|
LocalFree(qbihInfo);
|
||
|
return (hbmp);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// RgbInvertRgb
|
||
|
//
|
||
|
// Reverses the byte order of the RGB value (for file format).
|
||
|
//
|
||
|
// Returns the new color value (RGB to BGR).
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
LONG RgbInvertRgb(
|
||
|
LONG rgbOld)
|
||
|
{
|
||
|
LONG lRet;
|
||
|
BYTE R, G, B;
|
||
|
|
||
|
R = GetRValue(rgbOld);
|
||
|
G = GetGValue(rgbOld);
|
||
|
B = GetBValue(rgbOld);
|
||
|
|
||
|
lRet = (LONG)RGB(B, G, R);
|
||
|
|
||
|
return (lRet);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// HbmpLoadBmp
|
||
|
//
|
||
|
// Loads in a bitmap.
|
||
|
//
|
||
|
// Returns: Bitmap handle - success
|
||
|
// HNULL - failure
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#if 0
|
||
|
HBITMAP HbmpLoadBmp(
|
||
|
WORD bmp)
|
||
|
{
|
||
|
HBITMAP hbmp;
|
||
|
CHAR szBitmap[cbResNameMax];
|
||
|
|
||
|
hbmp = HNULL;
|
||
|
if (LoadString(g_hinst, bmp, (LPTSTR)szBitmap, cbResNameMax - 1))
|
||
|
{
|
||
|
hbmp = LoadBitmap(g_hinst, (LPCTSTR)szBitmap);
|
||
|
}
|
||
|
return (hbmp);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// AddNetButton
|
||
|
//
|
||
|
// Attempts to add a network button to the open, save, or print dialogs.
|
||
|
//
|
||
|
// hDlg - dialog to add button to
|
||
|
// hInstance - instance handle for dlg
|
||
|
// dyBottomMargin - DUs to bottom edge
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#define xDUsToPels(DUs, lDlgBaseUnits) \
|
||
|
(int)(((DUs) * (int)LOWORD((lDlgBaseUnits))) / 4)
|
||
|
|
||
|
#define yDUsToPels(DUs, lDlgBaseUnits) \
|
||
|
(int)(((DUs) * (int)HIWORD((lDlgBaseUnits))) / 8)
|
||
|
|
||
|
VOID AddNetButton(
|
||
|
HWND hDlg,
|
||
|
HANDLE hInstance,
|
||
|
int dyBottomMargin,
|
||
|
BOOL bAddAccel,
|
||
|
BOOL bTryLowerRight,
|
||
|
BOOL bTryLowerLeft)
|
||
|
{
|
||
|
LONG lDlgBaseUnits;
|
||
|
RECT rcDlg, rcCtrl, rcTmp;
|
||
|
LONG xButton, yButton;
|
||
|
LONG dxButton, dyButton;
|
||
|
LONG dxDlgFrame, dyDlgFrame;
|
||
|
LONG yDlgHeight, xDlgWidth;
|
||
|
HWND hwndButton, hCtrl, hLastCtrl, hTmp, hSave;
|
||
|
HFONT hFont;
|
||
|
POINT ptTopLeft, ptTopRight, ptCenter, ptBtmLeft, ptBtmRight, ptTopLeftTmp;
|
||
|
TCHAR szNetwork[MAX_PATH];
|
||
|
|
||
|
//
|
||
|
// Make sure a network button (psh14) doesn't already exist in
|
||
|
// the dialog.
|
||
|
//
|
||
|
if (GetDlgItem(hDlg, psh14))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get dialog coordinate info.
|
||
|
//
|
||
|
lDlgBaseUnits = GetDialogBaseUnits();
|
||
|
|
||
|
dxDlgFrame = GetSystemMetrics(SM_CXDLGFRAME);
|
||
|
dyDlgFrame = GetSystemMetrics(SM_CYDLGFRAME);
|
||
|
|
||
|
GetWindowRect(hDlg, &rcDlg);
|
||
|
|
||
|
rcDlg.left += dxDlgFrame;
|
||
|
rcDlg.right -= dxDlgFrame;
|
||
|
rcDlg.top += dyDlgFrame + GetSystemMetrics(SM_CYCAPTION);
|
||
|
rcDlg.bottom -= dyDlgFrame;
|
||
|
|
||
|
//
|
||
|
// Get the OK button.
|
||
|
//
|
||
|
if (!(hCtrl = GetDlgItem(hDlg, IDOK)))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GetWindowRect(hCtrl, &rcCtrl);
|
||
|
|
||
|
ptTopLeft.x = rcCtrl.left;
|
||
|
ptTopLeft.y = rcCtrl.top;
|
||
|
|
||
|
//
|
||
|
// Make sure the OK button isn't outside the dialog.
|
||
|
//
|
||
|
if (!PtInRect(&rcDlg, ptTopLeft))
|
||
|
{
|
||
|
//
|
||
|
// Try the CANCEL button.
|
||
|
//
|
||
|
if (!(hCtrl = GetDlgItem(hDlg, IDCANCEL)))
|
||
|
{
|
||
|
//
|
||
|
// Both OK and CANCEL do not exist, so return.
|
||
|
//
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The check for the Cancel button outside the dialog is handled
|
||
|
// below.
|
||
|
//
|
||
|
GetWindowRect(hCtrl, &rcCtrl);
|
||
|
}
|
||
|
hSave = hCtrl;
|
||
|
|
||
|
#ifdef UNICODE
|
||
|
//
|
||
|
// Get the full hDlg value if coming from WOW.
|
||
|
//
|
||
|
if (IS_INTRESOURCE(hDlg))
|
||
|
{
|
||
|
HWND hNewDlg = GetParent(hCtrl);
|
||
|
|
||
|
if (hDlg == (HWND)LOWORD(hNewDlg))
|
||
|
{
|
||
|
hDlg = hNewDlg;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Save the coordinate info of the button.
|
||
|
//
|
||
|
dxButton = rcCtrl.right - rcCtrl.left;
|
||
|
dyButton = rcCtrl.bottom - rcCtrl.top;
|
||
|
|
||
|
xButton = rcCtrl.left;
|
||
|
yButton = rcCtrl.bottom + yDUsToPels(4, lDlgBaseUnits);
|
||
|
|
||
|
yDlgHeight = rcDlg.bottom - yDUsToPels(dyBottomMargin, lDlgBaseUnits);
|
||
|
|
||
|
//
|
||
|
// Try to insert the network button in the lower right corner
|
||
|
// of dialog box.
|
||
|
//
|
||
|
if (bTryLowerRight && (hTmp = GetDlgItem(hDlg, cmb2)))
|
||
|
{
|
||
|
//
|
||
|
// See if the network button can be inserted in the
|
||
|
// lower right corner of the dialog box.
|
||
|
//
|
||
|
hLastCtrl = hCtrl;
|
||
|
GetWindowRect(hTmp, &rcTmp);
|
||
|
yButton = rcTmp.top;
|
||
|
|
||
|
//
|
||
|
// Set the coordinates of the new button.
|
||
|
//
|
||
|
ptTopLeft.x = ptBtmLeft.x = xButton;
|
||
|
ptTopLeft.y = ptTopRight.y = yButton;
|
||
|
ptTopRight.x = ptBtmRight.x = xButton + dxButton;
|
||
|
ptBtmLeft.y = ptBtmRight.y = yButton + dyButton;
|
||
|
ptCenter.x = xButton + dxButton / 2;
|
||
|
ptCenter.y = yButton + dyButton / 2;
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptTopLeft);
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptBtmLeft);
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptTopRight);
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptBtmRight);
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptCenter);
|
||
|
|
||
|
//
|
||
|
// See if the new button is over any other buttons.
|
||
|
//
|
||
|
if (((yButton + dyButton) < yDlgHeight) &&
|
||
|
((ChildWindowFromPoint(hDlg, ptTopLeft) == hDlg) &&
|
||
|
(ChildWindowFromPoint(hDlg, ptTopRight) == hDlg) &&
|
||
|
(ChildWindowFromPoint(hDlg, ptCenter) == hDlg) &&
|
||
|
(ChildWindowFromPoint(hDlg, ptBtmLeft) == hDlg) &&
|
||
|
(ChildWindowFromPoint(hDlg, ptBtmRight) == hDlg)))
|
||
|
{
|
||
|
//
|
||
|
// If the last control is the OK button and there is a
|
||
|
// HELP button, then the last control should be the
|
||
|
// HELP button.
|
||
|
//
|
||
|
if ((hLastCtrl == GetDlgItem(hDlg, IDOK)) &&
|
||
|
(hCtrl = GetDlgItem(hDlg, pshHelp)))
|
||
|
{
|
||
|
GetWindowRect(hCtrl, &rcCtrl);
|
||
|
ptTopLeftTmp.x = rcCtrl.left;
|
||
|
ptTopLeftTmp.y = rcCtrl.top;
|
||
|
|
||
|
//
|
||
|
// Make sure the HELP button isn't outside the dialog
|
||
|
// and then set the last control to be the HELP button.
|
||
|
//
|
||
|
if (PtInRect(&rcDlg, ptTopLeftTmp))
|
||
|
{
|
||
|
hLastCtrl = hCtrl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the last control is still the OK button and there is a
|
||
|
// CANCEL button, then the last control should be the
|
||
|
// CANCEL button.
|
||
|
//
|
||
|
if ((hLastCtrl == GetDlgItem(hDlg, IDOK)) &&
|
||
|
(hCtrl = GetDlgItem(hDlg, IDCANCEL)))
|
||
|
{
|
||
|
GetWindowRect(hCtrl, &rcCtrl);
|
||
|
ptTopLeftTmp.x = rcCtrl.left;
|
||
|
ptTopLeftTmp.y = rcCtrl.top;
|
||
|
|
||
|
//
|
||
|
// Make sure the CANCEL button isn't outside the dialog
|
||
|
// and then set the last control to be the CANCEL button.
|
||
|
//
|
||
|
if (PtInRect(&rcDlg, ptTopLeftTmp))
|
||
|
{
|
||
|
hLastCtrl = hCtrl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
goto FoundPlace;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Reset yButton.
|
||
|
//
|
||
|
yButton = rcCtrl.bottom + yDUsToPels(4, lDlgBaseUnits);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Try to insert the network button vertically below the other
|
||
|
// control buttons.
|
||
|
//
|
||
|
while (hCtrl != NULL)
|
||
|
{
|
||
|
//
|
||
|
// Move vertically down and see if there is space.
|
||
|
//
|
||
|
hLastCtrl = hCtrl;
|
||
|
GetWindowRect(hCtrl, &rcCtrl);
|
||
|
yButton = rcCtrl.bottom + yDUsToPels(4, lDlgBaseUnits);
|
||
|
|
||
|
//
|
||
|
// Make sure there is still room in the dialog.
|
||
|
//
|
||
|
if ((yButton + dyButton) > yDlgHeight)
|
||
|
{
|
||
|
//
|
||
|
// No space.
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the coordinates of the new button.
|
||
|
//
|
||
|
ptTopLeft.x = ptBtmLeft.x = xButton;
|
||
|
ptTopLeft.y = ptTopRight.y = yButton;
|
||
|
ptTopRight.x = ptBtmRight.x = xButton + dxButton;
|
||
|
ptBtmLeft.y = ptBtmRight.y = yButton + dyButton;
|
||
|
ptCenter.x = xButton + dxButton / 2;
|
||
|
ptCenter.y = yButton + dyButton / 2;
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptTopLeft);
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptBtmLeft);
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptTopRight);
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptBtmRight);
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptCenter);
|
||
|
|
||
|
//
|
||
|
// See if the new button is over any other buttons.
|
||
|
//
|
||
|
if (((hCtrl = ChildWindowFromPoint(hDlg, ptTopLeft)) == hDlg) &&
|
||
|
((hCtrl = ChildWindowFromPoint(hDlg, ptTopRight)) == hDlg) &&
|
||
|
((hCtrl = ChildWindowFromPoint(hDlg, ptCenter)) == hDlg) &&
|
||
|
((hCtrl = ChildWindowFromPoint(hDlg, ptBtmLeft)) == hDlg) &&
|
||
|
((hCtrl = ChildWindowFromPoint(hDlg, ptBtmRight)) == hDlg))
|
||
|
{
|
||
|
goto FoundPlace;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Try to insert the network button in the lower left corner of
|
||
|
// the dialog box.
|
||
|
//
|
||
|
if (bTryLowerLeft)
|
||
|
{
|
||
|
//
|
||
|
// Get the width of the dialog to make sure the button doesn't
|
||
|
// go off the side of the dialog.
|
||
|
//
|
||
|
xDlgWidth = rcDlg.right - xDUsToPels(FILE_RIGHT_MARGIN, lDlgBaseUnits);
|
||
|
|
||
|
//
|
||
|
// Use the OK or CANCEL button saved earlier to get the size of
|
||
|
// the buttons.
|
||
|
//
|
||
|
hCtrl = hSave;
|
||
|
|
||
|
//
|
||
|
// Start at the far left of the dialog.
|
||
|
//
|
||
|
// NOTE: We know that hCtrl is not NULL at this point because
|
||
|
// otherwise we would have returned earlier.
|
||
|
//
|
||
|
// The print dialogs have a left margin of 8.
|
||
|
//
|
||
|
GetWindowRect(hCtrl, &rcCtrl);
|
||
|
xButton = rcDlg.left + xDUsToPels(FILE_LEFT_MARGIN + 3, lDlgBaseUnits);
|
||
|
yButton = rcCtrl.top;
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
hLastCtrl = hCtrl;
|
||
|
|
||
|
//
|
||
|
// Make sure there is still room in the dialog.
|
||
|
//
|
||
|
if ((xButton + dxButton) > xDlgWidth)
|
||
|
{
|
||
|
//
|
||
|
// No space.
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the coordinates of the new button.
|
||
|
//
|
||
|
ptTopLeft.x = ptBtmLeft.x = xButton;
|
||
|
ptTopLeft.y = ptTopRight.y = yButton;
|
||
|
ptTopRight.x = ptBtmRight.x = xButton + dxButton;
|
||
|
ptBtmLeft.y = ptBtmRight.y = yButton + dyButton;
|
||
|
ptCenter.x = xButton + dxButton / 2;
|
||
|
ptCenter.y = yButton + dyButton / 2;
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptTopLeft);
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptBtmLeft);
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptTopRight);
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptBtmRight);
|
||
|
ScreenToClient(hDlg, (LPPOINT)&ptCenter);
|
||
|
|
||
|
//
|
||
|
// See if the new button is over any other buttons.
|
||
|
//
|
||
|
if ( ( ((hCtrl = ChildWindowFromPoint(hDlg, ptTopLeft)) == hDlg) &&
|
||
|
((hCtrl = ChildWindowFromPoint(hDlg, ptTopRight)) == hDlg) &&
|
||
|
((hCtrl = ChildWindowFromPoint(hDlg, ptCenter)) == hDlg) &&
|
||
|
((hCtrl = ChildWindowFromPoint(hDlg, ptBtmLeft)) == hDlg) &&
|
||
|
((hCtrl = ChildWindowFromPoint(hDlg, ptBtmRight)) == hDlg) ) )
|
||
|
{
|
||
|
//
|
||
|
// If the last control is the OK button and there is a
|
||
|
// HELP button, then the last control should be the
|
||
|
// HELP button.
|
||
|
//
|
||
|
if ((hLastCtrl == GetDlgItem(hDlg, IDOK)) &&
|
||
|
(hCtrl = GetDlgItem(hDlg, pshHelp)))
|
||
|
{
|
||
|
GetWindowRect(hCtrl, &rcCtrl);
|
||
|
ptTopLeftTmp.x = rcCtrl.left;
|
||
|
ptTopLeftTmp.y = rcCtrl.top;
|
||
|
|
||
|
//
|
||
|
// Make sure the HELP button isn't outside the dialog
|
||
|
// and then set the last control to be the HELP button.
|
||
|
//
|
||
|
if (PtInRect(&rcDlg, ptTopLeftTmp))
|
||
|
{
|
||
|
hLastCtrl = hCtrl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the last control is still the OK button and there is a
|
||
|
// CANCEL button, then the last control should be the
|
||
|
// CANCEL button.
|
||
|
//
|
||
|
if ((hLastCtrl == GetDlgItem(hDlg, IDOK)) &&
|
||
|
(hCtrl = GetDlgItem(hDlg, IDCANCEL)))
|
||
|
{
|
||
|
GetWindowRect(hCtrl, &rcCtrl);
|
||
|
ptTopLeftTmp.x = rcCtrl.left;
|
||
|
ptTopLeftTmp.y = rcCtrl.top;
|
||
|
|
||
|
//
|
||
|
// Make sure the CANCEL button isn't outside the dialog
|
||
|
// and then set the last control to be the CANCEL button.
|
||
|
//
|
||
|
if (PtInRect(&rcDlg, ptTopLeftTmp))
|
||
|
{
|
||
|
hLastCtrl = hCtrl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
goto FoundPlace;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure we encountered another control and that we
|
||
|
// didn't go off the end of the dialog.
|
||
|
//
|
||
|
if (!hCtrl)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Move over to the right and see if there is space.
|
||
|
//
|
||
|
GetWindowRect(hCtrl, &rcCtrl);
|
||
|
xButton = rcCtrl.right + xDUsToPels(4, lDlgBaseUnits);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
|
||
|
FoundPlace:
|
||
|
|
||
|
xButton = ptTopLeft.x;
|
||
|
yButton = ptTopLeft.y;
|
||
|
|
||
|
//If it a mirrored Dlg then the direction will be to the right.
|
||
|
if (IS_WINDOW_RTL_MIRRORED(hDlg))
|
||
|
xButton -= dxButton;
|
||
|
|
||
|
#ifndef UNICODE
|
||
|
//
|
||
|
// For non-localized apps that don't include the network button as part
|
||
|
// of their template, don't add a Far East one because the characters
|
||
|
// will not be displayed correctly.
|
||
|
//
|
||
|
{
|
||
|
#define NetworkButtonText TEXT("Network...")
|
||
|
#define NetworkButtonTextAccel TEXT("Net&work...")
|
||
|
|
||
|
CPINFO cpinfo;
|
||
|
|
||
|
if ((GetCPInfo(CP_ACP, &cpinfo)) && (cpinfo.MaxCharSize > 1))
|
||
|
{
|
||
|
TEXTMETRIC tm;
|
||
|
HFONT hPrevFont;
|
||
|
HWND hIDOK = GetDlgItem(hDlg, IDOK);
|
||
|
HDC hDC = GetDC(hIDOK);
|
||
|
|
||
|
hFont = (HFONT)SendMessage(hIDOK, WM_GETFONT, 0, 0L);
|
||
|
if (hFont != NULL)
|
||
|
{
|
||
|
hPrevFont = SelectObject(hDC, hFont);
|
||
|
GetTextMetrics(hDC, &tm);
|
||
|
SelectObject(hDC, hPrevFont);
|
||
|
ReleaseDC(hIDOK, hDC);
|
||
|
|
||
|
if (tm.tmCharSet == ANSI_CHARSET)
|
||
|
{
|
||
|
lstrcpy( szNetwork,
|
||
|
bAddAccel ? NetworkButtonTextAccel : NetworkButtonText );
|
||
|
goto CreateNetworkButton;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (CDLoadString( g_hinst,
|
||
|
(bAddAccel ? iszNetworkButtonTextAccel : iszNetworkButtonText),
|
||
|
(LPTSTR)szNetwork,
|
||
|
MAX_PATH ))
|
||
|
{
|
||
|
#ifndef UNICODE
|
||
|
CreateNetworkButton:
|
||
|
#endif
|
||
|
hwndButton = CreateWindow( TEXT("button"),
|
||
|
szNetwork,
|
||
|
WS_VISIBLE | WS_CHILD | WS_GROUP |
|
||
|
WS_TABSTOP | BS_PUSHBUTTON,
|
||
|
xButton,
|
||
|
yButton,
|
||
|
dxButton,
|
||
|
dyButton,
|
||
|
hDlg,
|
||
|
NULL,
|
||
|
hInstance,
|
||
|
NULL );
|
||
|
|
||
|
if (hwndButton != NULL)
|
||
|
{
|
||
|
SetWindowLong(hwndButton, GWL_ID, psh14);
|
||
|
SetWindowPos( hwndButton,
|
||
|
hLastCtrl,
|
||
|
0, 0, 0, 0,
|
||
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
|
||
|
hFont = (HFONT)SendDlgItemMessage(hDlg, IDOK, WM_GETFONT, 0, 0L);
|
||
|
SendMessage(hwndButton, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE,0));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// IsNetworkInstalled
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL IsNetworkInstalled()
|
||
|
{
|
||
|
if (GetSystemMetrics(SM_NETWORK) & RNC_NETWORKS)
|
||
|
{
|
||
|
return (TRUE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#ifdef WINNT
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Ssync_ANSI_UNICODE_Struct_For_WOW (This is exported for WOW)
|
||
|
//
|
||
|
// For WOW support on NT only.
|
||
|
//
|
||
|
// When a 16-bit app calls one of the comdlg API's, WOW thunks the 16-bit
|
||
|
// comdlg struct passed by the app to a 32-bit ANSI struct. Comdlg32 code
|
||
|
// then thunks the 32-bit ANSI struct into a UNICODE struct. This scheme
|
||
|
// creates a problem for WOW apps because on Win3.1, the app and comdlg16
|
||
|
// share the same structure. When either updates the struct, the other is
|
||
|
// aware of the change.
|
||
|
//
|
||
|
// This function allows us to sychronize the UNICODE struct with the app's
|
||
|
// 16-bit struct & vice versa from WOW.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
VOID Ssync_ANSI_UNICODE_Struct_For_WOW(
|
||
|
HWND hDlg,
|
||
|
BOOL fDirection,
|
||
|
DWORD dwID)
|
||
|
{
|
||
|
switch (dwID)
|
||
|
{
|
||
|
case ( WOW_CHOOSECOLOR ) :
|
||
|
{
|
||
|
Ssync_ANSI_UNICODE_CC_For_WOW(hDlg, fDirection);
|
||
|
break;
|
||
|
}
|
||
|
case ( WOW_CHOOSEFONT ) :
|
||
|
{
|
||
|
Ssync_ANSI_UNICODE_CF_For_WOW(hDlg, fDirection);
|
||
|
break;
|
||
|
}
|
||
|
case ( WOW_OPENFILENAME ) :
|
||
|
{
|
||
|
Ssync_ANSI_UNICODE_OFN_For_WOW(hDlg, fDirection);
|
||
|
break;
|
||
|
}
|
||
|
case ( WOW_PRINTDLG ) :
|
||
|
{
|
||
|
Ssync_ANSI_UNICODE_PD_For_WOW(hDlg, fDirection);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// case not needed for FINDREPLACE
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#ifdef WX86
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Wx86GetX86Callback
|
||
|
//
|
||
|
// Creates a RISC-callable alias for a x86 hook function pointer.
|
||
|
//
|
||
|
// lpfnHook - x86 address of hook
|
||
|
//
|
||
|
// Returns a function pointer which can be called from RISC.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
PVOID Wx86GetX86Callback(
|
||
|
PVOID lpfnHook)
|
||
|
{
|
||
|
if (!lpfnHook)
|
||
|
{
|
||
|
return (NULL);
|
||
|
}
|
||
|
|
||
|
if (!pfnAllocCallBx86)
|
||
|
{
|
||
|
HMODULE hMod;
|
||
|
|
||
|
if (!Wx86CurrentTib())
|
||
|
{
|
||
|
//
|
||
|
// Wx86 is not running in this thread. Assume a RISC app has
|
||
|
// passed a bad flag value and that lpfnHook is already a RISC
|
||
|
// function pointer.
|
||
|
//
|
||
|
return (lpfnHook);
|
||
|
}
|
||
|
|
||
|
hMod = GetModuleHandle(TEXT("wx86.dll"));
|
||
|
if (hMod == NULL)
|
||
|
{
|
||
|
//
|
||
|
// Wx86 is running, but wx86.dll is not loaded! This should
|
||
|
// never happen, but if it does, assume lpfnHook is already a
|
||
|
// RISC pointer.
|
||
|
//
|
||
|
return (lpfnHook);
|
||
|
}
|
||
|
pfnAllocCallBx86 = (PALLOCCALLBX86)GetProcAddress( hMod,
|
||
|
"AllocCallBx86" );
|
||
|
if (!pfnAllocCallBx86)
|
||
|
{
|
||
|
//
|
||
|
// Something has gone terribly wrong!
|
||
|
//
|
||
|
return (lpfnHook);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Call into Wx86.dll to create a RISC-to-x86 callback which takes
|
||
|
// 4 parameters and has no logging.
|
||
|
//
|
||
|
return (*pfnAllocCallBx86)(lpfnHook, 4, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// CDLoadString
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
int CDLoadString(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax)
|
||
|
{
|
||
|
return CDLoadStringEx(CP_ACP, hInstance, uID, lpBuffer, nBufferMax);
|
||
|
}
|
||
|
|
||
|
// CDLoadStringEx takes a codepage, so we can store unicode strings in the resource file
|
||
|
|
||
|
int CDLoadStringEx(UINT cp, HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax)
|
||
|
{
|
||
|
HRSRC hResInfo;
|
||
|
int cch = 0;
|
||
|
LPWSTR lpwsz;
|
||
|
LANGID LangID;
|
||
|
|
||
|
if (!GET_BIDI_LOCALIZED_SYSTEM_LANGID(NULL)) {
|
||
|
#ifdef WINNT
|
||
|
return LoadString(hInstance, uID, lpBuffer, nBufferMax);
|
||
|
#else
|
||
|
lpwsz = (LPWSTR) LocalAlloc(NONZEROLPTR, nBufferMax * sizeof(WCHAR));
|
||
|
if (lpwsz)
|
||
|
{
|
||
|
int iRet;
|
||
|
LoadStringWrapW(hInstance, uID, lpwsz, nBufferMax);
|
||
|
iRet = WideCharToMultiByte(cp, 0, lpwsz, -1, lpBuffer, nBufferMax, NULL, NULL);
|
||
|
LocalFree(lpwsz);
|
||
|
return iRet;
|
||
|
}
|
||
|
return 0;
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
LangID = (LANGID)TlsGetValue(g_tlsLangID);
|
||
|
|
||
|
if (!LangID || MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) == LangID) {
|
||
|
return LoadString(hInstance, uID, lpBuffer, nBufferMax);
|
||
|
}
|
||
|
|
||
|
if (!lpBuffer || (nBufferMax-- == 0))
|
||
|
return 0;
|
||
|
|
||
|
// String Tables are broken up into 16 string resources. Find the resource
|
||
|
// containing the string we are interested in.
|
||
|
if (hResInfo = FindResourceExFallback(hInstance, RT_STRING, MAKEINTRESOURCE((uID>>4)+1), LangID)) {
|
||
|
|
||
|
// Load the resource. Note LoadResource returns an address.
|
||
|
if (lpwsz = (LPWSTR)LoadResource(hInstance, hResInfo)) {
|
||
|
// Move past the other strings in this resource.
|
||
|
// (16 strings in a segment -> & 0x0F)
|
||
|
for (uID %= 16; uID; uID--) {
|
||
|
lpwsz += *lpwsz + 1;
|
||
|
}
|
||
|
cch = min(*lpwsz, nBufferMax - 1);
|
||
|
#ifdef UNICODE
|
||
|
// Copy the string into the buffer;
|
||
|
memcpy(lpBuffer, lpwsz+1, cch*sizeof(WCHAR));
|
||
|
#else
|
||
|
// Copy the string into the buffer, converting to Ansi.
|
||
|
cch= WideCharToMultiByte( CP_ACP, 0, lpwsz+1, cch, lpBuffer, cch, NULL, NULL);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lpBuffer[cch] = 0;
|
||
|
return cch;
|
||
|
}
|
||
|
|
||
|
#define ENGLISH_APP 0
|
||
|
#define MIRRORED_APP 1
|
||
|
#define BIDI_APP 2
|
||
|
|
||
|
DWORD GetAppType(HWND hWnd) {
|
||
|
DWORD dwExStyle = 0;
|
||
|
HWND hWndT = hWnd;
|
||
|
DWORD dwAppType = ENGLISH_APP;
|
||
|
|
||
|
#ifdef CHECK_OWNER
|
||
|
//Check the window and its owners.
|
||
|
while (!dwExStyle && hWndT) {
|
||
|
dwExStyle = GetWindowLongA(hWndT, GWL_EXSTYLE) & (WS_EX_RIGHT | WS_EX_RTLREADING | RTL_MIRRORED_WINDOW);
|
||
|
hWndT = GetWindow(hWndT, GW_OWNER);
|
||
|
}
|
||
|
|
||
|
if (!dwExStyle) {
|
||
|
#endif
|
||
|
//If we still did not find then check the parents.
|
||
|
hWndT = hWnd;
|
||
|
while (!dwExStyle && hWndT) {
|
||
|
dwExStyle = GetWindowLongA(hWndT, GWL_EXSTYLE) & (WS_EX_RIGHT | WS_EX_RTLREADING | RTL_MIRRORED_WINDOW);
|
||
|
hWndT = GetParent(hWndT);
|
||
|
}
|
||
|
#ifdef CHECK_OWNER
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (dwExStyle & RTL_MIRRORED_WINDOW) {
|
||
|
dwAppType = MIRRORED_APP;
|
||
|
} else if (dwExStyle & (WS_EX_RIGHT | WS_EX_RTLREADING)) {
|
||
|
dwAppType = BIDI_APP;
|
||
|
}
|
||
|
|
||
|
return dwAppType;
|
||
|
}
|
||
|
|
||
|
DWORD GetTemplateType(HANDLE hDlgTemplate)
|
||
|
{
|
||
|
DWORD dwExStyle = 0;
|
||
|
DWORD dwAppType = ENGLISH_APP;
|
||
|
LPDLGTEMPLATE pDlgTemplate;
|
||
|
|
||
|
pDlgTemplate = (LPDLGTEMPLATE)LockResource(hDlgTemplate);
|
||
|
if (pDlgTemplate) {
|
||
|
if (((LPDLGTEMPLATEEX) pDlgTemplate)->wSignature == 0xFFFF) {
|
||
|
dwExStyle = ((LPDLGTEMPLATEEX) pDlgTemplate)->dwExStyle;
|
||
|
} else {
|
||
|
dwExStyle = pDlgTemplate->dwExtendedStyle;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (dwExStyle & RTL_MIRRORED_WINDOW) {
|
||
|
dwAppType = MIRRORED_APP;
|
||
|
} else if (dwExStyle & (WS_EX_RIGHT | WS_EX_RTLREADING)) {
|
||
|
dwAppType = BIDI_APP;
|
||
|
}
|
||
|
|
||
|
return dwAppType;
|
||
|
}
|
||
|
|
||
|
LANGID GetDialogLanguage(HWND hwndOwner, HANDLE hDlgTemplate)
|
||
|
{
|
||
|
LANGID LangID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
||
|
DWORD dwType;
|
||
|
|
||
|
if (GET_BIDI_LOCALIZED_SYSTEM_LANGID(&LangID)) {
|
||
|
if (hDlgTemplate == NULL) {
|
||
|
dwType = GetAppType(hwndOwner);
|
||
|
} else {
|
||
|
dwType = GetTemplateType(hDlgTemplate);
|
||
|
}
|
||
|
|
||
|
switch (dwType) {
|
||
|
case ENGLISH_APP :
|
||
|
LangID = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
||
|
break;
|
||
|
|
||
|
case MIRRORED_APP:
|
||
|
LangID = MAKELANGID(PRIMARYLANGID(LangID), SUBLANG_DEFAULT);
|
||
|
break;
|
||
|
|
||
|
case BIDI_APP :
|
||
|
LangID = MAKELANGID(PRIMARYLANGID(LangID), SUBLANG_SYS_DEFAULT);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return LangID;
|
||
|
}
|
||
|
|
||
|
|