2025-04-27 07:49:33 -04:00

885 lines
22 KiB
C

/* Copyright (c) 1995, Microsoft Corporation, all rights reserved
**
** util.c
** Remote Access Common Dialog APIs
** Utility routines
** Listed alphabetically
*/
#include "rasdlgp.h" // Our private header
#include <dlgs.h> // Common dialog resource constants
#include <lmwksta.h> // NetWkstaGetInfo
#include <lmapibuf.h> // NetApiBufferFree
/* Cached workstation and logon information. See GetLogonUser,
** GetLogonDomain, and GetComputer.
*/
static TCHAR g_szLogonUser[ UNLEN + 1 ];
static TCHAR g_szLogonDomain[ DNLEN + 1 ];
static TCHAR g_szComputer[ CNLEN + 1 ];
/*----------------------------------------------------------------------------
** Help maps
**----------------------------------------------------------------------------
*/
static DWORD g_adwPnHelp[] =
{
CID_LE_ST_Item, HID_PN_EB_NewNumber,
CID_LE_EB_Item, HID_PN_EB_NewNumber,
CID_LE_PB_Add, HID_PN_PB_Add,
CID_LE_PB_Replace, HID_PN_PB_Replace,
CID_LE_ST_List, HID_PN_LB_List,
CID_LE_LB_List, HID_PN_LB_List,
CID_LE_PB_Up, HID_PN_PB_Up,
CID_LE_PB_Down, HID_PN_PB_Down,
CID_LE_PB_Delete, HID_PN_PB_Delete,
CID_LE_CB_Promote, HID_PN_CB_Promote,
0, 0
};
/*----------------------------------------------------------------------------
** Local helper prototypes (alphabetically)
**----------------------------------------------------------------------------
*/
VOID
GetWkstaUserInfo(
void );
/*----------------------------------------------------------------------------
** Utility routines (alphabetically)
**----------------------------------------------------------------------------
*/
BOOL
AllLinksAreModems(
IN PBENTRY* pEntry )
/* Returns true if all links associated with the entry are modem links
** (MXS or Unimodem), false otherwise.
*/
{
DTLNODE* pNode;
if (pEntry->pdtllistLinks)
{
for (pNode = DtlGetFirstNode( pEntry->pdtllistLinks );
pNode;
pNode = DtlGetNextNode( pNode ))
{
PBLINK* pLink = (PBLINK* )DtlGetData( pNode );
if (pLink->pbport.pbdevicetype != PBDT_Modem)
return FALSE;
}
}
return TRUE;
}
BOOL
AllLinksAreMxsModems(
IN PBENTRY* pEntry )
/* Returns true if all links associated with the entry are MXS modem
** links, false otherwise.
*/
{
DTLNODE* pNode;
if (pEntry->pdtllistLinks)
{
for (pNode = DtlGetFirstNode( pEntry->pdtllistLinks );
pNode;
pNode = DtlGetNextNode( pNode ))
{
PBLINK* pLink = (PBLINK* )DtlGetData( pNode );
if (pLink->pbport.pbdevicetype != PBDT_Modem
|| !pLink->pbport.fMxsModemPort)
{
return FALSE;
}
}
}
return TRUE;
}
/*---------------------------------------------------------------------------
This is a hack! At this point, the router portions should call to
mpradmin.hlp not rasphone.hlp. To minimize code churn, only those
portions of the code that can determine if they are for a router will
call ContextHelpHack(). The rest of the code can call ContextHelp().
---------------------------------------------------------------------------*/
VOID
ContextHelpHack(
IN DWORD* padwMap,
IN HWND hwndDlg,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam,
IN BOOL fRouter)
/* 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 = 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;
TRACE1("WinHelp(%s)", pszHelpFile);
WinHelp( hwnd, pszHelpFile, unType, (ULONG_PTR)padwMap );
}
VOID
ContextHelp(
IN DWORD* padwMap,
IN HWND hwndDlg,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam)
{
ContextHelpHack(padwMap, hwndDlg, unMsg, wparam, lparam, FALSE);
}
HWND
CreateWizardBitmap(
IN HWND hwndDlg,
IN BOOL fPage )
/* Create a static control that displays the RAS wizard bitmap at the
** standard place on dialog 'hwndDlg'. 'FPage' is set if the bitmap is
** being placed on a property page, false for the equivalent placement on
** a dialog.
**
** Returns the bitmap window handle or NULL or error.
*/
{
HWND hwnd;
INT x;
INT y;
if (fPage)
x = y = 0;
else
x = y = 10;
hwnd =
CreateWindowEx(
0,
TEXT("static"),
NULL,
WS_VISIBLE | WS_CHILD | SS_SUNKEN | SS_BITMAP,
x, y, 80, 140,
hwndDlg,
(HMENU )CID_BM_Wizard,
g_hinstDll,
NULL );
if (hwnd)
{
if (!g_hbmWizard)
{
g_hbmWizard = LoadBitmap(
g_hinstDll, MAKEINTRESOURCE( BID_Wizard ) );
}
SendMessage( hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM )g_hbmWizard );
}
return hwnd;
}
TCHAR*
DisplayPszFromDeviceAndPort(
IN TCHAR* pszDevice,
IN TCHAR* pszPort )
/* Returns address of heap block psz containing the MXS modem list display
** form, i.e. the device name 'pszDevice' followed by the port name
** 'pszPort'. It's caller's responsibility to Free the returned string.
*/
{
TCHAR* pszResult;
TCHAR* pszD;
if (pszDevice)
pszD = NULL;
else
pszD = pszDevice = PszFromId( g_hinstDll, SID_UnknownDevice );
pszResult = PszFromDeviceAndPort( pszDevice, pszPort );
Free0( pszD );
return pszResult;
}
TCHAR*
FirstPhoneNumberFromEntry(
IN PBENTRY* pEntry )
/* Returns the first phone number of the first link of entry 'pEntry' or
** an empty string if none. The returned address is into the list of
** phone numbers and should be copied if it needs to be stored.
*/
{
TCHAR* pszPhoneNumber;
DTLNODE* pNode;
PBLINK* pLink;
TRACE("FirstPhoneNumberFromEntry");
ASSERT(pEntry->pdtllistLinks);
pNode = DtlGetFirstNode( pEntry->pdtllistLinks );
ASSERT(pNode);
pLink = (PBLINK* )DtlGetData( pNode );
ASSERT(pLink);
return FirstPszFromList( pLink->pdtllistPhoneNumbers );
}
TCHAR*
FirstPszFromList(
IN DTLLIST* pPszList )
/* Returns the first string from the first node of 'pPszList' or an empty
** string if none. The returned address is into the list and should be
** copied if it needs to be stored.
*/
{
TCHAR* psz;
DTLNODE* pNode;
TRACE("FirstPszFromList");
if (DtlGetNodes( pPszList ) > 0)
{
pNode = DtlGetFirstNode( pPszList );
ASSERT(pNode);
psz = (TCHAR* )DtlGetData( pNode );
ASSERT( psz );
}
else
psz = TEXT("");
return psz;
}
DWORD
FirstPhoneNumberToEntry(
IN PBENTRY* pEntry,
IN TCHAR* pszPhoneNumber )
/* Sets the first phone number of the first link of entry 'pEntry' to
** 'pszPhoneNumber'.
**
** Returns 0 if successful, or an error code.
*/
{
DTLNODE* pNode;
PBLINK* pLink;
TCHAR* pszNew;
TRACE("FirstPhoneNumberToEntry");
ASSERT(pEntry->pdtllistLinks);
pNode = DtlGetFirstNode( pEntry->pdtllistLinks );
ASSERT(pNode);
pLink = (PBLINK* )DtlGetData( pNode );
ASSERT(pLink);
ASSERT(pLink->pdtllistPhoneNumbers);
return FirstPszToList( pLink->pdtllistPhoneNumbers, pszPhoneNumber );
}
DWORD
FirstPszToList(
IN DTLLIST* pPszList,
IN TCHAR* psz )
/* Sets the string of the first node of the list 'pPszList' to a copy of
** 'psz'. If 'psz' is "" the first node is deleted.
**
** Returns 0 if successful, or an error code.
*/
{
DTLNODE* pNode;
TCHAR* pszNew;
ASSERT(pPszList);
/* Delete the existing first node, if any.
*/
if (DtlGetNodes( pPszList ) > 0)
{
pNode = DtlGetFirstNode( pPszList );
DtlRemoveNode( pPszList, pNode );
DestroyPszNode( pNode );
}
/* Create a new first node and link it. An empty string is not added.
*/
if (*psz == TEXT('\0'))
return 0;
pszNew = StrDup( psz );
pNode = DtlCreateNode( pszNew, 0 );
if (!pszNew || !pNode)
{
Free0( pszNew );
return ERROR_NOT_ENOUGH_MEMORY;
}
DtlAddNodeFirst( pPszList, pNode );
return 0;
}
TCHAR*
GetComputer(
void )
/* Returns the address of a static buffer containing the local
** workstation's computer name.
*/
{
if (g_szComputer[ 0 ] == TEXT('\0'))
{
DWORD dwErr;
WKSTA_INFO_100* pInfo;
pInfo = NULL;
TRACE("NetWkstaGetInfo");
dwErr = NetWkstaGetInfo( NULL, 100, (LPBYTE* )&pInfo );
TRACE1("NetWkstaGetInfo=%d",dwErr);
if (pInfo)
{
if (dwErr == 0)
lstrcpy( g_szComputer, pInfo->wki100_computername );
NetApiBufferFree( pInfo );
}
}
TRACEW1("GetComputer=%s",g_szComputer);
return g_szComputer;
}
DWORD
GetDefaultEntryName(
IN DTLLIST* pdtllistEntries,
IN BOOL fRouter,
OUT TCHAR** ppszName )
/* Loads a default entry name into '*ppszName' that is unique in the list
** of phonebook entries 'pdtllistEntries'. 'FRouter' is set if a
** router-style name should be chosen rather than a client-style name. It
** is caller's responsibility to Free the returned string.
**
** Returns 0 if successful or an error code.
*/
{
TCHAR szBuf[ RAS_MaxEntryName + 1 ];
TCHAR* pszDefault;
DWORD dwDefaultLen;
LONG lNum;
*ppszName = NULL;
pszDefault = PszFromId( g_hinstDll,
(fRouter) ? SID_DefaultRouterEntry : SID_DefaultEntry );
if (!pszDefault)
return ERROR_NOT_ENOUGH_MEMORY;
dwDefaultLen = lstrlen( pszDefault );
lstrcpy( szBuf, pszDefault );
lNum = 2;
while (EntryNodeFromName( pdtllistEntries, szBuf ))
{
lstrcpy( szBuf, pszDefault );
LToT( lNum, szBuf + dwDefaultLen, 10 );
++lNum;
}
Free( pszDefault );
*ppszName = StrDup( szBuf );
if (!*ppszName)
return ERROR_NOT_ENOUGH_MEMORY;
return 0;
}
TCHAR*
GetLogonDomain(
void )
{
if (g_szLogonDomain[ 0 ] == TEXT('\0'))
GetWkstaUserInfo();
TRACEW1("GetLogonDomain=%s",g_szLogonDomain);
return g_szLogonDomain;
}
TCHAR*
GetLogonUser(
void )
/* Returns the address of a static buffer containing the logged on user's
** account name.
*/
{
if (g_szLogonUser[ 0 ] == TEXT('\0'))
GetWkstaUserInfo();
TRACEW1("GetLogonUser=%s",g_szLogonUser);
return g_szLogonUser;
}
VOID
GetWkstaUserInfo(
void )
/* Helper to load statics with NetWkstaUserInfo information. See
** GetLogonUser and GetLogonDomain.
*/
{
DWORD dwErr;
WKSTA_USER_INFO_1* pInfo;
pInfo = NULL;
TRACE("NetWkstaUserGetInfo");
dwErr = NetWkstaUserGetInfo( NULL, 1, (LPBYTE* )&pInfo );
TRACE1("NetWkstaUserGetInfo=%d",dwErr);
if (pInfo)
{
if (dwErr == 0)
{
lstrcpy( g_szLogonUser, pInfo->wkui1_username );
lstrcpy( g_szLogonDomain, pInfo->wkui1_logon_domain );
}
NetApiBufferFree( pInfo );
}
}
BOOL
IsLocalPad(
IN PBENTRY* pEntry )
/* Returns true if 'pEntry' is a local PAD device, i.e. the first link of
** the entry has device type "pad", false otherwise.
*/
{
PBLINK* pLink;
DTLNODE* pNode;
if (!pEntry)
return FALSE;
ASSERT(pEntry->pdtllistLinks);
pNode = DtlGetFirstNode( pEntry->pdtllistLinks );
ASSERT(pNode);
pLink = (PBLINK* )DtlGetData( pNode );
ASSERT(pLink);
return (pLink->pbport.pbdevicetype == PBDT_Pad);
}
VOID
LaunchMonitor(
IN HWND hwndNotify )
/* Launch the Dial-Up Networking monitor. 'HwndNotify' is the window to
** be reactivated when the monitor is up.
*/
{
TRACE("LaunchMonitor");
if (FindWindow( TEXT("RasmonWinClass"), NULL ))
return;
/* Write our hwnd in shared memory for rasmon to read.
*/
if (!g_pRmmem)
{
g_hRmmem = CreateFileMapping(
(HANDLE )INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0L, sizeof(RMMEM), RMMEMRASPHONE );
if (g_hRmmem)
g_pRmmem = MapViewOfFile( g_hRmmem, FILE_MAP_WRITE, 0L, 0L, 0L );
else
{
TRACE("CreateFileMapping failed");
}
}
if (g_pRmmem)
{
g_pRmmem->hwnd = hwndNotify;
g_pRmmem->pid = GetCurrentProcessId();
TRACE2("RmMem:h=$%08x,pid=$%08x",g_pRmmem->hwnd,g_pRmmem->pid);
}
/* Start RASMON.EXE.
*/
WinExec( "rasmon.exe", SW_SHOWNA );
TRACE("LaunchMonitor done");
}
BOOL
PhoneNumberDlg(
IN HWND hwndOwner,
IN BOOL fRouter,
IN OUT DTLLIST* pList,
IN OUT BOOL* pfCheck )
/* Popup the phone number list dialog. 'HwndOwner' is the owner of the
** created dialog. 'FRouter' indicates router-style labels should be used
** rather than client-style. 'PList' is a list of Psz nodes containing
** the phone numbers. 'PfCheck' is the address that contains the initial
** "promote number" checkbox setting and which receives the value set by
** user.
**
** Returns true if user presses OK and succeeds, false if he presses
** Cancel or encounters an error.
*/
{
DWORD dwErr;
DWORD sidHuntTitle;
DWORD sidHuntItemLabel;
DWORD sidHuntListLabel;
DWORD sidHuntCheckLabel;
TCHAR *pszTitle = NULL, *pszItem = NULL, *pszList = NULL, *pszCheck = NULL;
TRACE("PhoneNumberDlg");
if (fRouter)
{
sidHuntTitle = SID_RouterHuntTitle;
sidHuntItemLabel = SID_RouterHuntItemLabel;
sidHuntListLabel = SID_RouterHuntListLabel;
sidHuntCheckLabel = SID_RouterHuntCheckLabel;
}
else
{
sidHuntTitle = SID_HuntTitle;
sidHuntItemLabel = SID_HuntItemLabel;
sidHuntListLabel = SID_HuntListLabel;
sidHuntCheckLabel = SID_HuntCheckLabel;
}
pszTitle = PszFromId( g_hinstDll, sidHuntTitle );
pszItem = PszFromId( g_hinstDll, sidHuntItemLabel );
pszList = PszFromId( g_hinstDll, sidHuntListLabel );
pszCheck = PszFromId( g_hinstDll, sidHuntCheckLabel );
dwErr =
ListEditorDlg(
hwndOwner,
pList,
pfCheck,
RAS_MaxPhoneNumber,
pszTitle,
pszItem,
pszList,
pszCheck,
NULL,
0,
g_adwPnHelp,
0,
NULL );
Free0( pszTitle );
Free0( pszItem );
Free0( pszList );
Free0( pszCheck );
return dwErr;
}
VOID
PositionDlg(
IN HWND hwndDlg,
IN BOOL fPosition,
IN LONG xDlg,
IN LONG yDlg )
/* Positions the dialog 'hwndDlg' based on caller's API settings, where
** 'fPosition' is the RASxxFLAG_PositionDlg flag and 'xDlg' and 'yDlg' are
** the coordinates.
*/
{
if (fPosition)
{
/* Move it to caller's coordinates.
*/
SetWindowPos( hwndDlg, NULL, xDlg, yDlg, 0, 0,
SWP_NOZORDER + SWP_NOSIZE );
UnclipWindow( hwndDlg );
}
else
{
/* Center it on the owner window, or on the screen if none.
*/
CenterWindow( hwndDlg, GetParent( hwndDlg ) );
}
}
LRESULT CALLBACK
PositionDlgStdCallWndProc(
int code,
WPARAM wparam,
LPARAM lparam )
/* Standard Win32 CallWndProc hook callback that positions the next dialog
** to start in this thread at our standard offset relative to owner.
*/
{
/* 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 position
** the dialog at the standard place relative to the calling dialog.
*/
if (p->message == WM_INITDIALOG)
{
RECT rect;
HWND hwndOwner;
hwndOwner = GetParent( p->hwnd );
GetWindowRect( hwndOwner, &rect );
SetWindowPos( p->hwnd, NULL,
rect.left + DXSHEET, rect.top + DYSHEET,
0, 0, SWP_NOZORDER + SWP_NOSIZE );
UnclipWindow( p->hwnd );
}
}
return 0;
}
TCHAR*
PszFromPhoneNumberList(
IN DTLLIST* pList )
/* Returns the phone numbers in phone number list 'pList' in a comma
** string or NULL on error. It is caller's responsiblity to Free the
** returned string.
*/
{
TCHAR* pszResult;
DTLNODE* pNode;
DWORD cb;
const TCHAR* pszSeparator = TEXT(", ");
cb = (DtlGetNodes( pList ) *
(RAS_MaxPhoneNumber + lstrlen( pszSeparator )) + 1)
* sizeof(TCHAR);
pszResult = Malloc( cb );
if (!pszResult)
return NULL;
*pszResult = TEXT('\0');
for (pNode = DtlGetFirstNode( pList );
pNode;
pNode = DtlGetNextNode( pNode ))
{
TCHAR* psz = (TCHAR* )DtlGetData( pNode );
ASSERT(psz);
if (*pszResult)
lstrcat( pszResult, pszSeparator );
lstrcat( pszResult, psz );
}
pszResult = Realloc( pszResult,
(lstrlen( pszResult ) + 1) * sizeof(TCHAR) );
ASSERT(pszResult);
return pszResult;
}
#if 0
LRESULT CALLBACK
SelectDesktopCallWndRetProc(
int code,
WPARAM wparam,
LPARAM lparam )
/* Standard Win32 CallWndRetProc hook callback that makes "Desktop" the
** initial selection of the FileOpen "Look in" combo-box.
*/
{
/* Arrive here when any window procedure associated with our thread is
** called.
*/
if (!wparam)
{
CWPRETSTRUCT* p = (CWPRETSTRUCT* )lparam;
/* The message is from outside our process. Look for the MessageBox
** dialog initialization message and take that opportunity to set the
** "Look in:" combo box to the first item, i.e. "Desktop". FileOpen
** keys off CBN_CLOSEUP rather than CBN_SELCHANGE to update the
** "contents" listbox.
*/
if (p->message == WM_INITDIALOG)
{
HWND hwndLbLookIn;
hwndLbLookIn = GetDlgItem( p->hwnd, cmb2 );
ComboBox_SetCurSel( hwndLbLookIn, 0 );
SendMessage( p->hwnd, WM_COMMAND,
MAKELONG( cmb2, CBN_CLOSEUP ), (LPARAM )hwndLbLookIn );
}
}
return 0;
}
#endif
VOID
TweakTitleBar(
IN HWND hwndDlg )
/* Adjust the title bar to include an icon if unowned and the modal frame
** if not. 'HwndDlg' is the dialog window.
*/
{
if (GetParent( hwndDlg ))
{
LONG lStyle;
LONG lStyleAdd;
/* Drop the system menu and go for the dialog look.
*/
lStyleAdd = WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE;;
lStyle = GetWindowLong( hwndDlg, GWL_EXSTYLE );
if (lStyle)
SetWindowLong( hwndDlg, GWL_EXSTYLE, lStyle | lStyleAdd );
}
else
{
/* Stick a rasphone icon in the upper left of the dialog, and
** more importantly on the task bar
*/
SendMessage( hwndDlg, WM_SETICON, TRUE,
(LPARAM)LoadIcon( g_hinstDll, MAKEINTRESOURCE( IID_Rasphone ) ) );
}
}
int CALLBACK
UnHelpCallbackFunc(
IN HWND hwndDlg,
IN UINT unMsg,
IN LPARAM lparam )
/* A standard Win32 commctrl PropSheetProc. See MSDN documentation.
**
** Returns 0 always.
*/
{
TRACE2("UnHelpCallbackFunc(m=%d,l=%08x)",unMsg,lparam);
if (unMsg == PSCB_PRECREATE)
{
extern BOOL g_fNoWinHelp;
/* Turn off context help button if WinHelp won't work. See
** common\uiutil\ui.c.
*/
if (g_fNoWinHelp)
{
DLGTEMPLATE* pDlg = (DLGTEMPLATE* )lparam;
pDlg->style &= ~(DS_CONTEXTHELP);
}
}
return 0;
}