home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
msdn_vcb
/
samples
/
vc98
/
sdk
/
sdktools
/
winnt
/
dlgedit
/
custcntl.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-10-05
|
43KB
|
1,594 lines
/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright (C) 1993-1997 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/
/****************************** Module Header *******************************
* Module Name: custcntl.c
*
* Contains functions to support custom controls.
*
* Functions:
* NewCustDlgProc()
* OpenCustomDialog()
* SelCustDialog()
* SelCustDlgProc()
* RemCustDlgProc()
* CustomWndProc()
* AddCustomLink()
* RemoveCustomLink()
* CallCustomStyle()
* CallCustomSizeToText()
* ReadCustomProfile()
* WriteCustomProfile()
* NewCustInit()
* NewCustOK()
* OpenDLLFile()
* CallCustomInfoA()
* SelCustInit()
* SelCustSelect()
* SelCustOK()
* RemCustInit()
* RemCustOK()
* AllocCUSTLINK()
* FreeCUSTLINK()
*
* Comments:
*
****************************************************************************/
#include "dlgedit.h"
#include "dlgfuncs.h"
#include "dlgextrn.h"
#include "dialogs.h"
#include "dlghelp.h"
#include <stdlib.h>
#include <string.h>
#include <commdlg.h>
/*
* Minimum margin around the sample control.
*/
#define SAMPLEMARGIN 4
STATICFN VOID NewCustInit(HWND hwnd);
STATICFN BOOL NewCustOK(HWND hwnd);
STATICFN VOID OpenDLLFile(LPTSTR pszFileName);
STATICFN UINT CallCustomInfoA(LPFNCCINFOA lpfnInfoA, LPCCINFO acciW,
INT nControls);
STATICFN VOID SelCustInit(HWND hwnd);
STATICFN VOID SelCustSelect(HWND hwnd);
STATICFN BOOL SelCustOK(HWND hwnd);
STATICFN VOID RemCustInit(HWND hwnd);
STATICFN BOOL RemCustOK(HWND hwnd);
STATICFN PCUSTLINK AllocCUSTLINK(LPCCINFO pcci, BOOL fEmulated,
BOOL fUnicodeDLL, LPTSTR pszFileName, HANDLE hmod);
STATICFN VOID FreeCUSTLINK(PCUSTLINK pclFree);
/*
* Used to return the pwcd that is chosen from the Select Custom
* Control dialog.
*/
static PWINDOWCLASSDESC pwcdChosen;
/*
* Has the window handle of the sample custom control in the
* Select Custom Control dialog.
*/
static HWND hwndCustomSample;
/************************************************************************
* NewCustDlgProc
*
* This is the Add Custom Control dialog procedure.
*
* :
*
************************************************************************/
DIALOGPROC NewCustDlgProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
NewCustInit(hwnd);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
if (NewCustOK(hwnd))
EndDialog(hwnd, IDOK);
break;
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
case IDHELPDLG:
WinHelp(ghwndMain, gszHelpFile, HELP_CONTEXT,
HELPID_NEWCUST);
break;
}
return TRUE;
default:
return FALSE;
}
}
/************************************************************************
* NewCustInit
*
* Processes the WM_INITDIALOG message for the New Temporary Custom Control
* dialog procedure.
*
* History:
*
************************************************************************/
STATICFN VOID NewCustInit(
HWND hwnd)
{
TCHAR szStyles[32];
SendDlgItemMessage(hwnd, DID_NEWCUSTCLASS, EM_LIMITTEXT, CCHCCCLASS - 1, 0L);
SendDlgItemMessage(hwnd, DID_NEWCUSTSTYLES, EM_LIMITTEXT, CCHHEXLONGMAX, 0L);
wsprintf(szStyles, L"%#.8lx", awcd[W_CUSTOM].flStyles);
SetDlgItemText(hwnd, DID_NEWCUSTSTYLES, szStyles);
SendDlgItemMessage(hwnd, DID_NEWCUSTCX, EM_LIMITTEXT, 3, 0L);
SetDlgItemInt(hwnd, DID_NEWCUSTCX, awcd[W_CUSTOM].cxDefault, FALSE);
SendDlgItemMessage(hwnd, DID_NEWCUSTCY, EM_LIMITTEXT, 3, 0L);
SetDlgItemInt(hwnd, DID_NEWCUSTCY, awcd[W_CUSTOM].cyDefault, FALSE);
SendDlgItemMessage(hwnd, DID_NEWCUSTTEXT, EM_LIMITTEXT, CCHCCTEXT - 1, 0L);
CenterWindow(hwnd);
}
/************************************************************************
* NewCustOK
*
* Processes the OK button from the New Temporary Custom Control dialog.
*
* History:
*
************************************************************************/
STATICFN BOOL NewCustOK(
HWND hwnd)
{
TCHAR szStyles[CCHHEXLONGMAX + 1];
CCINFO cci;
/*
* Read the class field. It is required.
*/
if (!GetDlgItemText(hwnd, DID_NEWCUSTCLASS, cci.szClass, CCHCCCLASS)) {
Message(MSG_NOCLASS);
SetFocus(GetDlgItem(hwnd, DID_NEWCUSTCLASS));
return FALSE;
}
GetDlgItemText(hwnd, DID_NEWCUSTSTYLES, szStyles, CCHHEXLONGMAX + 1);
cci.flStyleDefault = valtoi(szStyles);
if (!(cci.cxDefault = GetDlgItemInt(hwnd, DID_NEWCUSTCX, NULL, FALSE))) {
Message(MSG_GTZERO, ids(IDS_WIDTH));
SetFocus(GetDlgItem(hwnd, DID_NEWCUSTCX));
return FALSE;
}
if (!(cci.cyDefault = GetDlgItemInt(hwnd, DID_NEWCUSTCY, NULL, FALSE))) {
Message(MSG_GTZERO, ids(IDS_HEIGHT));
SetFocus(GetDlgItem(hwnd, DID_NEWCUSTCY));
return FALSE;
}
GetDlgItemText(hwnd, DID_NEWCUSTTEXT, cci.szTextDefault, CCHCCTEXT);
cci.flOptions = 0;
*cci.szDesc = TEXT('\0');
cci.flExtStyleDefault = 0;
cci.flCtrlTypeMask = 0;
cci.cStyleFlags = 0;
cci.aStyleFlags = NULL;
cci.lpfnStyle = NULL;
cci.lpfnSizeToText = NULL;
cci.dwReserved1 = 0;
cci.dwReserved2 = 0;
if (AddCustomLink(&cci, TRUE, FALSE, NULL, NULL))
return TRUE;
else
return FALSE;
}
/************************************************************************
* OpenCustomDialog
*
* Displays the file open dialog and allows a custom DLL to be selected
* and loaded.
*
* History:
*
************************************************************************/
VOID OpenCustomDialog(VOID)
{
BOOL fGotName;
OPENFILENAME ofn;
TCHAR szNewFileName[CCHMAXPATH];
TCHAR szFilter[CCHTEXTMAX];
INT idPrevDlg;
/*
* Begin setting up the globals and the open file dialog structure.
*/
*szNewFileName = CHAR_NULL;
/*
* Build up the filter string.
*/
BuildFilterString(FILE_DLL, szFilter);
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = ghwndMain;
ofn.hInstance = NULL;
ofn.lpstrFilter = szFilter;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szNewFileName;
ofn.nMaxFile = CCHMAXPATH;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrTitle = ids(IDS_DLLOPENTITLE);
ofn.Flags = OFN_HIDEREADONLY | OFN_SHOWHELP | OFN_FILEMUSTEXIST;
ofn.lpstrDefExt = ids(IDS_DLLEXT);
ofn.lpstrInitialDir = NULL;
ofn.lCustData = 0;
ofn.lpfnHook = NULL;
ofn.lpTemplateName = NULL;
/*
* Fire off the dialog box to open the file.
*/
EnteringDialog(DID_COMMONFILEOPENDLL, &idPrevDlg, TRUE);
fGotName = GetOpenFileName(&ofn);
EnteringDialog(idPrevDlg, NULL, FALSE);
if (fGotName)
OpenDLLFile(szNewFileName);
}
/************************************************************************
* OpenDLLFile
*
*
* History:
*
************************************************************************/
STATICFN VOID OpenDLLFile(
LPTSTR pszFileName)
{
HANDLE hmod;
LPFNCCINFOA lpfnInfoA;
LPFNCCINFOW lpfnInfoW;
INT i;
BOOL fSuccess = FALSE;
BOOL fUnicodeDLL;
PCUSTLINK pclT;
INT nControls;
INT nControls2;
LPCCINFO acci;
/*
* Check to see if the DLL has already been loaded.
*/
for (pclT = gpclHead; pclT &&
(pclT->pwcd->fEmulated ||
lstrcmpi(pclT->pszFileName, pszFileName) != 0);
pclT = pclT->pclNext)
;
/*
* Is the DLL already loaded?
*/
if (pclT) {
Message(MSG_CUSTALREADYLOADED, pszFileName);
return;
}
if (!(hmod = LoadLibrary(pszFileName))) {
Message(MSG_CANTLOADDLL, pszFileName);
return;
}
lpfnInfoA = (LPFNCCINFOA)GetProcAddress(hmod, "CustomControlInfoA");
lpfnInfoW = (LPFNCCINFOW)GetProcAddress(hmod, "CustomControlInfoW");
if (!lpfnInfoA && !lpfnInfoW) {
Message(MSG_BADCUSTDLL, pszFileName);
goto Error1;
}
if (lpfnInfoW) {
nControls = (*lpfnInfoW)(NULL);
fUnicodeDLL = TRUE;
}
else {
nControls = (*lpfnInfoA)(NULL);
fUnicodeDLL = FALSE;
}
if (!nControls) {
Message(MSG_CANTINITDLL, pszFileName);
goto Error1;
}
if (!(acci = (LPCCINFO)MyAlloc(nControls * sizeof(CCINFO))))
goto Error1;
if (fUnicodeDLL)
nControls2 = (*lpfnInfoW)(acci);
else
nControls2 = CallCustomInfoA(lpfnInfoA, acci, nControls);
if (!nControls2) {
Message(MSG_CANTINITDLL, pszFileName);
goto Error2;
}
for (i = 0; i < nControls; i++) {
if (!AddCustomLink(&acci[i], FALSE, fUnicodeDLL, pszFileName, hmod))
goto Error2;
}
fSuccess = TRUE;
Error2:
MyFree(acci);
Error1:
if (!fSuccess)
FreeLibrary(hmod);
}
/************************************************************************
* CallCustomInfoA
*
* Thunks the call from the unicode DlgEdit to the ANSI custom control
* info procedure.
*
* History:
*
************************************************************************/
STATICFN UINT CallCustomInfoA(
LPFNCCINFOA lpfnInfoA,
LPCCINFO acciW,
INT nControls)
{
LPCCINFOA acciA;
INT nControls2;
INT i;
INT j;
LPCCSTYLEFLAGA lpFlagsA;
LPCCSTYLEFLAGW aFlagsW = NULL;
INT cch;
/*
* Allocate the appropriate number of ANSI info structures.
*/
if (!(acciA = (LPCCINFOA)MyAlloc(nControls * sizeof(CCINFOA))))
return 0;
/*
* Call the ANSI info function.
*/
if (nControls2 = (*lpfnInfoA)(acciA)) {
/*
* Copy all the ANSI structures to the UNICODE structures,
* converting strings to UNICODE as we go.
*/
for (i = 0; i < nControls; i++) {
MultiByteToWideChar(CP_ACP, 0, acciA[i].szClass, -1,
acciW[i].szClass, CCHCCCLASS);
acciW[i].flOptions = acciA[i].flOptions;
MultiByteToWideChar(CP_ACP, 0, acciA[i].szDesc, -1,
acciW[i].szDesc, CCHCCDESC);
acciW[i].cxDefault = acciA[i].cxDefault;
acciW[i].cyDefault = acciA[i].cyDefault;
acciW[i].flStyleDefault = acciA[i].flStyleDefault;
acciW[i].flExtStyleDefault = acciA[i].flExtStyleDefault;
acciW[i].flCtrlTypeMask = acciA[i].flCtrlTypeMask;
MultiByteToWideChar(CP_ACP, 0, acciA[i].szTextDefault, -1,
acciW[i].szTextDefault, CCHCCTEXT);
/*
* Is there a table of style flags? If so, we need to build
* up a table of unicode style flags. Note that since we
* allocate this table, the table must be freed when the
* custom link is destroyed!
*/
if (acciA[i].cStyleFlags) {
/*
* If they specified that there are style flags, the pointer
* to the table must not be NULL.
*/
if (!acciA[i].aStyleFlags)
return 0;
if (!(aFlagsW = (LPCCSTYLEFLAGW)MyAlloc(
acciA[i].cStyleFlags * sizeof(CCSTYLEFLAGW))))
return 0;
/*
* Copy all the flags to the new unicode style flag table.
*/
for (j = 0, lpFlagsA = acciA[i].aStyleFlags;
j < acciA[i].cStyleFlags; j++, lpFlagsA++) {
aFlagsW[j].flStyle = lpFlagsA->flStyle;
aFlagsW[j].flStyleMask = lpFlagsA->flStyleMask;
cch = lstrlenA(lpFlagsA->pszStyle) + 1;
aFlagsW[j].pszStyle = (LPWSTR)MyAlloc(cch * sizeof(WCHAR));
if (!aFlagsW[j].pszStyle)
return 0;
MultiByteToWideChar(CP_ACP, 0, lpFlagsA->pszStyle, -1,
aFlagsW[j].pszStyle, cch);
}
}
acciW[i].cStyleFlags = acciA[i].cStyleFlags;
acciW[i].aStyleFlags = aFlagsW;
acciW[i].lpfnStyle = (LPFNCCSTYLE)acciA[i].lpfnStyle;
acciW[i].lpfnSizeToText = (LPFNCCSIZETOTEXT)acciA[i].lpfnSizeToText;
acciW[i].dwReserved1 = acciA[i].dwReserved1;
acciW[i].dwReserved2 = acciA[i].dwReserved2;
}
}
MyFree(acciA);
return nControls2;
}
/************************************************************************
* SelCustDialog
*
* Displays the Select Custom Control dialog to choose which custom
* control tool should be selected.
*
* History:
*
************************************************************************/
PWINDOWCLASSDESC SelCustDialog(VOID)
{
if (DlgBox(DID_SELCUST, (WNDPROC)SelCustDlgProc) == IDOK)
return pwcdChosen;
else
return NULL;
}
/************************************************************************
* SelCustDlgProc
*
* This is the Select Custom Control dialog procedure.
*
* History:
*
************************************************************************/
DIALOGPROC SelCustDlgProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
SelCustInit(hwnd);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case DID_SELCUSTLIST:
switch (HIWORD(wParam)) {
case LBN_DBLCLK:
if (SelCustOK(hwnd))
EndDialog(hwnd, IDOK);
break;
case LBN_SELCHANGE:
SelCustSelect(hwnd);
break;
}
break;
case IDOK:
if (SelCustOK(hwnd))
EndDialog(hwnd, IDOK);
break;
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
case IDHELPDLG:
WinHelp(ghwndMain, gszHelpFile, HELP_CONTEXT,
HELPID_SELCUST);
break;
}
return TRUE;
default:
return FALSE;
}
}
/************************************************************************
* SelCustInit
*
* Processes the WM_INITDIALOG message for the Select Custom Control
* dialog procedure.
*
* History:
*
************************************************************************/
STATICFN VOID SelCustInit(
HWND hwnd)
{
HWND hwndLB;
INT i;
PCUSTLINK pcl;
LPTSTR pszDesc;
hwndLB = GetDlgItem(hwnd, DID_SELCUSTLIST);
/*
* Insert each custom control into the listbox.
*/
for (pcl = gpclHead; pcl; pcl = pcl->pclNext) {
/*
* Use the short description, if the control has one,
* otherwise use the class name itself.
*/
if (pcl->pszDesc)
pszDesc = pcl->pszDesc;
else
pszDesc = pcl->pwcd->pszClass;
i = (INT)SendMessage(hwndLB, LB_ADDSTRING, 0, (DWORD)pszDesc);
SendMessage(hwndLB, LB_SETITEMDATA, i, (DWORD)pcl);
}
hwndCustomSample = NULL;
/*
* Select the first item.
*/
SendMessage(hwndLB, LB_SETCURSEL, 0, 0L);
SelCustSelect(hwnd);
CenterWindow(hwnd);
}
/************************************************************************
* SelCustSelect
*
* Called every time that a different control is selected in the list box
* in the Select Custom Control dialog. It will create a sample control
* and show it in the Sample box.
*
* History:
*
************************************************************************/
STATICFN VOID SelCustSelect(
HWND hwnd)
{
HWND hwndLB;
INT iSelect;
PCUSTLINK pcl;
PWINDOWCLASSDESC pwcd;
LPTSTR pszClass;
RECT rc;
RECT rcParent;
HWND hwndParent;
INT x;
INT y;
INT cx;
INT cy;
INT cxParent;
INT cyParent;
hwndLB = GetDlgItem(hwnd, DID_SELCUSTLIST);
if ((iSelect = (INT)SendMessage(hwndLB, LB_GETCURSEL, 0, 0)) == LB_ERR)
return;
/*
* Get a pointer to the custom control link (stored in the listbox
* items data field).
*/
pcl = (PCUSTLINK)SendMessage(hwndLB, LB_GETITEMDATA, iSelect, 0L);
pwcd = pcl->pwcd;
/*
* Get the coordinates of the Sample box.
*/
hwndParent = GetDlgItem(hwnd, DID_SELCUSTSAMPLE);
GetWindowRect(hwndParent, &rcParent);
ScreenToClientRect(hwnd, &rcParent);
cxParent = (rcParent.right - rcParent.left) - (2 * SAMPLEMARGIN);
cyParent = (rcParent.bottom - rcParent.top) - (2 * SAMPLEMARGIN);
/*
* Calculate the window size of the sample control.
*/
SetRect(&rc, 0, 0, pwcd->cxDefault, pwcd->cyDefault);
DUToWinRect(&rc);
cx = rc.right - rc.left;
cy = rc.bottom - rc.top;
/*
* Be sure that the control can fit within the sample box. Adjust
* it down if necessary.
*/
if (cx < cxParent) {
x = ((cxParent - cx) / 2) + SAMPLEMARGIN;
}
else {
x = SAMPLEMARGIN;
cx = cxParent;
}
if (cy < cyParent) {
y = ((cyParent - cy) / 2) + SAMPLEMARGIN;
}
else {
y = SAMPLEMARGIN;
cy = cyParent;
}
x += rcParent.left;
y += rcParent.top;
/*
* Destroy the old sample.
*/
if (hwndCustomSample)
DestroyWindow(hwndCustomSample);
/*
* Get the class name to use.
* If the control is emulated, use the special emulator class.
* Otherwise, it is an installed custom control, and we can use
* it's real class string.
*/
if (pwcd->fEmulated)
pszClass = szCustomClass;
else
pszClass = pwcd->pszClass;
/*
* Create the sample control. We always create it visible here,
* even if the style says it isn't.
*/
hwndCustomSample = CreateWindow(
pszClass,
pwcd->pszTextDefault,
pwcd->flStyles | WS_VISIBLE,
x, y, cx, cy,
hwnd,
0,
ghInst,
NULL);
}
/************************************************************************
* SelCustOK
*
* Processes the final selection of a custom control from the
* Select Custom Control dialog.
*
* History:
*
************************************************************************/
STATICFN BOOL SelCustOK(
HWND hwnd)
{
HWND hwndLB;
INT iSelect;
PCUSTLINK pcl;
hwndLB = GetDlgItem(hwnd, DID_SELCUSTLIST);
if ((iSelect = (INT)SendMessage(hwndLB, LB_GETCURSEL, 0, 0)) == LB_ERR)
return FALSE;
/*
* Get a pointer to the custom control link (stored in the listbox
* items data field).
*/
pcl = (PCUSTLINK)SendMessage(hwndLB, LB_GETITEMDATA, iSelect, 0L);
pwcdChosen = pcl->pwcd;
return TRUE;
}
/************************************************************************
* RemCustDlgProc
*
* This is the Remove Custom Control dialog procedure.
* It is used to de-install a custom control.
*
* History:
*
************************************************************************/
DIALOGPROC RemCustDlgProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
RemCustInit(hwnd);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case DID_REMCUSTLIST:
if (HIWORD(wParam) == LBN_DBLCLK) {
if (RemCustOK(hwnd))
EndDialog(hwnd, IDOK);
}
break;
case IDOK:
if (RemCustOK(hwnd))
EndDialog(hwnd, IDOK);
break;
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
case IDHELPDLG:
WinHelp(ghwndMain, gszHelpFile, HELP_CONTEXT,
HELPID_REMCUST);
break;
}
return TRUE;
default:
return FALSE;
}
}
/************************************************************************
* RemCustInit
*
* Processes the WM_INITDIALOG message for the Remove Custom Control
* dialog procedure.
*
* History:
*
************************************************************************/
STATICFN VOID RemCustInit(
HWND hwnd)
{
HWND hwndLB;
INT i;
PCUSTLINK pcl;
LPTSTR pszDesc;
hwndLB = GetDlgItem(hwnd, DID_REMCUSTLIST);
/*
* Insert each custom control into the listbox.
*/
for (pcl = gpclHead; pcl; pcl = pcl->pclNext) {
/*
* Use the short description, if the control has one,
* otherwise use the class name itself.
*/
if (pcl->pszDesc)
pszDesc = pcl->pszDesc;
else
pszDesc = pcl->pwcd->pszClass;
i = (INT)SendMessage(hwndLB, LB_ADDSTRING, 0, (DWORD)pszDesc);
SendMessage(hwndLB, LB_SETITEMDATA, i, (DWORD)pcl);
}
/*
* Select the first item.
*/
SendMessage(hwndLB, LB_SETCURSEL, 0, 0L);
CenterWindow(hwnd);
}
/************************************************************************
* RemCustOK
*
* Processes the selection of a custom control to delete from the
* Remove Custom Control dialog.
*
* History:
*
************************************************************************/
STATICFN BOOL RemCustOK(
HWND hwnd)
{
HWND hwndLB;
INT iSelect;
PCUSTLINK pcl;
NPCTYPE npc;
hwndLB = GetDlgItem(hwnd, DID_REMCUSTLIST);
if ((iSelect = (INT)SendMessage(hwndLB, LB_GETCURSEL, 0, 0)) != LB_ERR) {
/*
* Get a pointer to the custom control link (stored in the listbox
* items data field).
*/
pcl = (PCUSTLINK)SendMessage(hwndLB, LB_GETITEMDATA, iSelect, 0L);
/*
* Cannot delete if any controls in the current dialog
* are of this type.
*/
for (npc = npcHead; npc; npc = npc->npcNext) {
if (pcl->pwcd == npc->pwcd) {
Message(MSG_CUSTCNTLINUSE);
return FALSE;
}
}
RemoveCustomLink(pcl);
}
return TRUE;
}
/****************************************************************************
* CustomWndProc
*
* This is the window procedure for the emulated Custom control.
*
* History:
*
****************************************************************************/
WINDOWPROC CustomWndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
switch (msg) {
case WM_PAINT:
{
HDC hDC;
PAINTSTRUCT ps;
RECT rc;
TCHAR szText[CCHTEXTMAX];
hDC = BeginPaint(hwnd, &ps);
SelectObject(hDC, GetStockObject(LTGRAY_BRUSH));
GetClientRect(hwnd, &rc);
Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
GetWindowText(hwnd, szText, CCHTEXTMAX);
#ifdef JAPAN
{
TCHAR szTmp[CCHTEXTMAX];
KDExpandCopy(szTmp, szText, CCHTEXTMAX);
lstrcpy(szText, szTmp);
}
#endif
SetBkMode(hDC, TRANSPARENT);
if (gcd.hFont)
SelectObject(hDC, gcd.hFont);
DrawText(hDC, szText, -1, &rc,
DT_CENTER | DT_NOCLIP | DT_VCENTER | DT_SINGLELINE);
EndPaint(hwnd, &ps);
}
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
/************************************************************************
* AddCustomLink
*
* Adds a new custom control to the linked list.
*
* Note that normally duplicates are checked for, but it allows multiple
* links to be added with the same class if it is a DLL control. This
* is to support multiple control types being added from the same DLL.
* Because of this, if the caller is adding a non-emulated link, they
* are responsible for checking the list for duplicates first!
*
* There is one special case. If it is adding a DLL link, and an
* emulated link with the same class name is found, it will walk the
* current list of controls and replace all of them with the new DLL
* control type, then delete the emulated link. This is to support
* the case where the user creates some controls of class FOO, where
* FOO is emulated, then later loads the FOO DLL. All controls of
* this emulated class will be changed to be the real FOO class, and
* the DLL FOO link replaces the emulated one.
*
* History:
*
************************************************************************/
PCUSTLINK AddCustomLink(
LPCCINFO pcci,
BOOL fEmulated,
BOOL fUnicodeDLL,
LPTSTR pszFileName,
HANDLE hmod)
{
PCUSTLINK pcl;
PCUSTLINK pclT;
PCUSTLINK pclPrev;
NPCTYPE npc;
HWND hwndOld;
if (!(pcl = AllocCUSTLINK(pcci, fEmulated, fUnicodeDLL, pszFileName, hmod)))
return NULL;
if (fEmulated) {
/*
* Search the list for another link with the same class.
*/
for (pclT = gpclHead;
pclT && lstrcmpi(pclT->pwcd->pszClass, pcci->szClass) != 0;
pclT = pclT->pclNext)
;
/*
* Was a duplicate found?
*/
if (pclT) {
FreeCUSTLINK(pcl);
Message(MSG_CUSTALREADYLOADED, pcci->szClass);
return NULL;
}
}
else {
/*
* Search the list for another link with the same class that
* is an emulated control.
*/
for (pclT = gpclHead;
pclT &&
(lstrcmpi(pclT->pwcd->pszClass, pcci->szClass) != 0 ||
!pclT->pwcd->fEmulated);
pclT = pclT->pclNext)
;
/*
* Was a duplicate found?
*/
if (pclT) {
/*
* At this point we know that this is a DLL link replacing
* an existing emulated control class. We want to go through
* the existing controls and replace any of this class with
* the new DLL class. This allows a user to load a dialog
* with some emulated controls, then later install the custom
* DLL and have all the existing controls of that class
* change to show the real control.
*/
for (npc = npcHead; npc; npc = npc->npcNext) {
/*
* Is the control of the type that we are replacing?
*/
if (npc->pwcd == pclT->pwcd) {
hwndOld = npc->hwnd;
/*
* Unsubclass the old control window, then switch
* the pwcd pointer before calling CreateControl.
*/
SetWindowLong(hwndOld, GWL_WNDPROC,
(DWORD)npc->pwcd->pfnOldWndProc);
UNSETPCINTOHWND(hwndOld);
npc->pwcd = pcl->pwcd;
/*
* Create a control of the new type in the same position.
*/
if (CreateControl(npc, npc->text, npc->flStyle,
npc->flExtStyle, npc->id, &npc->rc,
hwndOld, NULL)) {
/*
* Get rid of the old control window.
*/
DestroyWindow(hwndOld);
/*
* Adjust the size and position of its drag window.
*/
SizeDragToControl(npc);
}
}
}
/*
* Remove the old link, now that all the controls that
* used it are gone.
*/
RemoveCustomLink(pclT);
}
}
/*
* Search for the end of the list. Get a pointer to the last link.
*/
for (pclT = gpclHead, pclPrev = NULL; pclT;
pclPrev = pclT, pclT = pclT->pclNext)
;
/*
* Add the new link to the list. Add it to the end if there are
* other links, or initialize the head pointer if this is the
* first one.
*/
if (pclPrev)
pclPrev->pclNext = pcl;
else
gpclHead = pcl;
return pcl;
}
/************************************************************************
* AllocCUSTLINK
*
* Allocates a CUSTLINK structure and initializes it. This includes
* allocating an associated WINDOWCLASSDESC structure.
*
* History:
*
************************************************************************/
STATICFN PCUSTLINK AllocCUSTLINK(
LPCCINFO pcci,
BOOL fEmulated,
BOOL fUnicodeDLL,
LPTSTR pszFileName,
HANDLE hmod)
{
PCUSTLINK pcl;
PWINDOWCLASSDESC pwcd;
if (!(pwcd = (PWINDOWCLASSDESC)MyAlloc(sizeof(WINDOWCLASSDESC))))
return NULL;
/*
* Initialize the structure to be like an emulated custom control.
*/
*pwcd = awcd[W_CUSTOM];
/*
* Now override some values.
*/
pwcd->flStyles = pcci->flStyleDefault;
pwcd->flExtStyle = pcci->flExtStyleDefault;
pwcd->cxDefault = pcci->cxDefault;
pwcd->cyDefault = pcci->cyDefault;
pwcd->fEmulated = fEmulated;
pwcd->fUnicodeDLL = fUnicodeDLL;
pwcd->hmod = hmod;
pwcd->cStyleFlags = pcci->cStyleFlags;
pwcd->aStyleFlags = pcci->aStyleFlags;
pwcd->lpfnStyle = (PROC)pcci->lpfnStyle;
pwcd->lpfnSizeToText = (PROC)pcci->lpfnSizeToText;
pwcd->flCtrlTypeMask = pcci->flCtrlTypeMask;
if (pcci->flOptions & CCF_NOTEXT)
pwcd->fHasText = FALSE;
else
pwcd->fHasText = TRUE;
if (pcci->lpfnSizeToText && pwcd->fHasText)
pwcd->fSizeToText = TRUE;
/*
* Copy the class name.
*/
if (!(pwcd->pszClass = NameOrdDup(pcci->szClass)))
goto error1;
/*
* Copy the default text. This is an optional field.
*/
if (*pcci->szTextDefault) {
if (!(pwcd->pszTextDefault = NameOrdDup(pcci->szTextDefault)))
goto error2;
}
else {
pwcd->pszTextDefault = NULL;
}
if (!(pcl = (PCUSTLINK)MyAlloc(sizeof(CUSTLINK))))
goto error3;
/*
* Copy the DLL file name (NULL for emulated controls).
*/
if (pszFileName && *pszFileName) {
if (!(pcl->pszFileName = NameOrdDup(pszFileName)))
goto error4;
}
else {
pcl->pszFileName = NULL;
}
/*
* Copy the descriptive text. This is an optional field.
*/
if (*pcci->szDesc) {
if (!(pcl->pszDesc = NameOrdDup(pcci->szDesc)))
goto error5;
}
else {
pcl->pszDesc = NULL;
}
pcl->pclNext = NULL;
pcl->pwcd = pwcd;
return pcl;
error5:
if (pcl->pszFileName)
MyFree(pcl->pszFileName);
error4:
MyFree(pcl);
error3:
if (pwcd->pszTextDefault)
MyFree(pwcd->pszTextDefault);
error2:
MyFree(pwcd->pszClass);
error1:
MyFree(pwcd);
return NULL;
}
/************************************************************************
* RemoveCustomLink
*
* Removes and frees a custom control link from the list.
*
* History:
*
************************************************************************/
VOID RemoveCustomLink(
PCUSTLINK pclFree)
{
PCUSTLINK pcl;
PCUSTLINK pclPrev;
/*
* Search for the link in the list.
*/
for (pcl = gpclHead, pclPrev = NULL; pcl != pclFree;
pclPrev = pcl, pcl = pcl->pclNext)
;
/*
* Link was not found.
*/
if (!pcl)
return;
/*
* Remove the link from the list.
*/
if (pclPrev)
pclPrev->pclNext = pclFree->pclNext;
else
gpclHead = pclFree->pclNext;
/*
* Finally, free the link completely.
*/
FreeCUSTLINK(pclFree);
}
/************************************************************************
* FreeCUSTLINK
*
* Frees a CUSTLINK structure. This includes freeing the
* associated WINDOWCLASSDESC structure.
*
* History:
*
************************************************************************/
STATICFN VOID FreeCUSTLINK(
PCUSTLINK pclFree)
{
PCUSTLINK pcl;
INT i;
/*
* Do we need to unload the associated DLL?
*/
if (pclFree->pwcd->hmod) {
/*
* Run throught the custom list looking to see if any other
* installed custom control has the same module handle as the
* one that we are freeing.
*/
for (pcl = gpclHead;
pcl &&
(pcl == pclFree || pcl->pwcd->hmod != pclFree->pwcd->hmod);
pcl = pcl->pclNext)
;
/*
* If none were found, it is safe to unload this library.
* Otherwise, we must leave the library loaded for the
* others!
*/
if (!pcl)
FreeLibrary(pclFree->pwcd->hmod);
}
MyFree(pclFree->pwcd->pszClass);
if (pclFree->pwcd->pszTextDefault)
MyFree(pclFree->pwcd->pszTextDefault);
/*
* Is this a non-unicode DLL? If so, then when it was loaded,
* the dialog editor allocated a table of unicode style strings.
* This table must now be freed. If the DLL was a unicode one,
* then the table pointed to by aStyleFlags belongs to the DLL,
* and it must NOT be freed.
*/
if (pclFree->pwcd->hmod && !pclFree->pwcd->fUnicodeDLL) {
for (i = 0; i < pclFree->pwcd->cStyleFlags; i++)
MyFree(pclFree->pwcd->aStyleFlags[i].pszStyle);
if (pclFree->pwcd->aStyleFlags)
MyFree(pclFree->pwcd->aStyleFlags);
}
MyFree(pclFree->pwcd);
if (pclFree->pszFileName)
MyFree(pclFree->pszFileName);
if (pclFree->pszDesc)
MyFree(pclFree->pszDesc);
MyFree(pclFree);
}
/************************************************************************
* CallCustomStyle
*
*
* History:
*
************************************************************************/
BOOL CallCustomStyle(
NPCTYPE npc,
PDWORD pflStyleNew,
PDWORD pflExtStyleNew,
LPTSTR pszTextNew)
{
CCSTYLE ccs;
CCSTYLEA ccsA;
BOOL fSuccess;
BOOL fDefCharUsed;
INT idPrevDlg;
/*
* Because we are about ready to display the dialog, we need to
* call EnteringDialog so that the properties bar, toolbox and
* work mode dialog get disabled. The first parameter is the
* dialog id, used so that the proper help will be brought up
* for this dialog. Since we don't have a meaningful help screen
* for any old random custom control, just pass in a value of
* zero, which will cause the Help Contents screen to be
* brought up if the user presses F1 while the dialog is up.
*/
EnteringDialog(0, &idPrevDlg, TRUE);
/*
* Is this a UNICODE DLL?
*/
if (npc->pwcd->fUnicodeDLL) {
ccs.flStyle = *pflStyleNew;
ccs.flExtStyle = *pflExtStyleNew;
lstrcpy(ccs.szText, pszTextNew);
ccs.lgid = gcd.di.wLanguage;
ccs.wReserved1 = 0;
fSuccess = ((LPFNCCSTYLE)(*npc->pwcd->lpfnStyle))(ghwndMain, &ccs);
if (fSuccess) {
*pflStyleNew = ccs.flStyle;
*pflExtStyleNew = ccs.flExtStyle;
lstrcpy(pszTextNew, ccs.szText);
}
}
else {
ccsA.flStyle = *pflStyleNew;
ccsA.flExtStyle = *pflExtStyleNew;
WideCharToMultiByte(CP_ACP, 0, pszTextNew, -1, ccsA.szText, CCHCCTEXT,
NULL, &fDefCharUsed);
ccsA.lgid = gcd.di.wLanguage;
ccsA.wReserved1 = 0;
fSuccess = ((LPFNCCSTYLEA)(*npc->pwcd->lpfnStyle))(ghwndMain, &ccsA);
if (fSuccess) {
*pflStyleNew = ccsA.flStyle;
*pflExtStyleNew = ccsA.flExtStyle;
MultiByteToWideChar(CP_ACP, 0, ccsA.szText, -1, pszTextNew,
CCHTEXTMAX);
}
}
EnteringDialog(idPrevDlg, NULL, FALSE);
return fSuccess;
}
/************************************************************************
* CallCustomSizeToText
*
*
*
* Returns:
*
* History:
*
************************************************************************/
INT CallCustomSizeToText(
NPCTYPE npc)
{
INT x;
INT xDU;
BOOL fDefCharUsed;
CHAR szTextA[CCHTEXTMAX];
PSTR pszTextA;
/*
* Does this custom control have a SizeToText function?
*/
if (!npc->pwcd->lpfnSizeToText)
return -1;
/*
* Is this a UNICODE DLL that we are calling to?
*/
if (npc->pwcd->fUnicodeDLL) {
x = ((LPFNCCSIZETOTEXT)(*npc->pwcd->lpfnSizeToText))
(npc->flStyle, npc->flExtStyle, gcd.hFont, npc->text);
}
else {
/*
* No, not a UNICODE DLL. We must convert from UNICODE to
* ANSI first. NULL text cases must be handled properly.
*/
if (npc->text) {
WideCharToMultiByte(CP_ACP, 0, npc->text, -1, szTextA, CCHTEXTMAX,
NULL, &fDefCharUsed);
pszTextA = szTextA;
}
else {
pszTextA = NULL;
}
x = ((LPFNCCSIZETOTEXTA)(*npc->pwcd->lpfnSizeToText))
(npc->flStyle, npc->flExtStyle, gcd.hFont, pszTextA);
}
/*
* Did the call to the DLL fail?
*/
if (x == -1)
return -1;
/*
* Convert the size in pixels to a size in Dialog Units. Be sure
* that we round any fraction up to the next higher DU. Since
* we know how wide the control must be to fit the text, we must
* be sure that the size does not get rounded down below this
* value when converting to DU's.
*/
xDU = MulDiv(x, 4, gcd.cxChar);
if (MulDiv(xDU, gcd.cxChar, 4) != x)
xDU++;
return xDU;
}
/************************************************************************
* ReadCustomProfile
*
*
* History:
*
************************************************************************/
VOID ReadCustomProfile(VOID)
{
TCHAR szBuf[CCHTEXTMAX];
TCHAR szBuf2[CCHTEXTMAX];
LPTSTR pszKey;
GetPrivateProfileString(szCustomDLL, NULL, szEmpty,
szBuf, CCHTEXTMAX, ids(IDS_DLGEDITINI));
/*
* Get the file name for each custom control DLL and load it.
*/
for (pszKey = szBuf; *pszKey; pszKey += lstrlen(pszKey) + 1) {
if (GetPrivateProfileString(szCustomDLL, pszKey, szEmpty,
szBuf2, CCHTEXTMAX, ids(IDS_DLGEDITINI)))
OpenDLLFile(szBuf2);
}
}
/************************************************************************
* WriteCustomProfile
*
*
* History:
*
************************************************************************/
VOID WriteCustomProfile(VOID)
{
PCUSTLINK pcl;
PCUSTLINK pcl2;
BOOL fSecond;
/*
* Clear out the section.
*/
WritePrivateProfileString(szCustomDLL, NULL, NULL, ids(IDS_DLGEDITINI));
for (pcl = gpclHead; pcl; pcl = pcl->pclNext) {
/*
* Only write out installed DLL's, not emulated controls.
*/
if (pcl->pszFileName) {
/*
* Before writing out the path to the DLL, be sure
* that this DLL's path has not been written out
* already. This would only occur if they have
* multiple control types within the DLL.
*/
for (pcl2 = gpclHead, fSecond = FALSE;
pcl2 && pcl2 != pcl; pcl2 = pcl2->pclNext) {
if (lstrcmpi(pcl2->pszFileName, pcl->pszFileName) == 0) {
fSecond = TRUE;
break;
}
}
if (!fSecond)
WritePrivateProfileString(szCustomDLL, pcl->pwcd->pszClass,
pcl->pszFileName, ids(IDS_DLGEDITINI));
}
}
}