mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
625 lines
14 KiB
625 lines
14 KiB
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT MICROSOFT CORP., 1993-1994
|
|
*
|
|
* TITLE: SYSTRAY.C
|
|
*
|
|
* VERSION: 2.0
|
|
*
|
|
* AUTHOR: TCS/RAL
|
|
*
|
|
* DATE: 08 Feb 1994
|
|
*
|
|
********************************************************************************
|
|
*
|
|
* CHANGE LOG:
|
|
*
|
|
* DATE REV DESCRIPTION
|
|
* ----------- --- -------------------------------------------------------------
|
|
* 08 Feb 1994 TCS Original implementation.
|
|
* 11 Nov 1994 RAL Converted from batmeter to systray
|
|
* 11 Aug 1995 JEM Split batmeter functions into power.c & minor enahncements
|
|
* 23 Oct 1995 Shawnb Unicode enabled
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#include "systray.h"
|
|
|
|
// Global instance handle of this application.
|
|
HINSTANCE g_hInstance;
|
|
|
|
// Global handle to VxDs
|
|
HANDLE g_hVpowerD = INVALID_HANDLE_VALUE;
|
|
HANDLE g_hPCCARD = INVALID_HANDLE_VALUE;
|
|
|
|
static UINT g_uEnabledSvcs = 0;
|
|
|
|
const TCHAR g_szRegstrPathSysTray[] = REGSTR_PATH_SYSTRAY;
|
|
static const TCHAR g_szWindowClassName[] = SYSTRAY_CLASSNAME;
|
|
static const TCHAR g_szRegstrValSysTraySvc[] = REGSTR_VAL_SYSTRAYSVCS;
|
|
static const TCHAR g_szRegstrPathRun[] = REGSTR_PATH_RUN;
|
|
|
|
// Context sensitive help array used by the WinHelp engine.
|
|
extern const DWORD g_ContextMenuHelpIDs[];
|
|
|
|
LRESULT
|
|
PASCAL
|
|
SysTrayWndProc(
|
|
HWND hWnd,
|
|
UINT Message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
VOID PASCAL UpdateRunLine (BOOL fEnabled);
|
|
|
|
|
|
/**************************************************************************/
|
|
|
|
|
|
// stolen from the CRT, used to shrink our code
|
|
|
|
int _stdcall ModuleEntry(void)
|
|
{
|
|
int i;
|
|
STARTUPINFO si;
|
|
LPTSTR pszCmdLine = GetCommandLine ();
|
|
|
|
if ( *pszCmdLine == TEXT ('\"') ) {
|
|
/*
|
|
* Scan, and skip over, subsequent characters until
|
|
* another double-quote or a null is encountered.
|
|
*/
|
|
while ( *++pszCmdLine && (*pszCmdLine != TEXT ('\"')) )
|
|
;
|
|
|
|
/*
|
|
* If we stopped on a double-quote (usual case), skip
|
|
* over it.
|
|
*/
|
|
if ( *pszCmdLine == TEXT ('\"') )
|
|
pszCmdLine++;
|
|
}
|
|
else {
|
|
while (*pszCmdLine > ' ')
|
|
pszCmdLine++;
|
|
}
|
|
|
|
/*
|
|
* Skip past any white space preceeding the second token.
|
|
*/
|
|
while (*pszCmdLine && (*pszCmdLine <= ' ')) {
|
|
pszCmdLine++;
|
|
}
|
|
|
|
si.dwFlags = 0;
|
|
GetStartupInfo (&si);
|
|
|
|
i = WinMain(GetModuleHandle(NULL), NULL, (LPSTR)pszCmdLine,
|
|
si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
|
|
ExitProcess(i);
|
|
return i; // We never come here.
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* EnableService
|
|
*
|
|
* DESCRIPTION:
|
|
* Turns the specified service on or off depending upon the value in
|
|
* fEnable and writes the new value to the registry.
|
|
*
|
|
* PARAMETERS:
|
|
* (returns), Mask of all currently enabled services.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
|
|
UINT EnableService(UINT uNewSvcMask, BOOL fEnable)
|
|
{
|
|
HKEY hk;
|
|
UINT CurSvcMask = STSERVICE_ALL; // Assume all enabled
|
|
|
|
if (RegCreateKey(HKEY_CURRENT_USER, g_szRegstrPathSysTray, &hk) == ERROR_SUCCESS) {
|
|
DWORD cb = sizeof(CurSvcMask);
|
|
RegQueryValueEx(hk, g_szRegstrValSysTraySvc, NULL, NULL, (LPSTR)&CurSvcMask, &cb);
|
|
|
|
if (uNewSvcMask) {
|
|
if (fEnable) {
|
|
CurSvcMask |= uNewSvcMask;
|
|
} else {
|
|
CurSvcMask &= ~uNewSvcMask;
|
|
}
|
|
|
|
RegSetValueEx(hk, g_szRegstrValSysTraySvc, 0, REG_DWORD, (LPSTR)&CurSvcMask, sizeof(CurSvcMask));
|
|
UpdateRunLine(CurSvcMask != 0);
|
|
}
|
|
|
|
RegCloseKey(hk);
|
|
}
|
|
|
|
return(CurSvcMask & STSERVICE_ALL);
|
|
}
|
|
|
|
|
|
//
|
|
// For some reason atoi does not link, so this replaces it
|
|
//
|
|
|
|
INT intval(LPCTSTR lpsz)
|
|
{
|
|
INT i = 0;
|
|
while (*lpsz >= TEXT ('0') && *lpsz <= TEXT ('9')) {
|
|
i = i * 10 + (int)(*lpsz - TEXT ('0'));
|
|
lpsz++;
|
|
}
|
|
return(i);
|
|
}
|
|
|
|
|
|
//
|
|
// Closes file handles IFF the global variable != INVALID_HANDLE_VALUE
|
|
//
|
|
void CloseIfOpen(LPHANDLE lph)
|
|
{
|
|
if (*lph != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(*lph);
|
|
*lph = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WinMain
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
* if lpCmdLine contains an integer value then we'll enable that service
|
|
*
|
|
*******************************************************************************/
|
|
int
|
|
PASCAL
|
|
WinMain(
|
|
HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpszCmdLine,
|
|
int nCmdShow
|
|
)
|
|
{
|
|
WNDCLASSEX WndClassEx;
|
|
HWND hWnd;
|
|
MSG Msg;
|
|
HWND hExistWnd = FindWindow(g_szWindowClassName, NULL);
|
|
UINT iEnableServ = intval((LPTSTR)lpszCmdLine);
|
|
|
|
g_hInstance = hInstance;
|
|
|
|
if (hExistWnd) {
|
|
//
|
|
// NOTE: Send an enable message even if the command line parameter
|
|
// is 0 to force us to re-check for all enabled services.
|
|
//
|
|
SendMessage(hExistWnd, STWM_ENABLESERVICE, iEnableServ, TRUE);
|
|
goto ExitMain;
|
|
}
|
|
|
|
// Register a window class for the Battery Meter. This is done so that
|
|
// the power control panel applet has the ability to detect us and turn us
|
|
// off if we're running.
|
|
|
|
WndClassEx.cbSize = sizeof(WNDCLASSEX);
|
|
WndClassEx.style = CS_GLOBALCLASS;
|
|
WndClassEx.lpfnWndProc = SysTrayWndProc;
|
|
WndClassEx.cbClsExtra = 0;
|
|
WndClassEx.cbWndExtra = DLGWINDOWEXTRA;
|
|
WndClassEx.hInstance = hInstance;
|
|
WndClassEx.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_BATTERYPLUG));
|
|
WndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
WndClassEx.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
|
|
WndClassEx.lpszMenuName = NULL;
|
|
WndClassEx.lpszClassName = g_szWindowClassName;
|
|
WndClassEx.hIconSm = NULL;
|
|
|
|
if (!RegisterClassEx(&WndClassEx))
|
|
goto ExitMain;
|
|
|
|
// Create the Battery Meter and get this thing going!!!
|
|
|
|
hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_BATTERYMETER), NULL, NULL);
|
|
|
|
|
|
//
|
|
// This message will initialize all existing services if iEnableServ
|
|
// is 0, so it's used to do the general initialization as well as to
|
|
// enable a new service via the command line.
|
|
//
|
|
SendMessage(hWnd, STWM_ENABLESERVICE, iEnableServ, TRUE);
|
|
while (GetMessage(&Msg, NULL, 0, 0))
|
|
{
|
|
if (!IsDialogMessage(hWnd, &Msg))
|
|
{
|
|
TranslateMessage(&Msg);
|
|
DispatchMessage(&Msg);
|
|
}
|
|
}
|
|
|
|
ExitMain:
|
|
CloseIfOpen(&g_hVpowerD); // Close device handles
|
|
CloseIfOpen(&g_hPCCARD);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* UpdateServices
|
|
*
|
|
* DESCRIPTION:
|
|
* Enables or disables all services specified by the uEnabled mask.
|
|
*
|
|
* PARAMETERS:
|
|
* (returns), TRUE if any service wants to remain resident.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL UpdateServices(HWND hWnd, UINT uEnabled)
|
|
{
|
|
BOOL bAnyEnabled = FALSE;
|
|
g_uEnabledSvcs = uEnabled;
|
|
bAnyEnabled |= Power_CheckEnable(hWnd, uEnabled & STSERVICE_POWER);
|
|
bAnyEnabled |= PCMCIA_CheckEnable(hWnd, uEnabled & STSERVICE_PCMCIA);
|
|
bAnyEnabled |= Volume_CheckEnable(hWnd, uEnabled & STSERVICE_VOLUME);
|
|
return(bAnyEnabled);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* SysTrayWndProc
|
|
*
|
|
* DESCRIPTION:
|
|
* Callback procedure for the BatteryMeter window.
|
|
*
|
|
* PARAMETERS:
|
|
* hWnd, handle of BatteryMeter window.
|
|
* Message,
|
|
* wParam,
|
|
* lParam,
|
|
* (returns),
|
|
*
|
|
*******************************************************************************/
|
|
|
|
LRESULT
|
|
PASCAL
|
|
SysTrayWndProc(
|
|
HWND hWnd,
|
|
UINT Message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
|
|
switch (Message) {
|
|
|
|
case WM_COMMAND:
|
|
Power_OnCommand(hWnd, wParam, lParam);
|
|
break;
|
|
|
|
case STWM_NOTIFYPOWER:
|
|
Power_Notify(hWnd, wParam, lParam);
|
|
break;
|
|
|
|
case STWM_NOTIFYPCMCIA:
|
|
PCMCIA_Notify(hWnd, wParam, lParam);
|
|
break;
|
|
|
|
case STWM_NOTIFYVOLUME:
|
|
Volume_Notify(hWnd, wParam, lParam);
|
|
break;
|
|
|
|
case WM_SETFOCUS:
|
|
SetFocus(GetDlgItem(hWnd,IDOK));
|
|
break;
|
|
|
|
case MM_MIXM_CONTROL_CHANGE:
|
|
Volume_ControlChange(hWnd, (HMIXER)wParam, (DWORD)lParam);
|
|
break;
|
|
|
|
case MM_MIXM_LINE_CHANGE:
|
|
Volume_LineChange(hWnd, (HMIXER)wParam, (DWORD)lParam);
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
switch (wParam) {
|
|
|
|
case PWRSTATUS_UPDATE_TIMER_ID:
|
|
Power_UpdateStatus(hWnd, NIM_MODIFY, FALSE);
|
|
break;
|
|
|
|
case PCMCIA_TIMER_ID:
|
|
PCMCIA_Timer(hWnd);
|
|
break;
|
|
|
|
case VOLUME_TIMER_ID:
|
|
Volume_Timer(hWnd);
|
|
break;
|
|
|
|
case POWER_TIMER_ID:
|
|
Power_Timer(hWnd);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
ShowWindow(hWnd, SW_HIDE);
|
|
break;
|
|
|
|
//
|
|
// Private messages
|
|
//
|
|
case STWM_ENABLESERVICE:
|
|
if (!UpdateServices(hWnd,
|
|
EnableService((UINT)wParam, (BOOL)lParam))) {
|
|
DestroyWindow(hWnd);
|
|
}
|
|
break;
|
|
|
|
case STWM_GETSTATE:
|
|
return((BOOL)(g_uEnabledSvcs & (UINT)wParam));
|
|
break;
|
|
|
|
case WM_POWERBROADCAST:
|
|
if (wParam == PBT_APMPOWERSTATUSCHANGE &&
|
|
g_uEnabledSvcs & STSERVICE_POWER) {
|
|
Power_UpdateStatus(hWnd, NIM_MODIFY, FALSE);
|
|
}
|
|
break;
|
|
|
|
case WM_DEVICECHANGE:
|
|
if (g_uEnabledSvcs & STSERVICE_PCMCIA) {
|
|
PCMCIA_DeviceChange(hWnd, wParam, lParam);
|
|
}
|
|
|
|
if (g_uEnabledSvcs & STSERVICE_VOLUME) {
|
|
Volume_DeviceChange(hWnd, wParam, lParam);
|
|
}
|
|
break;
|
|
|
|
case WM_ENDSESSION:
|
|
if (g_uEnabledSvcs & STSERVICE_VOLUME) {
|
|
Volume_Shutdown(hWnd);
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
UpdateServices(hWnd, 0); // Force all services off
|
|
PostQuitMessage(0);
|
|
break;
|
|
|
|
case WM_HELP:
|
|
WinHelp(((LPHELPINFO)lParam)->hItemHandle, NULL, HELP_WM_HELP,
|
|
(DWORD)(LPSTR)g_ContextMenuHelpIDs);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (DWORD)
|
|
(LPSTR) g_ContextMenuHelpIDs);
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hWnd, Message, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* SysTray_RunProperties
|
|
*
|
|
* DESCRIPTION:
|
|
* Loads the specified string ID and executes it.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
void SysTray_RunProperties(UINT RunStringID)
|
|
{
|
|
const TCHAR szOpen[] = TEXT ("open");
|
|
const TCHAR szRunDLL[] = TEXT ("RUNDLL32.EXE");
|
|
LPTSTR pszRunCmd = LoadDynamicString(RunStringID);
|
|
if (pszRunCmd == NULL)
|
|
return;
|
|
|
|
ShellExecute(NULL, szOpen, szRunDLL,
|
|
pszRunCmd, NULL, SW_SHOWNORMAL);
|
|
|
|
DeleteDynamicString(pszRunCmd);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* SysTray_NotifyIcon
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
* hWnd, handle of BatteryMeter window.
|
|
* Message,
|
|
* hIcon,
|
|
* lpTip,
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
PASCAL
|
|
SysTray_NotifyIcon(
|
|
HWND hWnd,
|
|
UINT uCallbackMessage,
|
|
DWORD Message,
|
|
HICON hIcon,
|
|
LPCTSTR lpTip
|
|
)
|
|
{
|
|
NOTIFYICONDATA NotifyIconData;
|
|
|
|
NotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
|
|
NotifyIconData.uID = uCallbackMessage;
|
|
NotifyIconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
|
|
NotifyIconData.uCallbackMessage = uCallbackMessage;
|
|
|
|
NotifyIconData.hWnd = hWnd;
|
|
NotifyIconData.hIcon = hIcon;
|
|
if (lpTip) {
|
|
UINT cch = ARRAYSIZE(NotifyIconData.szTip);
|
|
lstrcpyn(NotifyIconData.szTip, lpTip, cch);
|
|
} else {
|
|
NotifyIconData.szTip[0] = 0;
|
|
}
|
|
|
|
Shell_NotifyIcon(Message, &NotifyIconData);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* LoadDynamicString
|
|
*
|
|
* DESCRIPTION:
|
|
* Wrapper for the FormatMessage function that loads a string from our
|
|
* resource table into a dynamically allocated buffer, optionally filling
|
|
* it with the variable arguments passed.
|
|
*
|
|
* BE CAREFUL in 16-bit code to pass 32-bit quantities for the variable
|
|
* arguments.
|
|
*
|
|
* PARAMETERS:
|
|
* StringID, resource identifier of the string to use.
|
|
* (optional), parameters to use to format the string message.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
LPTSTR
|
|
NEAR CDECL
|
|
LoadDynamicString(
|
|
UINT StringID,
|
|
...
|
|
)
|
|
{
|
|
|
|
#if 0
|
|
// WARNING: if you undo this 'if 0', the va_ stuff will break on alpha
|
|
LPTSTR pStr;
|
|
va_list Marker = va_start(Marker, StringID);
|
|
|
|
FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
|
(LPVOID) (DWORD) g_hInstance, StringID, 0, (LPTSTR) (LPTSTR FAR *)
|
|
&pStr, 0, &Marker);
|
|
|
|
#else
|
|
|
|
TCHAR Buffer[256];
|
|
LPTSTR pStr;
|
|
va_list Marker;
|
|
|
|
// va_start is a macro...it breaks when you use it as an assign
|
|
va_start(Marker, StringID);
|
|
|
|
LoadString(g_hInstance, StringID, Buffer, sizeof(Buffer));
|
|
|
|
FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
|
(LPVOID) (LPTSTR) Buffer, 0, 0, (LPTSTR) (LPTSTR FAR *) &pStr, 0, &Marker);
|
|
|
|
#endif
|
|
|
|
return pStr;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// GenericGetSet
|
|
//
|
|
// DESCRIPTION:
|
|
// Reads or writes a registry key value. The key must already be open.
|
|
// The key will be closed after the data is read/written.
|
|
//
|
|
// PARAMETERS:
|
|
// hk - HKEY to open registry key to read/write
|
|
// lpszOptVal - value name string pointer
|
|
// lpData - pointer to data buffer to read/write
|
|
// cbSize - size of data to read/write in bytes
|
|
// bSet - FALSE if reading, TRUE if writing
|
|
//
|
|
// RETURNS:
|
|
// TRUE if successful, FALSE if not.
|
|
//
|
|
// NOTE:
|
|
// Assumes data is of type REG_BINARY or REG_DWORD when bSet = TRUE!
|
|
//
|
|
//*****************************************************************************
|
|
|
|
BOOL NEAR PASCAL GenericGetSet(HKEY hk, LPCTSTR lpszOptVal, LPVOID lpData,
|
|
ULONG cbSize, BOOL bSet)
|
|
{
|
|
DWORD rr;
|
|
|
|
if (bSet)
|
|
rr = RegSetValueEx(hk, lpszOptVal, 0, (cbSize == sizeof(DWORD)) ? REG_DWORD : REG_BINARY,
|
|
lpData, cbSize);
|
|
else
|
|
rr = RegQueryValueEx(hk, lpszOptVal, NULL, NULL, lpData, &cbSize);
|
|
|
|
RegCloseKey(hk);
|
|
return(rr == ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* UpdateRunLine
|
|
*
|
|
* DESCRIPTION:
|
|
* Adds or removes an entry to/from the registry run-at-boot section.
|
|
*
|
|
* PARAMETERS:
|
|
* fEnabled, TRUE if adding, FALSE if removing
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID PASCAL UpdateRunLine (BOOL fEnabled)
|
|
{
|
|
HKEY hkey;
|
|
LPTSTR pService = LoadDynamicString(IDS_SYSTRAYSERVICENAME);
|
|
|
|
// Open the registry key that contains the configuration info
|
|
if (RegCreateKey(HKEY_LOCAL_MACHINE, g_szRegstrPathRun, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
if (fEnabled)
|
|
{
|
|
//
|
|
// Make an entry in "run" registry key
|
|
//
|
|
LPTSTR pAppName = LoadDynamicString(IDS_SYSTRAYAPPNAME);
|
|
UINT cbSize = (lstrlen(pAppName) + 1) * sizeof (TCHAR);
|
|
RegSetValueEx(hkey, pService, 0, REG_SZ, (LPSTR)pAppName, cbSize);
|
|
DeleteDynamicString(pAppName);
|
|
}
|
|
else
|
|
{
|
|
// Remove the entry from "run" registry key
|
|
//
|
|
RegDeleteValue(hkey, pService);
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
DeleteDynamicString(pService);
|
|
}
|