windows-nt/Source/XPSP1/NT/net/homenet/config/dll/sautil.cpp
2020-09-26 16:20:57 +08:00

1658 lines
44 KiB
C++

//#include "pch.h"
#pragma hdrstop
#include "sautil.h"
BOOL g_fNoWinHelp = FALSE;
VOID ContextHelp(
IN const DWORD* padwMap,
IN HWND hwndDlg,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam)
// Calls WinHelp to popup context sensitive help. 'PadwMap' is an array
// of control-ID help-ID pairs terminated with a 0,0 pair. 'UnMsg' is
// WM_HELP or WM_CONTEXTMENU indicating the message received requesting
// help. 'Wparam' and 'lparam' are the parameters of the message received
// requesting help.
//
{
HWND hwnd;
UINT unType;
TCHAR* pszHelpFile;
ASSERT( unMsg==WM_HELP || unMsg==WM_CONTEXTMENU );
// Don't try to do help if it won't work. See common\uiutil\ui.c.
//
{
extern BOOL g_fNoWinHelp;
if (g_fNoWinHelp)
{
return;
}
}
if (unMsg == WM_HELP)
{
LPHELPINFO p = (LPHELPINFO )lparam;;
TRACE3( "ContextHelp(WM_HELP,t=%d,id=%d,h=$%08x)",
p->iContextType, p->iCtrlId,p->hItemHandle );
if (p->iContextType != HELPINFO_WINDOW)
{
return;
}
hwnd = (HWND)p->hItemHandle;
ASSERT( hwnd );
unType = HELP_WM_HELP;
}
else
{
// Standard Win95 method that produces a one-item "What's This?" menu
// that user must click to get help.
//
TRACE1( "ContextHelp(WM_CONTEXTMENU,h=$%08x)", wparam );
hwnd = (HWND )wparam;
unType = HELP_CONTEXTMENU;
};
// if (fRouter)
// {
// pszHelpFile = g_pszRouterHelpFile;
// }
// else
// {
// pszHelpFile = g_pszHelpFile;
// }
pszHelpFile = PszFromId (g_hinstDll, SID_HelpFile );
TRACE1( "WinHelp(%s)", pszHelpFile );
WinHelp( hwnd, pszHelpFile, unType, (ULONG_PTR ) padwMap );
Free0 (pszHelpFile);
}
VOID
AddContextHelpButton(
IN HWND hwnd )
/* Turns on title bar context help button in 'hwnd'.
**
** Dlgedit.exe doesn't currently support adding this style at dialog
** resource edit time. When that's fixed set DS_CONTEXTHELP in the dialog
** definition and remove this routine.
*/
{
LONG lStyle;
if (g_fNoWinHelp)
return;
lStyle = GetWindowLong( hwnd, GWL_EXSTYLE );
if (lStyle)
SetWindowLong( hwnd, GWL_EXSTYLE, lStyle | WS_EX_CONTEXTHELP );
}
/* Extended arguments for the MsgDlgUtil routine. Designed so zeroed gives
** default behaviors.
*/
/*----------------------------------------------------------------------------
** Message popup
**----------------------------------------------------------------------------
*/
int
MsgDlgUtil(
IN HWND hwndOwner,
IN DWORD dwMsg,
IN OUT MSGARGS* pargs,
IN HINSTANCE hInstance,
IN DWORD dwTitle )
/* Pops up a message dialog centered on 'hwndOwner'. 'DwMsg' is the
** string resource ID of the message text. 'Pargs' is a extended
** formatting arguments or NULL if none. 'hInstance' is the
** application/module handle where string resources are located.
** 'DwTitle' is the string ID of the dialog title.
**
** Returns MessageBox-style code.
*/
{
TCHAR* pszUnformatted;
TCHAR* pszResult;
TCHAR* pszNotFound;
int nResult;
TRACE("MsgDlgUtil");
/* A placeholder for missing strings components.
*/
pszNotFound = TEXT("");
/* Build the message string.
*/
pszResult = pszNotFound;
if (pargs && pargs->pszString)
{
FormatMessage(
FORMAT_MESSAGE_FROM_STRING +
FORMAT_MESSAGE_ALLOCATE_BUFFER +
FORMAT_MESSAGE_ARGUMENT_ARRAY,
pargs->pszString, 0, 0, (LPTSTR )&pszResult, 1,
(va_list* )pargs->apszArgs );
}
else
{
pszUnformatted = PszFromId( hInstance, dwMsg );
if (pszUnformatted)
{
FormatMessage(
FORMAT_MESSAGE_FROM_STRING +
FORMAT_MESSAGE_ALLOCATE_BUFFER +
FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszUnformatted, 0, 0, (LPTSTR )&pszResult, 1,
(va_list* )((pargs) ? pargs->apszArgs : NULL) );
Free( pszUnformatted );
}
}
if (!pargs || !pargs->fStringOutput)
{
TCHAR* pszTitle;
DWORD dwFlags;
HHOOK hhook;
if (pargs && pargs->dwFlags != 0)
dwFlags = pargs->dwFlags;
else
dwFlags = MB_ICONINFORMATION + MB_OK + MB_SETFOREGROUND;
pszTitle = PszFromId( hInstance, dwTitle );
if (hwndOwner)
{
/* Install hook that will get the message box centered on the
** owner window.
*/
hhook = SetWindowsHookEx( WH_CALLWNDPROC,
CenterDlgOnOwnerCallWndProc,
hInstance, GetCurrentThreadId() );
}
else
hhook = NULL;
if (pszResult)
{
nResult = MessageBox( hwndOwner, pszResult, pszTitle, dwFlags );
}
if (hhook)
UnhookWindowsHookEx( hhook );
Free0( pszTitle );
if (pszResult != pszNotFound)
LocalFree( pszResult );
}
else
{
/* Caller wants the string without doing the popup.
*/
pargs->pszOutput = (pszResult != pszNotFound) ? pszResult : NULL;
nResult = IDOK;
}
return nResult;
}
VOID
UnclipWindow(
IN HWND hwnd )
/* Moves window 'hwnd' so any clipped parts are again visible on the
** screen. The window is moved only as far as necessary to achieve this.
*/
{
RECT rect;
INT dxScreen = GetSystemMetrics( SM_CXSCREEN );
INT dyScreen = GetSystemMetrics( SM_CYSCREEN );
GetWindowRect( hwnd, &rect );
if (rect.right > dxScreen)
rect.left = dxScreen - (rect.right - rect.left);
if (rect.left < 0)
rect.left = 0;
if (rect.bottom > dyScreen)
rect.top = dyScreen - (rect.bottom - rect.top);
if (rect.top < 0)
rect.top = 0;
SetWindowPos(
hwnd, NULL,
rect.left, rect.top, 0, 0,
SWP_NOZORDER + SWP_NOSIZE );
}
VOID
CenterWindow(
IN HWND hwnd,
IN HWND hwndRef )
/* Center window 'hwnd' on window 'hwndRef' or if 'hwndRef' is NULL on
** screen. The window position is adjusted so that no parts are clipped
** by the edge of the screen, if necessary. If 'hwndRef' has been moved
** off-screen with SetOffDesktop, the original position is used.
*/
{
RECT rectCur;
LONG dxCur;
LONG dyCur;
RECT rectRef;
LONG dxRef;
LONG dyRef;
GetWindowRect( hwnd, &rectCur );
dxCur = rectCur.right - rectCur.left;
dyCur = rectCur.bottom - rectCur.top;
if (hwndRef)
{
// if (!SetOffDesktop( hwndRef, SOD_GetOrgRect, &rectRef ))
GetWindowRect( hwndRef, &rectRef );
}
else
{
rectRef.top = rectRef.left = 0;
rectRef.right = GetSystemMetrics( SM_CXSCREEN );
rectRef.bottom = GetSystemMetrics( SM_CYSCREEN );
}
dxRef = rectRef.right - rectRef.left;
dyRef = rectRef.bottom - rectRef.top;
rectCur.left = rectRef.left + ((dxRef - dxCur) / 2);
rectCur.top = rectRef.top + ((dyRef - dyCur) / 2);
SetWindowPos(
hwnd, NULL,
rectCur.left, rectCur.top, 0, 0,
SWP_NOZORDER + SWP_NOSIZE );
UnclipWindow( hwnd );
}
LRESULT CALLBACK
CenterDlgOnOwnerCallWndProc(
int code,
WPARAM wparam,
LPARAM lparam )
/* Standard Win32 CallWndProc hook callback that looks for the next dialog
** started and centers it on it's owner window.
*/
{
/* Arrive here when any window procedure associated with our thread is
** called.
*/
if (!wparam)
{
CWPSTRUCT* p = (CWPSTRUCT* )lparam;
/* The message is from outside our process. Look for the MessageBox
** dialog initialization message and take that opportunity to center
** the dialog on it's owner's window.
*/
if (p->message == WM_INITDIALOG)
CenterWindow( p->hwnd, GetParent( p->hwnd ) );
}
return 0;
}
TCHAR*
PszFromId(
IN HINSTANCE hInstance,
IN DWORD dwStringId )
/* String resource message loader routine.
**
** Returns the address of a heap block containing the string corresponding
** to string resource 'dwStringId' or NULL if error. It is caller's
** responsibility to Free the returned string.
*/
{
HRSRC hrsrc;
TCHAR* pszBuf;
int cchBuf = 256;
int cchGot;
for (;;)
{
pszBuf = (TCHAR*)Malloc( cchBuf * sizeof(TCHAR) );
if (!pszBuf)
break;
/* LoadString wants to deal with character-counts rather than
** byte-counts...weird. Oh, and if you're thinking I could
** FindResource then SizeofResource to figure out the string size, be
** advised it doesn't work. From perusing the LoadString source, it
** appears the RT_STRING resource type requests a segment of 16
** strings not an individual string.
*/
cchGot = LoadString( hInstance, (UINT )dwStringId, pszBuf, cchBuf );
if (cchGot < cchBuf - 1)
{
TCHAR *pszTemp = pszBuf;
/* Good, got the whole string. Reduce heap block to actual size
** needed.
*/
pszBuf = (TCHAR*)Realloc( pszBuf, (cchGot + 1) * sizeof(TCHAR));
if(NULL == pszBuf)
{
Free(pszTemp);
}
break;
}
/* Uh oh, LoadStringW filled the buffer entirely which could mean the
** string was truncated. Try again with a larger buffer to be sure it
** wasn't.
*/
Free( pszBuf );
cchBuf += 256;
TRACE1("Grow string buf to %d",cchBuf);
}
return pszBuf;
}
TCHAR*
GetText(
IN HWND hwnd )
/* Returns heap block containing the text contents of the window 'hwnd' or
** NULL. It is caller's responsibility to Free the returned string.
*/
{
INT cch;
TCHAR* psz;
cch = GetWindowTextLength( hwnd );
psz = (TCHAR*)Malloc( (cch + 1) * sizeof(TCHAR) );
if (psz)
{
*psz = TEXT('\0');
GetWindowText( hwnd, psz, cch + 1 );
}
return psz;
}
BOOL
GetErrorText(
DWORD dwError,
TCHAR** ppszError )
/* Fill caller's '*ppszError' with the address of a LocalAlloc'ed heap
** block containing the error text associated with error 'dwError'. It is
** caller's responsibility to LocalFree the returned string.
**
** Returns true if successful, false otherwise.
*/
{
#define MAXRASERRORLEN 256
TCHAR szBuf[ MAXRASERRORLEN + 1 ];
DWORD dwFlags;
HANDLE hmodule;
DWORD cch;
/* Don't panic if the RAS API address is not loaded. Caller may be trying
** and get an error up during LoadRas.
*/
// if ((Rasapi32DllLoaded() || RasRpcDllLoaded())
// && g_pRasGetErrorString
// && g_pRasGetErrorString(
if (RasGetErrorString ((UINT)dwError, (LPTSTR)szBuf, MAXRASERRORLEN) == 0)
{
/* It's a RAS error.
*/
*ppszError = (TCHAR*)LocalAlloc( LPTR, (lstrlen( szBuf ) + 1) * sizeof(TCHAR) );
if (!*ppszError)
return FALSE;
lstrcpy( *ppszError, szBuf );
return TRUE;
}
/* The rest adapted from BLT's LoadSystem routine.
*/
dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER + FORMAT_MESSAGE_IGNORE_INSERTS;
if (dwError >= MIN_LANMAN_MESSAGE_ID && dwError <= MAX_LANMAN_MESSAGE_ID)
{
/* It's a net error.
*/
dwFlags += FORMAT_MESSAGE_FROM_HMODULE;
hmodule = GetModuleHandle( TEXT("NETMSG.DLL") );
}
else
{
/* It must be a system error.
*/
dwFlags += FORMAT_MESSAGE_FROM_SYSTEM;
hmodule = NULL;
}
cch = FormatMessage(
dwFlags, hmodule, dwError, 0, (LPTSTR )ppszError, 1, NULL );
return (cch > 0);
}
int
ErrorDlgUtil(
IN HWND hwndOwner,
IN DWORD dwOperation,
IN DWORD dwError,
IN OUT ERRORARGS* pargs,
IN HINSTANCE hInstance,
IN DWORD dwTitle,
IN DWORD dwFormat )
/* Pops up a modal error dialog centered on 'hwndOwner'. 'DwOperation' is
** the string resource ID of the string describing the operation underway
** when the error occurred. 'DwError' is the code of the system or RAS
** error that occurred. 'Pargs' is a extended formatting arguments or
** NULL if none. 'hInstance' is the application/module handle where
** string resources are located. 'DwTitle' is the string ID of the dialog
** title. 'DwFormat' is the string ID of the error format title.
**
** Returns MessageBox-style code.
*/
{
TCHAR* pszUnformatted;
TCHAR* pszOp;
TCHAR szErrorNum[ 50 ];
TCHAR* pszError;
TCHAR* pszResult;
TCHAR* pszNotFound;
int nResult;
TRACE("ErrorDlgUtil");
/* A placeholder for missing strings components.
*/
pszNotFound = TEXT("");
/* Build the error number string.
*/
if (dwError > 0x7FFFFFFF)
wsprintf( szErrorNum, TEXT("0x%X"), dwError );
else
wsprintf( szErrorNum, TEXT("%u"), dwError );
/* Build the error text string.
*/
if (!GetErrorText( dwError, &pszError ))
pszError = pszNotFound;
/* Build the operation string.
*/
pszUnformatted = PszFromId( hInstance, dwOperation );
pszOp = pszNotFound;
if (pszUnformatted)
{
FormatMessage(
FORMAT_MESSAGE_FROM_STRING +
FORMAT_MESSAGE_ALLOCATE_BUFFER +
FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszUnformatted, 0, 0, (LPTSTR )&pszOp, 1,
(va_list* )((pargs) ? pargs->apszOpArgs : NULL) );
Free( pszUnformatted );
}
/* Call MsgDlgUtil with the standard arguments plus any auxillary format
** arguments.
*/
pszUnformatted = PszFromId( hInstance, dwFormat );
pszResult = pszNotFound;
if (pszUnformatted)
{
MSGARGS msgargs;
ZeroMemory( &msgargs, sizeof(msgargs) );
msgargs.dwFlags = MB_ICONEXCLAMATION + MB_OK + MB_SETFOREGROUND;
msgargs.pszString = pszUnformatted;
msgargs.apszArgs[ 0 ] = pszOp;
msgargs.apszArgs[ 1 ] = szErrorNum;
msgargs.apszArgs[ 2 ] = pszError;
if (pargs)
{
msgargs.fStringOutput = pargs->fStringOutput;
CopyMemory( &msgargs.apszArgs[ 3 ], pargs->apszAuxFmtArgs,
3 * sizeof(TCHAR) );
}
nResult =
MsgDlgUtil(
hwndOwner, 0, &msgargs, hInstance, dwTitle );
Free( pszUnformatted );
if (pargs && pargs->fStringOutput)
pargs->pszOutput = msgargs.pszOutput;
}
if (pszOp != pszNotFound)
LocalFree( pszOp );
if (pszError != pszNotFound)
LocalFree( pszError );
return nResult;
}
int MsgDlgUtil(IN HWND hwndOwner, IN DWORD dwMsg, IN OUT MSGARGS* pargs, IN HINSTANCE hInstance, IN DWORD dwTitle);
#define MsgDlg(h,m,a) \
MsgDlgUtil(h,m,a,g_hinstDll,SID_PopupTitle)
#define ErrorDlg(h,o,e,a) \
ErrorDlgUtil(h,o,e,a,g_hinstDll,SID_PopupTitle,SID_FMT_ErrorMsg)
// LVX stuff (cut-n-paste'd from ...\net\rras\ras\ui\common\uiutil\lvx.c, etc.
static LPCTSTR g_lvxcbContextId = NULL;
BOOL
ListView_IsCheckDisabled (
IN HWND hwndLv,
IN INT iItem)
/* Returns true if the check box of item 'iItem' of listview of checkboxes
** 'hwndLv' is disabled, false otherwise.
*/
{
UINT unState;
unState = ListView_GetItemState( hwndLv, iItem, LVIS_STATEIMAGEMASK );
if ((unState == INDEXTOSTATEIMAGEMASK( SI_DisabledChecked )) ||
(unState == INDEXTOSTATEIMAGEMASK( SI_DisabledUnchecked )))
return TRUE;
return FALSE;
}
VOID
ListView_SetCheck(
IN HWND hwndLv,
IN INT iItem,
IN BOOL fCheck )
/* Sets the check mark on item 'iItem' of listview of checkboxes 'hwndLv'
** to checked if 'fCheck' is true or unchecked if false.
*/
{
NM_LISTVIEW nmlv;
if (ListView_IsCheckDisabled(hwndLv, iItem))
return;
ListView_SetItemState( hwndLv, iItem,
INDEXTOSTATEIMAGEMASK( (fCheck) ? SI_Checked : SI_Unchecked ),
LVIS_STATEIMAGEMASK );
nmlv.hdr.code = LVXN_SETCHECK;
nmlv.hdr.hwndFrom = hwndLv;
nmlv.iItem = iItem;
FORWARD_WM_NOTIFY(
GetParent(hwndLv), GetDlgCtrlID(hwndLv), &nmlv, SendMessage
);
}
VOID*
ListView_GetParamPtr(
IN HWND hwndLv,
IN INT iItem )
/* Returns the lParam address of the 'iItem' item in 'hwndLv' or NULL if
** none or error.
*/
{
LV_ITEM item;
ZeroMemory( &item, sizeof(item) );
item.mask = LVIF_PARAM;
item.iItem = iItem;
if (!ListView_GetItem( hwndLv, &item ))
return NULL;
return (VOID* )item.lParam;
}
BOOL
ListView_GetCheck(
IN HWND hwndLv,
IN INT iItem )
/* Returns true if the check box of item 'iItem' of listview of checkboxes
** 'hwndLv' is checked, false otherwise. This function works on disabled
** check boxes as well as enabled ones.
*/
{
UINT unState;
unState = ListView_GetItemState( hwndLv, iItem, LVIS_STATEIMAGEMASK );
return !!((unState == INDEXTOSTATEIMAGEMASK( SI_Checked )) ||
(unState == INDEXTOSTATEIMAGEMASK( SI_DisabledChecked )));
}
LRESULT APIENTRY
LvxcbProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
/* List view subclass window procedure to trap toggle-check events.
*/
{
WNDPROC pOldProc;
INT iItem;
BOOL fSet;
BOOL fClear;
BOOL fToggle;
iItem = -1;
fSet = fClear = fToggle = FALSE;
if (unMsg == WM_LBUTTONDOWN)
{
LV_HITTESTINFO info;
/* Left mouse button pressed over checkbox icon toggles state.
** Normally, we'd use LVHT_ONITEMSTATEICON and be done with it, but we
** want to work with our cool owner-drawn list view extensions in
** which case the control doesn't know where the icon is on the item,
** so it returns a hit anywhere on the item anyway.
*/
ZeroMemory( &info, sizeof(info) );
info.pt.x = LOWORD( lparam );
info.pt.y = HIWORD( lparam );
info.flags = LVHT_ONITEM;
iItem = ListView_HitTest( hwnd, &info );
if (iItem >= 0)
{
/* OK, it's over item 'iItem'. Now figure out if it's over the
** checkbox. Note this currently doesn't account for use of the
** "indent" feature on an owner-drawn item.
*/
if ((INT )(LOWORD( lparam )) >= GetSystemMetrics( SM_CXSMICON ))
iItem = -1;
else
fToggle = TRUE;
}
}
else if (unMsg == WM_LBUTTONDBLCLK)
{
LV_HITTESTINFO info;
/* Left mouse button double clicked over any area toggles state.
** Normally, we'd use LVHT_ONITEMSTATEICON and be done with it, but we
** want to work with our cool owner-drawn list view extensions in
** which case the control doesn't know where the icon is on the item,
** so it returns a hit anywhere on the item anyway.
*/
ZeroMemory( &info, sizeof(info) );
info.pt.x = LOWORD( lparam );
info.pt.y = HIWORD( lparam );
info.flags = LVHT_ONITEM;
iItem = ListView_HitTest( hwnd, &info );
if (iItem >= 0)
{
/* OK, it's over item 'iItem'. If the click does not occur
* over a checkbox, inform the parent of the double click.
*/
if ((INT )(LOWORD( lparam )) >= GetSystemMetrics( SM_CXSMICON )) {
NM_LISTVIEW nmlv;
nmlv.hdr.code = LVXN_DBLCLK;
nmlv.hdr.hwndFrom = hwnd;
nmlv.iItem = iItem;
FORWARD_WM_NOTIFY(
GetParent(hwnd), GetDlgCtrlID(hwnd), &nmlv, SendMessage);
iItem = -1;
}
/*
* Otherwise, toggle the state.
*/
else
fToggle = TRUE;
}
}
else if (unMsg == WM_CHAR)
{
/* Space bar pressed with item selected toggles check.
** Plus or Equals keys set check.
** Minus key clears check.
*/
switch (wparam)
{
case TEXT(' '):
fToggle = TRUE;
break;
case TEXT('+'):
case TEXT('='):
fSet = TRUE;
break;
case TEXT('-'):
fClear = TRUE;
break;
}
if (fToggle || fSet || fClear)
iItem = ListView_GetNextItem( hwnd, -1, LVNI_SELECTED );
}
else if (unMsg == WM_KEYDOWN)
{
/* Left arrow becomes up arrow and right arrow becomes down arrow so
** the list of checkboxes behaves just like a static group of
** checkboxes.
*/
if (wparam == VK_LEFT)
wparam = VK_UP;
else if (wparam == VK_RIGHT)
wparam = VK_DOWN;
}
if (iItem >= 0)
{
/* If we are handling the spacebar, plus, minus, or equals,
** the change we make applies to all the selected items;
** hence the do {} while(WM_CHAR).
*/
do {
if (fToggle)
{
UINT unOldState;
BOOL fCheck;
fCheck = ListView_GetCheck( hwnd, iItem );
ListView_SetCheck( hwnd, iItem, !fCheck );
}
else if (fSet)
{
if (!ListView_GetCheck( hwnd, iItem ))
ListView_SetCheck( hwnd, iItem, TRUE );
}
else if (fClear)
{
if (ListView_GetCheck( hwnd, iItem ))
ListView_SetCheck( hwnd, iItem, FALSE );
}
iItem = ListView_GetNextItem(hwnd, iItem, LVNI_SELECTED);
} while(iItem >= 0 && unMsg == WM_CHAR);
if (fSet || fClear) {
/* Don't pass to listview to avoid beep.
*/
return 0;
}
}
pOldProc = (WNDPROC )GetProp( hwnd, g_lvxcbContextId );
if (pOldProc)
return CallWindowProc( pOldProc, hwnd, unMsg, wparam, lparam );
return 0;
}
BOOL
ListView_InstallChecks(
IN HWND hwndLv,
IN HINSTANCE hinst )
/* Initialize "list of checkbox" handling for listview 'hwndLv'. 'Hinst'
** is the module instance containing the two checkbox icons. See LVX.RC.
**
** Returns true if successful, false otherwise. Caller must eventually
** call 'ListView_UninstallChecks', typically in WM_DESTROY processing.
*/
{
HICON hIcon;
HIMAGELIST himl;
WNDPROC pOldProc;
// pmay: 397395
//
// Prevent endless loops resulting from accidentally calling this
// api twice.
//
pOldProc = (WNDPROC)GetWindowLongPtr(hwndLv, GWLP_WNDPROC);
if (pOldProc == LvxcbProc)
{
return TRUE;
}
/* Build checkbox image lists.
*/
himl = ImageList_Create(
GetSystemMetrics( SM_CXSMICON ),
GetSystemMetrics( SM_CYSMICON ),
ILC_MASK | ILC_MIRROR, 2, 2 );
/* The order these are added is significant since it implicitly
** establishes the state indices matching SI_Unchecked and SI_Checked.
*/
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Unchecked ) );
if ( NULL != hIcon )
{
ImageList_AddIcon( himl, hIcon );
DeleteObject( hIcon );
}
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Checked ) );
if ( NULL != hIcon )
{
ImageList_AddIcon( himl, hIcon );
DeleteObject( hIcon );
}
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_DisabledUnchecked ) );
if ( NULL != hIcon )
{
ImageList_AddIcon( himl, hIcon );
DeleteObject( hIcon );
}
hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_DisabledChecked ) );
if ( NULL != hIcon )
{
ImageList_AddIcon( himl, hIcon );
DeleteObject( hIcon );
}
ListView_SetImageList( hwndLv, himl, LVSIL_STATE );
/* Register atom for use in the Windows XxxProp calls which are used to
** associate the old WNDPROC with the listview window handle.
*/
if (!g_lvxcbContextId)
g_lvxcbContextId = (LPCTSTR )GlobalAddAtom( _T("RASLVXCB") );
if (!g_lvxcbContextId)
return FALSE;
/* Subclass the current window procedure.
*/
pOldProc = (WNDPROC)SetWindowLongPtr(
hwndLv, GWLP_WNDPROC, (ULONG_PTR)LvxcbProc );
return SetProp( hwndLv, g_lvxcbContextId, (HANDLE )pOldProc );
}
VOID
ListView_InsertSingleAutoWidthColumn(
HWND hwndLv )
// Insert a single auto-sized column into listview 'hwndLv', e.g. for a
// list of checkboxes with no visible column header.
//
{
LV_COLUMN col;
ZeroMemory( &col, sizeof(col) );
col.mask = LVCF_FMT;
col.fmt = LVCFMT_LEFT;
ListView_InsertColumn( hwndLv, 0, &col );
ListView_SetColumnWidth( hwndLv, 0, LVSCW_AUTOSIZE );
}
TCHAR*
Ellipsisize(
IN HDC hdc,
IN TCHAR* psz,
IN INT dxColumn,
IN INT dxColText OPTIONAL )
/* Returns a heap string containing the 'psz' shortened to fit in the
** given width, if necessary, by truncating and adding "...". 'Hdc' is the
** device context with the appropiate font selected. 'DxColumn' is the
** width of the column. It is caller's responsibility to Free the
** returned string.
*/
{
const TCHAR szDots[] = TEXT("...");
SIZE size;
TCHAR* pszResult;
TCHAR* pszResultLast;
TCHAR* pszResult2nd;
DWORD cch;
cch = lstrlen( psz );
pszResult = (TCHAR*)Malloc( (cch * sizeof(TCHAR)) + sizeof(szDots) );
if (!pszResult)
return NULL;
lstrcpy( pszResult, psz );
dxColumn -= dxColText;
if (dxColumn <= 0)
{
/* None of the column text will be visible so bag the calculations and
** just return the original string.
*/
return pszResult;
}
if (!GetTextExtentPoint32( hdc, pszResult, cch, &size ))
{
Free( pszResult );
return NULL;
}
pszResult2nd = CharNext( pszResult );
pszResultLast = pszResult + cch;
while (size.cx > dxColumn && pszResultLast > pszResult2nd)
{
/* Doesn't fit. Lop off a character, add the ellipsis, and try again.
** The minimum result is "..." for empty original or "x..." for
** non-empty original.
*/
pszResultLast = CharPrev( pszResult2nd, pszResultLast );
lstrcpy( pszResultLast, szDots );
if (!GetTextExtentPoint( hdc, pszResult, lstrlen( pszResult ), &size ))
{
Free( pszResult );
return NULL;
}
}
return pszResult;
}
BOOL
LvxDrawItem(
IN DRAWITEMSTRUCT* pdis,
IN PLVXCALLBACK pLvxCallback )
/* Respond to WM_DRAWITEM by drawing the list view item. 'Pdis' is the
** information sent by the system. 'PLvxCallback' is caller's callback to
** get information about drawing the control.
**
** Returns true is processed the message, false otherwise.
*/
{
LV_ITEM item;
INT i;
INT dxState;
INT dyState;
INT dxSmall;
INT dySmall;
INT dxIndent;
UINT uiStyleState;
UINT uiStyleSmall;
HIMAGELIST himlState;
HIMAGELIST himlSmall;
LVXDRAWINFO* pDrawInfo;
RECT rc;
RECT rcClient;
BOOL fEnabled;
BOOL fSelected;
HDC hdc;
HFONT hfont;
TRACE3("LvxDrawItem,i=%d,a=$%X,s=$%X",
pdis->itemID,pdis->itemAction,pdis->itemState);
/* Make sure this is something we want to handle.
*/
if (pdis->CtlType != ODT_LISTVIEW)
return FALSE;
if (pdis->itemAction != ODA_DRAWENTIRE
&& pdis->itemAction != ODA_SELECT
&& pdis->itemAction != ODA_FOCUS)
{
return TRUE;
}
/* Get item information from the list view.
*/
ZeroMemory( &item, sizeof(item) );
item.mask = LVIF_IMAGE + LVIF_STATE;
item.iItem = pdis->itemID;
item.stateMask = LVIS_STATEIMAGEMASK;
if (!ListView_GetItem( pdis->hwndItem, &item ))
{
TRACE("LvxDrawItem GetItem failed");
return TRUE;
}
/* Stash some useful stuff for reference later.
*/
fEnabled = IsWindowEnabled( pdis->hwndItem )
&& !(pdis->itemState & ODS_DISABLED);
fSelected = (pdis->itemState & ODS_SELECTED);
GetClientRect( pdis->hwndItem, &rcClient );
/* Callback owner to get drawing information.
*/
ASSERT(pLvxCallback);
pDrawInfo = pLvxCallback( pdis->hwndItem, pdis->itemID );
ASSERT(pDrawInfo);
/* Get image list icon sizes now, though we draw them last because their
** background is set up during first column text output.
*/
dxState = dyState = 0;
himlState = ListView_GetImageList( pdis->hwndItem, LVSIL_STATE );
if (himlState)
ImageList_GetIconSize( himlState, &dxState, &dyState );
dxSmall = dySmall = 0;
himlSmall = ListView_GetImageList( pdis->hwndItem, LVSIL_SMALL );
if (himlSmall)
ImageList_GetIconSize( himlSmall, &dxSmall, &dySmall );
uiStyleState = uiStyleSmall = ILD_TRANSPARENT;
/* Figure out the number of pixels to indent the item, if any.
*/
if (pDrawInfo->dxIndent >= 0)
dxIndent = pDrawInfo->dxIndent;
else
{
if (dxSmall > 0)
dxIndent = dxSmall;
else
dxIndent = GetSystemMetrics( SM_CXSMICON );
}
/* Get a device context for the window and set it up with the font the
** control says it's using. (Can't use the one that comes in the
** DRAWITEMSTRUCT because sometimes it has the wrong rectangle, see bug
** 13106)
*/
hdc = GetDC( pdis->hwndItem );
if(NULL == hdc)
{
return FALSE;
}
hfont = (HFONT )SendMessage( pdis->hwndItem, WM_GETFONT, 0, 0 );
if (hfont)
SelectObject( hdc, hfont );
/* Set things up as if we'd just got done processing a column that ends
** after the icons, then loop thru each column from left to right.
*/
rc.right = pdis->rcItem.left + dxIndent + dxState + dxSmall;
rc.top = pdis->rcItem.top;
rc.bottom = pdis->rcItem.bottom;
for (i = 0; i < pDrawInfo->cCols; ++i)
{
TCHAR szText[ LVX_MaxColTchars + 1 ];
TCHAR* pszText;
INT dxCol;
/* Get the column width, adding any index and icon width to the first
** column.
*/
dxCol = ListView_GetColumnWidth( pdis->hwndItem, i );
if (i == 0)
dxCol -= dxIndent + dxState + dxSmall;
szText[ 0 ] = TEXT('\0');
ListView_GetItemText( pdis->hwndItem, pdis->itemID, i, szText,
LVX_MaxColTchars + 1 );
/* Update rectangle to enclose just this one item's column 'i'.
*/
rc.left = rc.right;
rc.right = rc.left + dxCol;
if ((pDrawInfo->dwFlags & LVXDI_DxFill)
&& i == pDrawInfo->cCols - 1)
{
INT dxWnd = pdis->rcItem.left + rcClient.right;
if (rc.right < dxWnd)
{
/* When the last column does not fill out a full controls
** width of space, extend it to the right so it does. Note
** this does not mean the user can't scroll off to the right
** if they want.
** (Abolade-Gbadegesin 03-27-96)
** Don't subtrace rc.left when there is only one column;
** this accounts for the space needed for icons.
*/
rc.right = pdis->rcItem.right = dxWnd;
if (i == 0) {
ListView_SetColumnWidth(pdis->hwndItem, i, rc.right);
}
else {
ListView_SetColumnWidth(
pdis->hwndItem, i, rc.right - rc.left );
}
}
}
/* Lop the text and append "..." if it won't fit in the column.
*/
pszText = Ellipsisize( hdc, szText, rc.right - rc.left, LVX_dxColText );
if (!pszText)
continue;
/* Figure out the appropriate text and background colors for the
** current item state.
*/
if (fEnabled)
{
if (fSelected)
{
SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
if (pDrawInfo->dwFlags & LVXDI_Blend50Sel)
uiStyleSmall |= ILD_BLEND50;
}
else
{
if (pDrawInfo->adwFlags[ i ] & LVXDIA_3dFace)
{
SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) );
}
else
{
SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
}
}
}
else
{
if (pDrawInfo->adwFlags[ i ] & LVXDIA_Static)
{
SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) );
}
else
{
SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) );
}
if (pDrawInfo->dwFlags & LVXDI_Blend50Dis)
uiStyleSmall |= ILD_BLEND50;
}
/* Draw the column text. In the first column the background of any
** indent and icons is erased to the text background color.
*/
{
RECT rcBg = rc;
if (i == 0)
rcBg.left -= dxIndent + dxState + dxSmall;
ExtTextOut( hdc, rc.left + LVX_dxColText,
rc.top + LVX_dyColText, ETO_CLIPPED + ETO_OPAQUE,
&rcBg, pszText, lstrlen( pszText ), NULL );
}
Free( pszText );
}
/* Finally, draw the icons, if caller specified any.
*/
if (himlState)
{
ImageList_Draw( himlState, (item.state >> 12) - 1, hdc,
pdis->rcItem.left + dxIndent, pdis->rcItem.top, uiStyleState );
}
if (himlSmall)
{
ImageList_Draw( himlSmall, item.iImage, hdc,
pdis->rcItem.left + dxIndent + dxState,
pdis->rcItem.top, uiStyleSmall );
}
/* Draw the dotted focus rectangle around the whole item, if indicated.
*/
//comment for bug 52688 whistler
// if ((pdis->itemState & ODS_FOCUS) && GetFocus() == pdis->hwndItem)
// DrawFocusRect( hdc, &pdis->rcItem );
//
ReleaseDC( pdis->hwndItem, hdc );
return TRUE;
}
BOOL
LvxMeasureItem(
IN HWND hwnd,
IN OUT MEASUREITEMSTRUCT* pmis )
/* Respond to WM_MEASUREITEM message, i.e. fill in the height of an item
** in the ListView. 'Hwnd' is the owner window. 'Pmis' is the structure
** provided from Windows.
**
** Returns true is processed the message, false otherwise.
*/
{
HDC hdc;
HWND hwndLv;
HFONT hfont;
TEXTMETRIC tm;
UINT dySmIcon;
RECT rc;
TRACE("LvxMeasureItem");
if (pmis->CtlType != ODT_LISTVIEW)
return FALSE;
hwndLv = GetDlgItem( hwnd, pmis->CtlID );
ASSERT(hwndLv);
/* Get a device context for the list view control and set up the font the
** control says it's using. MSDN claims the final font may not be
** available at this point, but it sure seems to be.
*/
hdc = GetDC( hwndLv );
hfont = (HFONT )SendMessage( hwndLv, WM_GETFONT, 0, 0 );
if (hfont)
SelectObject( hdc, hfont );
if (GetTextMetrics( hdc, &tm ))
pmis->itemHeight = tm.tmHeight + 1;
else
pmis->itemHeight = 0;
/* Make sure it's tall enough for a standard small icon.
*/
dySmIcon = (UINT )GetSystemMetrics( SM_CYSMICON );
if (pmis->itemHeight < dySmIcon + LVX_dyIconSpacing)
pmis->itemHeight = dySmIcon + LVX_dyIconSpacing;
/* Set the width since the docs say to, though I don't think it's used by
** list view.
*/
GetClientRect( hwndLv, &rc );
pmis->itemWidth = rc.right - rc.left - 1;
ReleaseDC( hwndLv, hdc );
return TRUE;
}
BOOL
ListView_OwnerHandler(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam,
IN PLVXCALLBACK pLvxCallback )
/* Handler that, when installed, turns a regular report-view-only list
** view (but with style LVS_OWNERDRAWFIXED) into an enhanced list view
** with full width selection bar and other custom column display options.
** It should appear in list view owner's dialog proc as follows:
**
** BOOL
** MyDlgProc(
** IN HWND hwnd,
** IN UINT unMsg,
** IN WPARAM wparam,
** IN LPARAM lparam )
** {
** if (ListView_OwnerHandler(
** hwnd, unMsg, wParam, lParam, MyLvxCallback ))
** return TRUE;
**
** <the rest of your stuff here>
** }
**
** 'PLvxCallback' is caller's callback routine that provides information
** about drawing columns and other options.
**
** Returns true if processed message, false otherwise.
*/
{
/* This routine executes on EVERY message thru the dialog so keep it
** efficient, please.
*/
switch (unMsg)
{
case WM_DRAWITEM:
return LvxDrawItem( (DRAWITEMSTRUCT* )lparam, pLvxCallback );
case WM_MEASUREITEM:
return LvxMeasureItem( hwnd, (MEASUREITEMSTRUCT* )lparam );
}
return FALSE;
}
// StrDup* functions
TCHAR* _StrDup(LPCTSTR psz ) // my local version...
/* Returns heap block containing a copy of 0-terminated string 'psz' or
** NULL on error or is 'psz' is NULL. It is caller's responsibility to
** 'Free' the returned string.
*/
{
TCHAR* pszNew = NULL;
if (psz)
{
pszNew = (TCHAR*)Malloc( (lstrlen( psz ) + 1) * sizeof(TCHAR) );
if (!pszNew)
{
TRACE("StrDup Malloc failed");
return NULL;
}
lstrcpy( pszNew, psz );
}
return pszNew;
}
TCHAR*
StrDupTFromW(
LPCWSTR psz )
/* Returns heap block containing a copy of 0-terminated string 'psz' or
** NULL on error or is 'psz' is NULL. The output string is converted to
** UNICODE. It is caller's responsibility to Free the returned string.
*/
{
#ifdef UNICODE
return _StrDup ( psz );
#else // !UNICODE
CHAR* pszNew = NULL;
if (psz)
{
DWORD cb;
cb = WideCharToMultiByte( CP_ACP, 0, psz, -1, NULL, 0, NULL, NULL );
ASSERT(cb);
pszNew = (CHAR* )Malloc( cb + 1 );
if (!pszNew)
{
TRACE("StrDupTFromW Malloc failed");
return NULL;
}
cb = WideCharToMultiByte( CP_ACP, 0, psz, -1, pszNew, cb, NULL, NULL );
if (cb == 0)
{
Free( pszNew );
TRACE("StrDupTFromW conversion failed");
return NULL;
}
}
return pszNew;
#endif
}
WCHAR*
StrDupWFromT(
LPCTSTR psz )
/* Returns heap block containing a copy of 0-terminated string 'psz' or
** NULL on error or if 'psz' is NULL. The output string is converted to
** UNICODE. It is caller's responsibility to Free the returned string.
*/
{
#ifdef UNICODE
return _StrDup ( psz );
#else // !UNICODE
WCHAR* pszNew = NULL;
if (psz)
{
DWORD cb;
cb = MultiByteToWideChar( CP_ACP, 0, psz, -1, NULL, 0 );
ASSERT(cb);
pszNew = (WCHAR*)Malloc( (cb + 1) * sizeof(WCHAR) );
if (!pszNew)
{
TRACE("StrDupWFromT Malloc failed");
return NULL;
}
cb = MultiByteToWideChar( CP_ACP, 0, psz, -1, pszNew, cb );
if (cb == 0)
{
Free( pszNew );
TRACE("StrDupWFromT conversion failed");
return NULL;
}
}
return pszNew;
#endif
}
void
IpHostAddrToPsz(
IN DWORD dwAddr,
OUT LPTSTR pszBuffer )
// Converts an IP address in host byte order to its
// string representation.
// pszBuffer should be allocated by the caller and be
// at least 16 characters long.
//
{
BYTE* pb = (BYTE*)&dwAddr;
static const TCHAR c_szIpAddr [] = TEXT("%d.%d.%d.%d");
wsprintf (pszBuffer, c_szIpAddr, pb[3], pb[2], pb[1], pb[0]);
}
#ifdef DOWNLEVEL_CLIENT
DWORD
IpPszToHostAddr(
IN LPCTSTR cp )
// Converts an IP address represented as a string to
// host byte order.
//
{
DWORD val, base, n;
TCHAR c;
DWORD parts[4], *pp = parts;
again:
// Collect number up to ``.''.
// Values are specified as for C:
// 0x=hex, 0=octal, other=decimal.
//
val = 0; base = 10;
if (*cp == TEXT('0'))
base = 8, cp++;
if (*cp == TEXT('x') || *cp == TEXT('X'))
base = 16, cp++;
while (c = *cp)
{
if ((c >= TEXT('0')) && (c <= TEXT('9')))
{
val = (val * base) + (c - TEXT('0'));
cp++;
continue;
}
if ((base == 16) &&
( ((c >= TEXT('0')) && (c <= TEXT('9'))) ||
((c >= TEXT('A')) && (c <= TEXT('F'))) ||
((c >= TEXT('a')) && (c <= TEXT('f'))) ))
{
val = (val << 4) + (c + 10 - (
((c >= TEXT('a')) && (c <= TEXT('f')))
? TEXT('a')
: TEXT('A') ) );
cp++;
continue;
}
break;
}
if (*cp == TEXT('.'))
{
// Internet format:
// a.b.c.d
// a.b.c (with c treated as 16-bits)
// a.b (with b treated as 24 bits)
//
if (pp >= parts + 3)
return (DWORD) -1;
*pp++ = val, cp++;
goto again;
}
// Check for trailing characters.
//
if (*cp && (*cp != TEXT(' ')))
return 0xffffffff;
*pp++ = val;
// Concoct the address according to
// the number of parts specified.
//
n = (DWORD) (pp - parts);
switch (n)
{
case 1: // a -- 32 bits
val = parts[0];
break;
case 2: // a.b -- 8.24 bits
val = (parts[0] << 24) | (parts[1] & 0xffffff);
break;
case 3: // a.b.c -- 8.8.16 bits
val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
(parts[2] & 0xffff);
break;
case 4: // a.b.c.d -- 8.8.8.8 bits
val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
break;
default:
return 0xffffffff;
}
return val;
}
#endif
VOID*
Free0(
VOID* p )
/* Like Free, but deals with NULL 'p'.
*/
{
if (!p)
return NULL;
return Free( p );
}
HRESULT ActivateLuna(HANDLE* phActivationContext, ULONG_PTR* pulCookie)
{
HRESULT hr = E_FAIL;
TCHAR szPath[MAX_PATH];
if(0 != GetModuleFileName(_Module.GetResourceInstance(), szPath, sizeof(szPath) / sizeof(TCHAR)))
{
ACTCTX ActivationContext;
ZeroMemory(&ActivationContext, sizeof(ActivationContext));
ActivationContext.cbSize = sizeof(ActivationContext);
ActivationContext.lpSource = szPath;
ActivationContext.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
ActivationContext.lpResourceName = MAKEINTRESOURCE(123);
ULONG_PTR ulCookie;
HANDLE hActivationContext = CreateActCtx(&ActivationContext);
if(NULL != hActivationContext)
{
if(TRUE == ActivateActCtx(hActivationContext, &ulCookie))
{
*phActivationContext = hActivationContext;
*pulCookie = ulCookie;
hr = S_OK;
}
else
{
ReleaseActCtx(hActivationContext);
}
}
}
return hr;
}
HRESULT DeactivateLuna(HANDLE hActivationContext, ULONG_PTR ulCookie)
{
DeactivateActCtx(0, ulCookie);
ReleaseActCtx(hActivationContext);
return S_OK;
}