windows-nt/Source/XPSP1/NT/shell/ext/systray/dll/pccard.c
2020-09-26 16:20:57 +08:00

502 lines
12 KiB
C

/*******************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORP., 1993-1994
*
* TITLE: PCCARD.C
*
* VERSION: 1.0
*
* AUTHOR: RAL
*
* DATE: 11/01/94
*
********************************************************************************
*
* CHANGE LOG:
*
* DATE REV DESCRIPTION
* ----------- --- -------------------------------------------------------------
* Nov. 11, 94 RAL Original
* Oct 23, 95 Shawnb UNICODE enabled
*
*******************************************************************************/
#include "stdafx.h"
#include "systray.h"
#define PCMCIAMENU_PROPERTIES 100
#define PCMCIAMENU_DISABLE 101
#define PCMCIAMENU_SOCKET 200
extern HANDLE g_hPCCARD;
extern HINSTANCE g_hInstance;
static BOOL g_bPCMCIAEnabled = FALSE;
static BOOL g_bPCMCIAIconShown = FALSE;
static HICON g_hPCMCIAIcon = NULL;
#define MAX_DEVNODES 20
static DWORD g_aDevnodes[MAX_DEVNODES];
static BYTE g_aSktState[MAX_DEVNODES] = {0};
static UINT g_numskts = 0;
static DWORD g_PCMCIAFlags = 0;
static TCHAR g_szDevNodeKeyFmt[] = REGSTR_PATH_DYNA_ENUM TEXT ("\\%X");
static const TCHAR g_szEnumKeyPrefix[] = REGSTR_PATH_ENUM TEXT ("\\");
static const TCHAR g_szPCMCIAFlags[] = REGSTR_VAL_SYSTRAYPCCARDFLAGS;
static const TCHAR g_szClass[] = REGSTR_VAL_CLASS;
static const TCHAR g_szModemClass[] = REGSTR_KEY_MODEM_CLASS;
#if NOTYET
static const TCHAR g_szDiskDriveClass[] = REGSTR_KEY_DISKDRIVE_CLASS;
#endif
#define SKTSTATE_GOODEJECT 1
#define SKTSTATE_SHOULDWARN 2
#define SKTSTATE_TYPEKNOWN 4
HKEY OpenDevnodeDynKey(DWORD dwDevnode)
{
TCHAR szScratch[MAX_PATH];
HKEY hkDyn = NULL;
wsprintf(szScratch, g_szDevNodeKeyFmt, dwDevnode);
if (RegOpenKey(HKEY_DYN_DATA, szScratch, &hkDyn) != ERROR_SUCCESS) {
return(NULL);
}
return hkDyn;
}
UINT GetDynInfo(DWORD dwDevNode, LPCTSTR lpszValName,
LPVOID lpBuffer, UINT cbBuffer)
{
UINT cbSize = 0;
HKEY hkDyn = OpenDevnodeDynKey(dwDevNode);
if (hkDyn) {
if (RegQueryValueEx(hkDyn, lpszValName, NULL, NULL,
lpBuffer, &cbBuffer) == ERROR_SUCCESS) {
cbSize = cbBuffer;
}
RegCloseKey(hkDyn);
}
return(cbSize);
}
HKEY OpenDevnodeHwKey(DWORD dwDevnode)
{
TCHAR szScratch[MAX_PATH];
HKEY hkDyn, hkHw = NULL;
UINT cbSize;
UINT cchOffset;
if ((hkDyn = OpenDevnodeDynKey(dwDevnode)) == NULL) {
return(NULL);
}
lstrcpy(szScratch, g_szEnumKeyPrefix);
cbSize = sizeof(szScratch) - sizeof(g_szEnumKeyPrefix);
cchOffset = ARRAYSIZE(g_szEnumKeyPrefix) - 1;
if (RegQueryValueEx(hkDyn, REGSTR_VAL_HARDWARE_KEY,
NULL, NULL, (LPSTR)&(szScratch[cchOffset]),
&cbSize) == ERROR_SUCCESS) {
if (RegOpenKey(HKEY_LOCAL_MACHINE, szScratch, &hkHw) != ERROR_SUCCESS) {
hkHw = NULL;
}
}
RegCloseKey(hkDyn);
return(hkHw);
}
UINT GetHwInfo(DWORD dwDevNode, LPCTSTR lpszValName,
LPVOID lpBuffer, UINT cbBuffer)
{
UINT cbSize = 0;
HKEY hkHw = OpenDevnodeHwKey(dwDevNode);
if (hkHw) {
if (RegQueryValueEx(hkHw, lpszValName, NULL, NULL,
lpBuffer, &cbBuffer) == ERROR_SUCCESS) {
cbSize = cbBuffer;
}
RegCloseKey(hkHw);
}
return(cbSize);
}
void UpdateSktTypes()
{
UINT i;
TCHAR szClassName[32];
for (i = 0; i < g_numskts; i++) {
if (g_aSktState[i] == 0 && g_aDevnodes[i] != 0) {
if (GetHwInfo(g_aDevnodes[i], g_szClass,
szClassName, sizeof(szClassName))) {
g_aSktState[i] |= SKTSTATE_TYPEKNOWN;
if (lstrcmpi(g_szModemClass, szClassName) != 0) {
g_aSktState[i] |= SKTSTATE_SHOULDWARN;
}
}
}
}
}
void UpdateSocketInfo()
{
UINT cbReturned;
if (DeviceIoControl(g_hPCCARD, PCCARD_IOCTL_GET_DEVNODES,
NULL, 0,
g_aDevnodes, sizeof(g_aDevnodes), &cbReturned, NULL)) {
g_numskts = cbReturned / 4;
} else {
g_numskts = 0;
}
UpdateSktTypes();
}
void UpdateGlobalFlags()
{
HKEY hk;
if (RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_SYSTRAY, &hk) ==
ERROR_SUCCESS) {
UINT cb = sizeof(g_PCMCIAFlags);
if (RegQueryValueEx(hk, g_szPCMCIAFlags, NULL, NULL,
(LPSTR)(&g_PCMCIAFlags), &cb) != ERROR_SUCCESS) {
g_PCMCIAFlags = 0;
}
RegCloseKey(hk);
}
}
BOOL PCMCIA_Init(HWND hWnd)
{
if (g_hPCCARD == INVALID_HANDLE_VALUE) {
g_hPCCARD = CreateFile(TEXT ("\\\\.\\PCCARD"), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
UpdateGlobalFlags();
}
return(g_hPCCARD != INVALID_HANDLE_VALUE);
}
//
// NOTE: This function expects the caller to have called UpdateSocketInfo
// prior to calling it.
//
void PCMCIA_UpdateStatus(HWND hWnd, BOOL bShowIcon, DWORD dnRemove)
{
if (bShowIcon) {
UINT i;
bShowIcon = FALSE; // Assume no devnodes
for (i = 0; i < g_numskts; i++) {
if (g_aDevnodes[i] != 0 && g_aDevnodes[i] != dnRemove) {
bShowIcon = TRUE;
break;
}
}
}
if (bShowIcon != g_bPCMCIAIconShown) {
g_bPCMCIAIconShown = bShowIcon;
if (bShowIcon) {
LPTSTR pStr = LoadDynamicString(IDS_PCMCIATIP);
g_hPCMCIAIcon = LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_PCMCIA),
IMAGE_ICON, 16, 16, 0);
SysTray_NotifyIcon(hWnd, STWM_NOTIFYPCMCIA, NIM_ADD,
g_hPCMCIAIcon, pStr);
DeleteDynamicString(pStr);
} else {
SysTray_NotifyIcon(hWnd, STWM_NOTIFYPCMCIA, NIM_DELETE, NULL, NULL);
if (g_hPCMCIAIcon) {
DestroyIcon(g_hPCMCIAIcon);
}
}
}
}
#define DEVNODE_NOT_IN_LIST -1
int FindSocketIndex(DWORD dn)
{
int i;
for (i = 0; i < (int)g_numskts; i++) {
if (g_aDevnodes[i] == dn) {
return(i);
}
}
return(DEVNODE_NOT_IN_LIST);
}
void PCMCIA_DeviceChange(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
int i;
#define lpdbd ((PDEV_BROADCAST_DEVNODE)lParam)
#define DN_STARTED 0x00000008 // WARNING KEEP THIS IN SYNC WITH CONFIGMG.H
if ((wParam != DBT_DEVICEREMOVEPENDING &&
wParam != DBT_DEVICEARRIVAL &&
wParam != DBT_DEVICEREMOVECOMPLETE) ||
lpdbd->dbcd_devicetype != DBT_DEVTYP_DEVNODE) {
return;
}
switch (wParam) {
case DBT_DEVICEREMOVEPENDING: // Query remove succeeded
i = FindSocketIndex(lpdbd->dbcd_devnode);
if (i != DEVNODE_NOT_IN_LIST) {
g_aSktState[i] |= SKTSTATE_GOODEJECT;
}
break;
case DBT_DEVICEARRIVAL:
UpdateSocketInfo();
i = FindSocketIndex(lpdbd->dbcd_devnode);
if (i != DEVNODE_NOT_IN_LIST) {
g_aSktState[i] = 0;
UpdateSktTypes();
PCMCIA_UpdateStatus(hDlg, TRUE, 0);
}
break;
case DBT_DEVICEREMOVECOMPLETE:
{
ULONG Status = 0L;
ULONG Size = sizeof(ULONG);
TCHAR szDevNode[REGSTR_MAX_VALUE_LENGTH];
HKEY hkDevDyna;
wsprintf(szDevNode, TEXT ("%s\\%8X"),REGSTR_PATH_DYNA_ENUM,lpdbd->dbcd_devnode);
if (RegOpenKey( HKEY_DYN_DATA,
szDevNode,
&hkDevDyna ) == ERROR_SUCCESS)
{
RegQueryValueEx( hkDevDyna, REGSTR_VAL_STATUS, 0, NULL, (LPSTR)&Status, &Size );
RegCloseKey(hkDevDyna);
}
if (Status & DN_STARTED)
{
i = FindSocketIndex(lpdbd->dbcd_devnode);
if (i != DEVNODE_NOT_IN_LIST) {
//
// Check to see if we're supposed to warn the user about this
// eject. Only warn if NOT good eject and class is one we warn
// about.
//
BOOL fWarnUser = (g_aSktState[i] &
(SKTSTATE_SHOULDWARN | SKTSTATE_GOODEJECT)) ==
SKTSTATE_SHOULDWARN;
g_aSktState[i] = 0;
UpdateSocketInfo();
PCMCIA_UpdateStatus(hDlg, TRUE, lpdbd->dbcd_devnode);
if (fWarnUser) {
// Make sure the user did not turn this off earlier
UpdateGlobalFlags();
if (!(g_PCMCIAFlags & PCMCIA_REGFLAG_NOWARN)) {
const TCHAR szOpen[] = TEXT ("open");
const TCHAR szRunDLL[] = TEXT ("RUNDLL32.EXE");
const TCHAR szParams[] = TEXT ("RUNDLL mspcic.dll,EjectWarningDlg");
ShellExecute(NULL, szOpen, szRunDLL,
szParams, NULL, SW_SHOW);
}
}
}
}
break;
}
}
#undef lpdbd
}
//
// Called at init time and whenever services are enabled/disabled.
// Returns false if PCMCIA services are not active.
//
BOOL PCMCIA_CheckEnable(HWND hWnd, BOOL bSvcEnabled)
{
BOOL bEnable = bSvcEnabled && PCMCIA_Init(hWnd);
if (bEnable != g_bPCMCIAEnabled) {
g_bPCMCIAEnabled = bEnable;
UpdateSocketInfo();
PCMCIA_UpdateStatus(hWnd, bEnable, 0);
if (!bEnable) {
CloseIfOpen(&g_hPCCARD);
}
}
return(bEnable);
}
/*----------------------------------------------------------------------------
* PCMCIA_CreateMenu()
*
* build a menu containing all sockets.
*
*----------------------------------------------------------------------------*/
//static CRITICAL_SECTION csMenu;
static HMENU _hMenu[2] = {0};
HMENU PCMCIA_CreateMenu(LONG l)
{
//EnterCriticalSection(&csMenu);
if (l > 0) {
if (_hMenu[1] == NULL) {
HMENU hmenu = _hMenu[l] = CreatePopupMenu();
LPTSTR lpszMenu;
if ((lpszMenu = LoadDynamicString(IDS_PCCARDMENU1)) != NULL) {
AppendMenu(hmenu,MF_STRING,PCMCIAMENU_PROPERTIES,lpszMenu);
DeleteDynamicString(lpszMenu);
}
if ((lpszMenu = LoadDynamicString(IDS_PCCARDMENU2)) != NULL) {
AppendMenu(hmenu,MF_STRING,PCMCIAMENU_DISABLE,lpszMenu);
DeleteDynamicString(lpszMenu);
}
SetMenuDefaultItem(hmenu,PCMCIAMENU_PROPERTIES,FALSE);
}
} else {
HMENU hMenu;
if (_hMenu[0]) {
DestroyMenu(_hMenu[0]);
}
hMenu = _hMenu[0] = CreatePopupMenu();
if (g_hPCCARD != INVALID_HANDLE_VALUE) {
TCHAR szDesc[80];
LPTSTR lpszMenuText;
UINT i;
UpdateSocketInfo();
for (i = 0; i < g_numskts; i++) {
if (g_aDevnodes[i] &&
GetHwInfo(g_aDevnodes[i], REGSTR_VAL_DEVDESC, szDesc, sizeof(szDesc))) {
#if NOTYET
DWORD dwChild;
TCHAR szClassName[32];
TCHAR szDriveLetters[32];
if (GetDynInfo(g_aDevnodes[i], REGSTR_VAL_CHILD,
&dwChild, sizeof(dwChild)) &&
GetHwInfo(dwChild, g_szClass,
szClassName, sizeof(szClassName)) &&
lstrcmpi(g_szDiskDriveClass, szClassName) == 0 &&
GetHwInfo(dwChild, REGSTR_VAL_CURDRVLET,
szDriveLetters, sizeof(szDriveLetters)) &&
lstrlen(szDriveLetters) > 0) {
lpszMenuText = LoadDynamicString(IDS_EJECTFMTDISKDRIVE,
szDesc, szDriveLetters[0]);
}
else
#endif
{
lpszMenuText = LoadDynamicString(IDS_EJECTFMT, szDesc);
}
if (lpszMenuText) {
AppendMenu(hMenu,MF_STRING,PCMCIAMENU_SOCKET+i,lpszMenuText);
DeleteDynamicString(lpszMenuText);
}
}
}
}
}
//LeaveCriticalSection(&csMenu);
return _hMenu[l];
}
void PCMCIA_Menu(HWND hwnd, UINT uMenuNum, UINT uButton)
{
POINT pt;
UINT iCmd;
SetForegroundWindow(hwnd);
GetCursorPos(&pt);
iCmd = TrackPopupMenu(PCMCIA_CreateMenu(uMenuNum), uButton | TPM_RETURNCMD | TPM_NONOTIFY,
pt.x, pt.y, 0, hwnd, NULL);
if (iCmd >= PCMCIAMENU_SOCKET) {
const TCHAR szOpen[] = TEXT ("open");
const TCHAR szRunDLL[] = TEXT ("RUNDLL32.EXE");
LPTSTR lpszCommand = LoadDynamicString(IDS_RUNEJECT, iCmd-PCMCIAMENU_SOCKET);
if (lpszCommand == NULL)
return;
ShellExecute(NULL, szOpen, szRunDLL,
lpszCommand, NULL, SW_SHOW);
DeleteDynamicString(lpszCommand);
} else {
switch (iCmd) {
case PCMCIAMENU_PROPERTIES:
SysTray_RunProperties(IDS_RUNPCMCIAPROPERTIES);
break;
case PCMCIAMENU_DISABLE:
PostMessage(hwnd, STWM_ENABLESERVICE, STSERVICE_PCMCIA, FALSE);
break;
}
}
}
void PCMCIA_Notify(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
switch (lParam)
{
case WM_RBUTTONUP:
PCMCIA_Menu(hwnd, 1, TPM_RIGHTBUTTON);
break;
case WM_LBUTTONDOWN:
SetTimer(hwnd, PCMCIA_TIMER_ID, GetDoubleClickTime()+100, NULL);
break;
case WM_LBUTTONDBLCLK:
KillTimer(hwnd, PCMCIA_TIMER_ID);
SysTray_RunProperties(IDS_RUNPCMCIAPROPERTIES);
break;
}
}
void PCMCIA_Timer(HWND hwnd)
{
KillTimer(hwnd, PCMCIA_TIMER_ID);
PCMCIA_Menu(hwnd, 0, TPM_LEFTBUTTON);
}