2175 lines
50 KiB
2175 lines
50 KiB
/*++
|
|
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
|
|
Module Name:
|
|
|
|
wndproc.CPP
|
|
|
|
Abstract:
|
|
|
|
This is the window procedure for STI server process
|
|
|
|
Author:
|
|
|
|
Vlad Sadovsky (vlads) 12-20-96
|
|
|
|
Revision History:
|
|
|
|
20-Dec-1996 Vlads Created
|
|
28-Sep-1997 VladS Added code for SCM glue
|
|
20-May-2000 ByronC Replaced windows messaging
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// Headers
|
|
//
|
|
#include "precomp.h"
|
|
#include "stiexe.h"
|
|
#include <windowsx.h>
|
|
|
|
#include "device.h"
|
|
#include "monui.h"
|
|
#include <validate.h>
|
|
#include <apiutil.h>
|
|
|
|
#include <shellapi.h>
|
|
#include <devguid.h>
|
|
|
|
#include "wiamindr.h"
|
|
|
|
//
|
|
// Definitions
|
|
//
|
|
|
|
#define REFRESH_ASYNC 1 // Do refresh asyncronously
|
|
|
|
#define USE_WORKER_THREAD 1 // Run configuration changes on separate worker thread
|
|
|
|
#define USE_BROADCASTSYSTEM 1 // Rebroadcast device arrivals/removal
|
|
|
|
#define DEVICE_REFRESH_WAIT_TIME 30000 // Wait time in milliseconds
|
|
|
|
//
|
|
// Interval to delay refreshing device list after add new device notification received
|
|
//
|
|
#define REFRESH_DELAY 3000
|
|
#define BOOT_REFRESH_DELAY 5000
|
|
|
|
#define STI_MSG_WAIT_TIME 1
|
|
|
|
//
|
|
// External references
|
|
//
|
|
extern BOOL g_fUIPermitted;
|
|
extern DWORD g_dwCurrentState;
|
|
extern LONG g_lTotalActiveDevices;
|
|
extern LONG g_lGlobalDeviceId;
|
|
extern UINT g_uiDefaultPollTimeout;
|
|
extern HDEVNOTIFY g_hStiServiceNotificationSink ;
|
|
extern HWND g_hStiServiceWindow;
|
|
extern BOOL g_fUseServiceCtrlSink;
|
|
extern BOOL g_fFirstDevNodeChangeMsg;
|
|
|
|
//
|
|
// Global Data
|
|
//
|
|
|
|
//
|
|
// Static data
|
|
//
|
|
|
|
//
|
|
// Prototypes
|
|
//
|
|
|
|
LRESULT CALLBACK
|
|
StiExeWinProc(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
DWORD
|
|
StiWnd_OnServiceControlMessage(
|
|
HWND hwnd,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
BOOL
|
|
OnSetParameters(
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
BOOL
|
|
OnDoRefreshActiveDeviceList(
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
BOOL
|
|
OnAddNewDevice(
|
|
DEVICE_BROADCAST_INFO *psDevBroadcast
|
|
);
|
|
|
|
BOOL
|
|
OnRemoveActiveDevice(
|
|
DEVICE_BROADCAST_INFO *psDevBroadcast,
|
|
BOOL fRebroadcastRemoval
|
|
);
|
|
|
|
VOID
|
|
ConfigChangeThread(
|
|
LPVOID lpParameter
|
|
);
|
|
|
|
VOID
|
|
DebugDumpDeviceList(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
DebugPurgeDeviceList(
|
|
VOID *pContext
|
|
);
|
|
|
|
VOID
|
|
RefreshDeviceCallback(
|
|
VOID * pContext
|
|
);
|
|
|
|
DWORD
|
|
ResetSavedWindowPos(
|
|
HWND hWnd
|
|
);
|
|
|
|
DWORD
|
|
SaveWindowPos(
|
|
HWND hWnd
|
|
);
|
|
|
|
VOID
|
|
DumpDeviceChangeData(
|
|
HWND hWnd,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
VOID
|
|
StiServiceStop(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
StiServicePause(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
StiServiceResume(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
BroadcastSTIChange(
|
|
DEVICE_BROADCAST_INFO *psDevBroadcastInfo,
|
|
LPTSTR lpszStiAction
|
|
);
|
|
|
|
VOID
|
|
BroadcastSysMessageThreadProc(
|
|
VOID *pContext
|
|
);
|
|
|
|
|
|
//
|
|
// Message handlers prototypes
|
|
//
|
|
BOOL StiWnd_OnQueryEndSession(HWND hwnd);
|
|
VOID StiWnd_OnEndSession(HWND hwnd, BOOL fEnding);
|
|
|
|
int StiWnd_OnCreate(HWND hwnd,LPCREATESTRUCT lpCreateStruct);
|
|
VOID StiWnd_OnDoRefreshActiveDeviceList(WPARAM wParam,LPARAM lParam);
|
|
|
|
BOOL StiWnd_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct);
|
|
VOID StiWnd_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
|
|
|
|
VOID StiWnd_OnSize(HWND hwnd, UINT state, int cx, int cy);
|
|
VOID StiWnd_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos);
|
|
VOID StiWnd_OnVScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos);
|
|
|
|
VOID StiWnd_OnDestroy(HWND hwnd);
|
|
|
|
VOID StiWnd_OnMenuRefresh(VOID);
|
|
VOID StiWnd_OnMenuDeviceList(VOID);
|
|
VOID StiWnd_OnMenuSetTimeout(VOID);
|
|
VOID StiWnd_OnMenuRemoveAll(VOID);
|
|
|
|
|
|
|
|
//
|
|
// Utilities
|
|
//
|
|
BOOL
|
|
ParseGUID(
|
|
LPGUID pguid,
|
|
LPCTSTR ptsz
|
|
);
|
|
|
|
BOOL
|
|
IsStillImagePnPMessage(
|
|
PDEV_BROADCAST_HDR pDev
|
|
);
|
|
|
|
BOOL
|
|
GetDeviceNameFromDevNode(
|
|
DEVNODE dnDevNode,
|
|
StiCString& strDeviceName
|
|
);
|
|
|
|
//
|
|
// Code
|
|
//
|
|
|
|
VOID
|
|
WINAPI
|
|
StiMessageCallback(
|
|
VOID *pArg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine simply calls the Sti message dispatcher (aka winproc). It
|
|
is used in conjunction with StiPostMessage to replace ::PostMessage.
|
|
|
|
Arguments:
|
|
|
|
pArg - Must be of type STI_MESSAGE
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
STI_MESSAGE *pMessage = (STI_MESSAGE*)pArg;
|
|
LRESULT lRes = 0;
|
|
|
|
//
|
|
// Validate params
|
|
//
|
|
|
|
if (!pMessage) {
|
|
DBG_WRN(("::StiMessageCallback, NULL message"));
|
|
return;
|
|
}
|
|
|
|
if (IsBadReadPtr(pMessage, sizeof(STI_MESSAGE))) {
|
|
DBG_WRN(("::StiMessageCallback, Bad message"));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Call StiSvcWinProc to process the message
|
|
//
|
|
|
|
_try {
|
|
lRes = StiSvcWinProc(NULL,
|
|
pMessage->m_uMsg,
|
|
pMessage->m_wParam,
|
|
pMessage->m_lParam);
|
|
}
|
|
_finally {
|
|
pMessage = NULL;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
StiRefreshCallback(
|
|
VOID *pArg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine simply calls RefreshDeviceList.
|
|
|
|
Arguments:
|
|
|
|
pArg - Must be of type STI_MESSAGE
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
STI_MESSAGE *pMessage = (STI_MESSAGE*)pArg;
|
|
LRESULT lRes = 0;
|
|
|
|
//
|
|
// Validate params
|
|
//
|
|
|
|
if (!pMessage) {
|
|
DBG_WRN(("::StiRefreshCallback, NULL message"));
|
|
return;
|
|
}
|
|
|
|
if (IsBadReadPtr(pMessage, sizeof(STI_MESSAGE))) {
|
|
DBG_WRN(("::StiRefreshCallback, Bad message"));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Call RefreshDeviceList
|
|
//
|
|
|
|
_try {
|
|
RefreshDeviceList((WORD)pMessage->m_wParam,
|
|
(WORD)pMessage->m_lParam);
|
|
}
|
|
_finally {
|
|
pMessage = NULL;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
LRESULT
|
|
StiSendMessage(
|
|
HWND hWnd,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine replaces the normal windows messaging SendMessage by calling
|
|
the message dispatcher (StiSvcWinProc) directly. It replaces ::SendMessage.
|
|
|
|
Arguments:
|
|
|
|
hWnd - handle to destination window. This is not used.
|
|
Msg - message
|
|
wParam - first message parameter
|
|
lParam - second message parameterReturn Value:
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
--*/
|
|
{
|
|
return StiSvcWinProc(NULL, Msg, wParam, lParam);
|
|
}
|
|
|
|
BOOL
|
|
StiPostMessage(
|
|
HWND hWnd,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine simulates PostMessage by putting StiMessageCallback on the
|
|
Scheduler's queue.
|
|
|
|
Arguments:
|
|
|
|
hWnd - handle to destination window. This is not used.
|
|
Msg - message
|
|
wParam - first message parameter
|
|
lParam - second message parameterReturn Value:
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - success
|
|
FALSE - message could not be posted
|
|
|
|
--*/
|
|
{
|
|
BOOL bRet = FALSE;
|
|
STI_MESSAGE *pMsg = new STI_MESSAGE(Msg, wParam, lParam);
|
|
|
|
if (pMsg) {
|
|
|
|
if (ScheduleWorkItem((PFN_SCHED_CALLBACK) StiMessageCallback,
|
|
pMsg,
|
|
STI_MSG_WAIT_TIME,
|
|
NULL)) {
|
|
bRet = TRUE;
|
|
} else {
|
|
delete pMsg;
|
|
}
|
|
}
|
|
|
|
if (!bRet) {
|
|
DBG_WRN(("::StiPostMessage, could not post message"));
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
StiRefreshWithDelay(
|
|
ULONG ulDelay,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine simulates PostMessage by putting StiMessageCallback on the
|
|
Scheduler's queue with a delay of ulDelay.
|
|
|
|
Arguments:
|
|
|
|
ulDelay - delay in milliseconds
|
|
Msg - message
|
|
wParam - first message parameter
|
|
lParam - second message parameter
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - success
|
|
FALSE - message could not be posted
|
|
|
|
--*/
|
|
{
|
|
BOOL bRet = FALSE;
|
|
STI_MESSAGE *pMsg = new STI_MESSAGE(0, wParam, lParam);
|
|
|
|
if (pMsg) {
|
|
|
|
if (ScheduleWorkItem((PFN_SCHED_CALLBACK) StiRefreshCallback,
|
|
pMsg,
|
|
ulDelay,
|
|
NULL)) {
|
|
bRet = TRUE;
|
|
} else {
|
|
delete pMsg;
|
|
}
|
|
}
|
|
|
|
if (!bRet) {
|
|
DBG_WRN(("::StiRefreshWithDelay, could not post message"));
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
|
|
HWND
|
|
WINAPI
|
|
CreateMasterWindow(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
#ifndef WINNT
|
|
//Don't use windows messaging on NT
|
|
|
|
DBG_FN(CreateMasterWindow);
|
|
|
|
|
|
WNDCLASSEX wc;
|
|
HWND hwnd = FindWindow(g_szClass,NULL);
|
|
|
|
if (hwnd) {
|
|
|
|
//
|
|
// Notify master window that we started.
|
|
//
|
|
if (g_fUIPermitted) {
|
|
::ShowWindow(hwnd,g_fUIPermitted ? SW_SHOWNORMAL : SW_HIDE);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Create class
|
|
//
|
|
memset(&wc,0,sizeof(wc));
|
|
|
|
wc.cbSize = sizeof(WNDCLASSEX);
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = StiExeWinProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = g_hInst;
|
|
wc.hIcon = LoadIcon(NULL,MAKEINTRESOURCE(1));
|
|
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
|
|
wc.lpszClassName = g_szClass;
|
|
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
|
|
|
|
if (!RegisterClassEx(&wc))
|
|
return NULL;
|
|
|
|
#ifndef WINNT
|
|
#ifdef FE_IME
|
|
// Disable IME processing on Millenium
|
|
ImmDisableIME(::GetCurrentThreadId());
|
|
#endif
|
|
#endif
|
|
|
|
g_hMainWindow = CreateWindowEx(0, // Style bits
|
|
g_szClass, // Class name
|
|
g_szTitle, // Title
|
|
WS_OVERLAPPEDWINDOW , // Window style bits
|
|
CW_USEDEFAULT, // x
|
|
CW_USEDEFAULT, // y
|
|
CW_USEDEFAULT, // h
|
|
CW_USEDEFAULT, // w
|
|
NULL, // Parent
|
|
NULL, // Menu
|
|
g_hInst, // Module instance
|
|
NULL); // Options
|
|
|
|
if(g_hMainWindow) {
|
|
|
|
// Register custom message
|
|
g_StiFileLog->SetLogWindowHandle(g_hMainWindow);
|
|
}
|
|
|
|
DBG_ERR(("WIASERVC :: CreateMasterWindow. Handle = %X ",g_hMainWindow);
|
|
|
|
#endif
|
|
return g_hMainWindow;
|
|
}
|
|
|
|
LRESULT
|
|
CALLBACK
|
|
StiExeWinProc(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Master window callback procedure
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
switch(uMsg) {
|
|
|
|
case WM_COMMAND:
|
|
HANDLE_WM_COMMAND(hwnd, wParam, lParam, StiWnd_OnCommand);
|
|
break;
|
|
|
|
case WM_CREATE:
|
|
return HANDLE_WM_CREATE(hwnd, wParam, lParam, StiWnd_OnCreate);
|
|
break;
|
|
|
|
case STIMON_MSG_SET_PARAMETERS:
|
|
OnSetParameters(wParam,lParam);
|
|
break;
|
|
|
|
case STIMON_MSG_VISUALIZE:
|
|
{
|
|
//
|
|
// Make ourselves visible or hidden
|
|
//
|
|
BOOL fShow = (BOOL)wParam;
|
|
|
|
g_fUIPermitted = fShow;
|
|
|
|
ShowWindow(hwnd,fShow ? SW_SHOWNORMAL : SW_HIDE);
|
|
g_StiFileLog->SetReportMode(g_StiFileLog->QueryReportMode() | STI_TRACE_LOG_TOUI);
|
|
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
HANDLE_WM_DESTROY(hwnd, wParam, lParam, StiWnd_OnDestroy);
|
|
break;
|
|
|
|
case WM_ENDSESSION:
|
|
return HANDLE_WM_ENDSESSION(hwnd, wParam, lParam, StiWnd_OnEndSession);
|
|
|
|
case WM_QUERYENDSESSION:
|
|
return HANDLE_WM_QUERYENDSESSION(hwnd, wParam, lParam, StiWnd_OnQueryEndSession);
|
|
|
|
case WM_CLOSE:
|
|
DBG_TRC(("Service instance received WM_CLOSE"));
|
|
|
|
default:
|
|
return DefWindowProc(hwnd,uMsg,wParam,lParam);
|
|
|
|
}
|
|
|
|
return 0L;
|
|
|
|
} /* endproc WinProc */
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
OnSetParameters(
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
switch(wParam) {
|
|
case STIMON_MSG_SET_TIMEOUT:
|
|
return lParam ? ResetAllPollIntervals((UINT)lParam) : 0;
|
|
default:
|
|
;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
StiWnd_OnQueryEndSession(
|
|
HWND hwnd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
StiWnd_OnEndSession(
|
|
HWND hwnd,
|
|
BOOL fEnding
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
return;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
StiWnd_OnCreate(
|
|
HWND hwnd,
|
|
LPCREATESTRUCT lpCreateStruct
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
// Restore window charateristics
|
|
ResetSavedWindowPos(hwnd);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
StiWnd_OnCommand(
|
|
HWND hwnd,
|
|
int id,
|
|
HWND hwndCtl,
|
|
UINT codeNotify
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
switch (id) {
|
|
case IDM_TOOLS_DEVLIST:
|
|
StiWnd_OnMenuDeviceList();
|
|
break;
|
|
case IDM_TOOLS_REFRESH:
|
|
StiWnd_OnMenuRefresh();
|
|
break;
|
|
case IDM_TOOLS_TIMEOUT:
|
|
StiWnd_OnMenuSetTimeout();
|
|
break;
|
|
|
|
case IDM_TOOLS_REMOVEALL:
|
|
StiWnd_OnMenuRemoveAll();
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
StiWnd_OnDestroy(
|
|
HWND hwnd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DBG_TRC(("Service instance received WM_DESTROY"));
|
|
|
|
// Save current window position
|
|
SaveWindowPos(hwnd);
|
|
|
|
// Main window is going away.
|
|
PostQuitMessage(0);
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Menu verb handlers
|
|
//
|
|
|
|
VOID
|
|
WINAPI
|
|
StiWnd_OnMenuRefresh(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
STIMONWPRINTF(TEXT("Menu: Refreshing device list "));
|
|
|
|
OnDoRefreshActiveDeviceList(STIMON_MSG_REFRESH_REREAD,
|
|
STIMON_MSG_REFRESH_NEW | STIMON_MSG_REFRESH_EXISTING
|
|
);
|
|
|
|
STIMONWPRINTF(TEXT("Done refreshing device list. Active device count:%d Current device id:%d "),
|
|
g_lTotalActiveDevices,g_lGlobalDeviceId);
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
StiWnd_OnMenuDeviceList(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
STIMONWPRINTF(TEXT("Menu: Displaying device list "));
|
|
|
|
DebugDumpDeviceList();
|
|
|
|
STIMONWPRINTF(TEXT("Active device count:%d Current device id:%d "),
|
|
g_lTotalActiveDevices,g_lGlobalDeviceId);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
StiWnd_OnMenuRemoveAll(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
STIMONWPRINTF(TEXT("Menu: removing all devices "));
|
|
|
|
#ifdef USE_WORKER_THREAD
|
|
|
|
HANDLE hThread;
|
|
DWORD dwThread;
|
|
|
|
hThread = ::CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)DebugPurgeDeviceList,
|
|
(LPVOID)0,
|
|
0,
|
|
&dwThread);
|
|
|
|
if ( hThread )
|
|
CloseHandle(hThread);
|
|
|
|
|
|
#else
|
|
//
|
|
// Try to schedule refresh work item
|
|
//
|
|
DWORD dwSchedulerCookie = ::ScheduleWorkItem(
|
|
(PFN_SCHED_CALLBACK) DebugPurgeDeviceList,
|
|
(LPVOID)0,
|
|
10);
|
|
|
|
if ( !dwSchedulerCookie ){
|
|
ASSERT(("Refresh routine could not schedule work item", 0));
|
|
|
|
STIMONWPRINTF(TEXT("Could not schedule asyncronous removal"));
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
StiWnd_OnMenuSetTimeout(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
CSetTimeout cdlg(IDD_SETTIMEOUT,::GetActiveWindow(),NULL,g_uiDefaultPollTimeout);
|
|
|
|
if ( (cdlg.CreateModal() == IDOK) && (cdlg.m_fValidChange) ) {
|
|
|
|
g_uiDefaultPollTimeout = cdlg.GetNewTimeout();
|
|
|
|
if (cdlg.IsAllChange()) {
|
|
// Update all devices
|
|
ResetAllPollIntervals(g_uiDefaultPollTimeout);
|
|
}
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
ResetSavedWindowPos(
|
|
HWND hwnd
|
|
)
|
|
/*++
|
|
Loads the window position structure from registry and resets
|
|
|
|
Returns:
|
|
Win32 error code. NO_ERROR on success
|
|
|
|
--*/
|
|
{
|
|
DWORD dwError = NO_ERROR;
|
|
BUFFER buf;
|
|
|
|
RegEntry re(REGSTR_PATH_STICONTROL,HKEY_LOCAL_MACHINE);
|
|
|
|
re.GetValue(REGSTR_VAL_DEBUG_STIMONUIWIN,&buf);
|
|
|
|
if (buf.QuerySize() >= sizeof(WINDOWPLACEMENT) ) {
|
|
|
|
WINDOWPLACEMENT *pWinPos = (WINDOWPLACEMENT *)buf.QueryPtr();
|
|
|
|
//
|
|
// Command line and registry settings override last saved parameters
|
|
//
|
|
pWinPos->showCmd = g_fUIPermitted ? SW_SHOWNORMAL : SW_HIDE;
|
|
|
|
dwError = ::SetWindowPlacement(hwnd,(WINDOWPLACEMENT *)buf.QueryPtr());
|
|
}
|
|
else {
|
|
::ShowWindow(hwnd,g_fUIPermitted ? SW_SHOWNORMAL : SW_HIDE);
|
|
}
|
|
|
|
return dwError;
|
|
|
|
} //
|
|
|
|
DWORD
|
|
WINAPI
|
|
SaveWindowPos(
|
|
HWND hwnd
|
|
)
|
|
/*++
|
|
Loads the window position structure from registry and resets
|
|
|
|
Returns:
|
|
Win32 error code. NO_ERROR on success
|
|
|
|
--*/
|
|
{
|
|
DWORD dwError = NO_ERROR;
|
|
BUFFER buf(sizeof(WINDOWPLACEMENT));
|
|
|
|
if (buf.QuerySize() >= sizeof(WINDOWPLACEMENT) ) {
|
|
|
|
WINDOWPLACEMENT *pWinPos = (WINDOWPLACEMENT *)buf.QueryPtr();
|
|
|
|
pWinPos->length = sizeof(WINDOWPLACEMENT);
|
|
dwError = ::GetWindowPlacement(hwnd,(WINDOWPLACEMENT *)buf.QueryPtr());
|
|
|
|
RegEntry re(REGSTR_PATH_STICONTROL,HKEY_LOCAL_MACHINE);
|
|
|
|
dwError = re.SetValue(REGSTR_VAL_DEBUG_STIMONUIWIN,(unsigned char *)buf.QueryPtr(),buf.QuerySize());
|
|
}
|
|
else {
|
|
dwError = ::GetLastError();
|
|
}
|
|
|
|
return dwError;
|
|
|
|
} //
|
|
|
|
//
|
|
// Window procedure and handlers for service hidden window
|
|
//
|
|
LRESULT
|
|
WINAPI
|
|
CALLBACK
|
|
StiSvcWinProc(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
STI service hidden window. Used for queuing actions and receiving
|
|
PnP notifications and Power broadcasts
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBG_FN(StiSvcWinProc);
|
|
|
|
PDEVICE_BROADCAST_INFO pBufDevice;
|
|
|
|
LRESULT lRet = NOERROR;
|
|
|
|
DBG_TRC(("Came to Service Window proc .uMsg=%X wParam=%X lParam=%X",uMsg,wParam,lParam));
|
|
|
|
//
|
|
// Give WIA a chance at processing messages. Note that
|
|
// WIA hooks both message dispatch and the window proc. so that
|
|
// both posted and sent messages can be detected.
|
|
//
|
|
if (ProcessWiaMsg(hwnd, uMsg, wParam, lParam) == S_OK) {
|
|
return 0;
|
|
}
|
|
|
|
switch(uMsg) {
|
|
|
|
case WM_CREATE:
|
|
{
|
|
|
|
#ifdef WINNT
|
|
/*
|
|
//*
|
|
//* REMOVE all instances where we register for PnP events using window Handle on NT
|
|
//*
|
|
|
|
if (!g_fUseServiceCtrlSink || !g_hStiServiceNotificationSink) {
|
|
|
|
DEV_BROADCAST_HDR *psh;
|
|
DEV_BROADCAST_DEVICEINTERFACE sNotificationFilter;
|
|
DWORD dwError;
|
|
|
|
//
|
|
// Register to receive device notifications from PnP
|
|
//
|
|
|
|
psh = (DEV_BROADCAST_HDR *)&sNotificationFilter;
|
|
|
|
psh->dbch_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
|
|
psh->dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
|
psh->dbch_reserved = 0;
|
|
|
|
sNotificationFilter.dbcc_classguid = *g_pguidDeviceNotificationsGuid;
|
|
|
|
CopyMemory(&sNotificationFilter.dbcc_classguid,g_pguidDeviceNotificationsGuid,sizeof(GUID));
|
|
|
|
sNotificationFilter.dbcc_name[0] = 0x0;
|
|
|
|
DPRINTF(DM_TRACE, TEXT("Attempting to register with PnP"));
|
|
|
|
g_hStiServiceNotificationSink =
|
|
RegisterDeviceNotification(hwnd,
|
|
(LPVOID)&sNotificationFilter,
|
|
DEVICE_NOTIFY_WINDOW_HANDLE);
|
|
dwError = GetLastError();
|
|
if( !g_hStiServiceNotificationSink && (NOERROR != dwError)) {
|
|
//
|
|
// Failed to create notification sink with PnP subsystem
|
|
//
|
|
// ASSERT
|
|
StiLogTrace(STI_TRACE_ERROR,TEXT("Failed to register with PnP ErrorCode =%d"),dwError);
|
|
}
|
|
|
|
DPRINTF(DM_WARNING ,TEXT("Done register with PnP"));
|
|
|
|
}
|
|
*/
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
case STIMON_MSG_REFRESH:
|
|
OnDoRefreshActiveDeviceList(wParam,lParam);
|
|
break;
|
|
|
|
case STIMON_MSG_REMOVE_DEVICE:
|
|
pBufDevice = (PDEVICE_BROADCAST_INFO )lParam;
|
|
//
|
|
// wParam value indicates whether device removal should be rebroadcasted
|
|
//
|
|
if (pBufDevice) {
|
|
|
|
lRet = OnRemoveActiveDevice(pBufDevice,(BOOL)wParam) ? NOERROR : (LRESULT) ::GetLastError();
|
|
|
|
delete pBufDevice;
|
|
}
|
|
break;
|
|
|
|
case STIMON_MSG_ADD_DEVICE:
|
|
pBufDevice = (PDEVICE_BROADCAST_INFO )lParam;
|
|
//
|
|
// New device arrived
|
|
//
|
|
if (pBufDevice) {
|
|
lRet = OnAddNewDevice(pBufDevice)? NOERROR : (LRESULT) ::GetLastError();
|
|
delete pBufDevice;
|
|
}
|
|
break;
|
|
|
|
case WM_DEVICECHANGE:
|
|
|
|
DumpDeviceChangeData(hwnd,wParam,lParam);
|
|
return (StiWnd_OnDeviceChangeMessage(hwnd,(UINT)wParam,lParam));
|
|
break;
|
|
|
|
case WM_POWERBROADCAST:
|
|
return (StiWnd_OnPowerControlMessage(hwnd,(DWORD)wParam,lParam));
|
|
|
|
default:
|
|
return DefWindowProc(hwnd,uMsg,wParam,lParam);
|
|
|
|
}
|
|
|
|
return lRet;
|
|
|
|
} // endproc WinProc
|
|
|
|
DWORD
|
|
WINAPI
|
|
StiWnd_OnPowerControlMessage(
|
|
HWND hwnd,
|
|
DWORD dwPowerEvent,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process power management broadcast messages .
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DBG_FN(StiWnd_OnPowerControlMessage);
|
|
|
|
DWORD dwRet = NO_ERROR;
|
|
UINT uiTraceMessage = 0;
|
|
|
|
#ifdef DEBUG
|
|
static LPCTSTR pszPwrEventNames[] = {
|
|
TEXT("PBT_APMQUERYSUSPEND"), // 0x0000
|
|
TEXT("PBT_APMQUERYSTANDBY"), // 0x0001
|
|
TEXT("PBT_APMQUERYSUSPENDFAILED"), // 0x0002
|
|
TEXT("PBT_APMQUERYSTANDBYFAILED"), // 0x0003
|
|
TEXT("PBT_APMSUSPEND"), // 0x0004
|
|
TEXT("PBT_APMSTANDBY"), // 0x0005
|
|
TEXT("PBT_APMRESUMECRITICAL"), // 0x0006
|
|
TEXT("PBT_APMRESUMESUSPEND"), // 0x0007
|
|
TEXT("PBT_APMRESUMESTANDBY"), // 0x0008
|
|
// TEXT(" PBTF_APMRESUMEFROMFAILURE"), // 0x00000001
|
|
TEXT("PBT_APMBATTERYLOW"), // 0x0009
|
|
TEXT("PBT_APMPOWERSTATUSCHANGE"), // 0x000A
|
|
TEXT("PBT_APMOEMEVENT"), // 0x000B
|
|
TEXT("PBT_UNKNOWN"), // 0x000C
|
|
TEXT("PBT_UNKNOWN"), // 0x000D
|
|
TEXT("PBT_UNKNOWN"), // 0x000E
|
|
TEXT("PBT_UNKNOWN"), // 0x000F
|
|
TEXT("PBT_UNKNOWN"), // 0x0010
|
|
TEXT("PBT_UNKNOWN"), // 0x0011
|
|
TEXT("PBT_APMRESUMEAUTOMATIC"), // 0x0012
|
|
};
|
|
|
|
// UINT uiMsgIndex;
|
|
//
|
|
// uiMsgIndex = (dwPowerEvent < (sizeof(pszPwrEventNames) / sizeof(CHAR *) )) ?
|
|
// (UINT) dwPowerEvent : 0x0010;
|
|
|
|
DBG_TRC(("Still image APM Broadcast Message:%S Code:%x ",
|
|
pszPwrEventNames[dwPowerEvent],dwPowerEvent));
|
|
|
|
#endif
|
|
|
|
switch(dwPowerEvent)
|
|
{
|
|
case PBT_APMQUERYSUSPEND:
|
|
//
|
|
// Request for permission to suspend
|
|
//
|
|
if(g_NumberOfActiveTransfers > 0) {
|
|
|
|
//
|
|
// Veto suspend while any transfers are in progress
|
|
//
|
|
return BROADCAST_QUERY_DENY;
|
|
}
|
|
|
|
SchedulerSetPauseState(TRUE);
|
|
dwRet = TRUE;
|
|
break;
|
|
|
|
case PBT_APMQUERYSUSPENDFAILED:
|
|
//
|
|
// Suspension request denied - do nothing
|
|
//
|
|
SchedulerSetPauseState(FALSE);
|
|
break;
|
|
|
|
case PBT_APMSUSPEND:
|
|
StiServicePause();
|
|
uiTraceMessage = MSG_TRACE_PWR_SUSPEND;
|
|
|
|
break;
|
|
|
|
case PBT_APMRESUMECRITICAL:
|
|
// Operation resuming after critical suspension
|
|
// Fall through
|
|
|
|
case PBT_APMRESUMESUSPEND:
|
|
//
|
|
// Operation resuming after suspension
|
|
// Restart all services which were active at the moment of suspend
|
|
//
|
|
StiServiceResume();
|
|
uiTraceMessage = MSG_TRACE_PWR_RESUME;
|
|
g_fFirstDevNodeChangeMsg = TRUE;
|
|
break;
|
|
|
|
default:
|
|
dwRet = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return (dwRet == NOERROR) ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
LRESULT
|
|
WINAPI
|
|
StiWnd_OnDeviceChangeMessage(
|
|
HWND hwnd,
|
|
UINT DeviceEvent,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DBG_FN(StiWnd_OnDeviceChangeMessage);
|
|
|
|
//DWORD dwRet = NO_ERROR;
|
|
LRESULT lRet = NOERROR;
|
|
|
|
PDEV_BROADCAST_HDR pDev = (PDEV_BROADCAST_HDR)lParam;
|
|
DEVICE_BROADCAST_INFO *pBufDevice;
|
|
|
|
static LPCTSTR pszDBTEventNames[] = {
|
|
TEXT("DBT_DEVICEARRIVAL"), // 0x8000
|
|
TEXT("DBT_DEVICEQUERYREMOVE"), // 0x8001
|
|
TEXT("DBT_DEVICEQUERYREMOVEFAILED"), // 0x8002
|
|
TEXT("DBT_DEVICEREMOVEPENDING"), // 0x8003
|
|
TEXT("DBT_DEVICEREMOVECOMPLETE"), // 0x8004
|
|
TEXT("DBT_DEVICETYPESPECIFIC"), // 0x8005
|
|
};
|
|
BOOL fLocatedDeviceInstance = FALSE;
|
|
BOOL fNeedReenumerateDeviceList = FALSE;
|
|
|
|
//
|
|
// If the DeviceEvent is DBT_DEVNODES_CHANGED, then lParam will be NULL,
|
|
// so skip devnode processing.
|
|
//
|
|
|
|
if ((DeviceEvent != DBT_DEVNODES_CHANGED) &&
|
|
(DeviceEvent != DBT_DEVICEARRIVAL)) {
|
|
|
|
//
|
|
// Determine if message is for us
|
|
//
|
|
if (IsBadReadPtr(pDev,sizeof(PDEV_BROADCAST_HDR))) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Trace that we are here. For all messages, not intended for StillImage devices , we should refresh
|
|
// device list if we are running on WIndows NT and registered for device interfaces other than StillImage
|
|
//
|
|
|
|
PDEV_BROADCAST_DEVNODE pDevNode = (PDEV_BROADCAST_DEVNODE)lParam;
|
|
PDEV_BROADCAST_DEVICEINTERFACE pDevInterface = (PDEV_BROADCAST_DEVICEINTERFACE)pDev;
|
|
|
|
if (IsStillImagePnPMessage(pDev)) {
|
|
|
|
DBG_TRC(("Still image Device/DevNode PnP Message:%S Type:%x DevNode:%x ",
|
|
((DeviceEvent>=0x8000) && (DeviceEvent<=0x8005) ?
|
|
pszDBTEventNames[DeviceEvent-0x8000] : TEXT("Unknown DBT message"),
|
|
pDev->dbch_devicetype,
|
|
pDevNode->dbcd_devnode)));
|
|
|
|
//
|
|
// Update device info set if necessary
|
|
//
|
|
if (g_pDeviceInfoSet) {
|
|
if (DeviceEvent == DBT_DEVICEARRIVAL) {
|
|
g_pDeviceInfoSet->ProcessNewDeviceChangeMessage(lParam);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get device name and store along with the broadacast structure
|
|
//
|
|
|
|
pBufDevice = new DEVICE_BROADCAST_INFO;
|
|
if (!pBufDevice) {
|
|
::SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Fill in information we have
|
|
//
|
|
pBufDevice->m_uiDeviceChangeMessage = DeviceEvent;
|
|
pBufDevice->m_strBroadcastedName.CopyString(pDevInterface->dbcc_name) ;
|
|
pBufDevice->m_dwDevNode = pDevNode->dbcd_devnode;
|
|
|
|
fLocatedDeviceInstance = FALSE;
|
|
|
|
fLocatedDeviceInstance = GetDeviceNameFromDevBroadcast((DEV_BROADCAST_HEADER *)pDev,pBufDevice);
|
|
|
|
if (fLocatedDeviceInstance) {
|
|
DBG_TRC(("DEVICECHANGE: Device (%S) ",(LPCTSTR)pBufDevice->m_strDeviceName));
|
|
}
|
|
else {
|
|
DBG_TRC(("DEVICECHANGE: Device - failed to get device name from broadcast"));
|
|
}
|
|
|
|
//
|
|
// We don't need broadcast information if device instance had not been found
|
|
//
|
|
if (!fLocatedDeviceInstance) {
|
|
delete pBufDevice;
|
|
pBufDevice = NULL;
|
|
}
|
|
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Not ours , but we are watching it - send refresh message to reread device list.
|
|
//
|
|
if (IsPlatformNT() ) {
|
|
fNeedReenumerateDeviceList = TRUE;
|
|
}
|
|
} // endif IsStillImageDevNode
|
|
}
|
|
|
|
//
|
|
// Process device event
|
|
//
|
|
|
|
lRet = NOERROR;
|
|
|
|
switch(DeviceEvent)
|
|
{
|
|
case DBT_DEVICEARRIVAL:
|
|
|
|
/*
|
|
if (fLocatedDeviceInstance && pBufDevice) {
|
|
|
|
PostMessage(hwnd,STIMON_MSG_ADD_DEVICE,1,(LPARAM)pBufDevice);
|
|
}
|
|
else {
|
|
//
|
|
// Just refresh active list
|
|
//
|
|
fNeedReenumerateDeviceList = TRUE;
|
|
|
|
//
|
|
//::PostMessage(g_hStiServiceWindow,
|
|
// STIMON_MSG_REFRESH,
|
|
// STIMON_MSG_REFRESH_REREAD,
|
|
// STIMON_MSG_REFRESH_NEW
|
|
// );
|
|
}
|
|
*/
|
|
g_pDevMan->ProcessDeviceArrival();
|
|
|
|
break;
|
|
|
|
case DBT_DEVICEQUERYREMOVE:
|
|
|
|
if ( fLocatedDeviceInstance && (pDev->dbch_devicetype == DBT_DEVTYP_HANDLE )) {
|
|
//
|
|
// This is targeted query - remove. We should disable PnP and device notifications and
|
|
// close interface handle immediately and then wait for remove - complete.
|
|
//
|
|
// NOTE: We always close and remove the device here, since it's the safest. If
|
|
// we wait till REMOVECOMPLETE, it may be too late.
|
|
//
|
|
#ifdef USE_POST_FORPNP
|
|
PostMessage(hwnd,STIMON_MSG_REMOVE_DEVICE,1,(LPARAM)pBufDevice);
|
|
#else
|
|
lRet = ::SendMessage(hwnd,STIMON_MSG_REMOVE_DEVICE,1,(LPARAM)pBufDevice);
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
|
|
case DBT_DEVICEQUERYREMOVEFAILED:
|
|
|
|
if ( fLocatedDeviceInstance && (pDev->dbch_devicetype == DBT_DEVTYP_HANDLE )) {
|
|
//
|
|
// This is targeted query - remove - failed. We should reenable PnP notifications
|
|
//
|
|
// BUGBUG For now nothing to do as device is gone .
|
|
}
|
|
|
|
break;
|
|
|
|
case DBT_DEVICEREMOVEPENDING:
|
|
|
|
if (fLocatedDeviceInstance) {
|
|
|
|
//
|
|
// Added here for NT, as REMOVECOMPLETE comes too late
|
|
//
|
|
#ifdef USE_POST_FORPNP
|
|
PostMessage(hwnd,STIMON_MSG_REMOVE_DEVICE,1,(LPARAM)pBufDevice);
|
|
#else
|
|
lRet = ::SendMessage(hwnd,STIMON_MSG_REMOVE_DEVICE,1,(LPARAM)pBufDevice);
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
|
|
case DBT_DEVICEREMOVECOMPLETE:
|
|
|
|
//
|
|
// For Windows 9x we can immediately remove device , as we don't have handle based
|
|
// notifications.
|
|
// On NT we should do that for handle based notifications only
|
|
//
|
|
|
|
fNeedReenumerateDeviceList = TRUE;
|
|
|
|
if ( fLocatedDeviceInstance &&
|
|
( (pDev->dbch_devicetype == DBT_DEVTYP_HANDLE ) ||
|
|
(pDev->dbch_devicetype == DBT_DEVTYP_DEVNODE )
|
|
)
|
|
) {
|
|
//
|
|
// We 've got targeted remove complete - get rid of device structures
|
|
//
|
|
if ( fLocatedDeviceInstance ) {
|
|
//
|
|
// Immediately remove device, as PnP counts handles and expects everyting
|
|
// to be cleaned up when this message handler returns.
|
|
//
|
|
lRet = ::SendMessage(hwnd,STIMON_MSG_REMOVE_DEVICE,FALSE,(LPARAM)pBufDevice);
|
|
|
|
fNeedReenumerateDeviceList = FALSE;
|
|
|
|
}
|
|
else {
|
|
//
|
|
// Bad thing happened - we really need to have active device when receiving notifications for it
|
|
//
|
|
ASSERT(("WM_DEVICECHANGE/REMOVE_COMPLETE/HANDLE No device found", 0));
|
|
}
|
|
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Update info set as device is really destroyed now .
|
|
//
|
|
if (g_pDeviceInfoSet) {
|
|
g_pDeviceInfoSet->ProcessDeleteDeviceChangeMessage(lParam);
|
|
}
|
|
|
|
fNeedReenumerateDeviceList = TRUE;
|
|
|
|
}
|
|
break;
|
|
|
|
case DBT_DEVICETYPESPECIFIC:
|
|
break;
|
|
|
|
case DBT_DEVNODES_CHANGED:
|
|
if (g_fFirstDevNodeChangeMsg) {
|
|
//
|
|
// DevNodes have been modified in some way, so safest thing
|
|
// is to refresh the device list
|
|
//
|
|
|
|
fNeedReenumerateDeviceList = TRUE;
|
|
//
|
|
// Set flag to indicate that the first devnode change message
|
|
// after returning from standby has been handled
|
|
//
|
|
g_fFirstDevNodeChangeMsg = FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
lRet = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( fNeedReenumerateDeviceList ) {
|
|
//
|
|
// Purge the whole list , as this is the most reliable way to eliminate inactive devices
|
|
// Broadcast device removal here, as only now we know for sure device is gone.
|
|
//
|
|
|
|
// Nb: when we get this message, PnP on NT won't give us device name , thus reenumeration
|
|
// is required to clean up
|
|
//
|
|
::PostMessage(g_hStiServiceWindow,
|
|
STIMON_MSG_REFRESH,
|
|
STIMON_MSG_REFRESH_REREAD,
|
|
STIMON_MSG_PURGE_REMOVED | STIMON_MSG_REFRESH_NEW );
|
|
}
|
|
|
|
|
|
|
|
return (lRet == NOERROR) ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Guard to avoid reentrance in refresh routine
|
|
//
|
|
static LONG lInRefresh = 0L;
|
|
|
|
BOOL
|
|
OnDoRefreshActiveDeviceList(
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DBG_FN(OnDoRefreshActiveDeviceList);
|
|
|
|
DWORD dwParameter = MAKELONG(wParam,lParam);
|
|
|
|
#ifdef REFRESH_ASYNC
|
|
|
|
#ifdef USE_WORKER_THREAD
|
|
|
|
|
|
HANDLE hThread;
|
|
DWORD dwThread;
|
|
|
|
hThread = ::CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)ConfigChangeThread,
|
|
(LPVOID)ULongToPtr(dwParameter),
|
|
0,
|
|
&dwThread);
|
|
|
|
if ( hThread )
|
|
CloseHandle(hThread);
|
|
|
|
#else
|
|
|
|
//
|
|
// Try to schedule refresh work item.
|
|
// This code will not work in case of suspending, because processing work items is stopped
|
|
//
|
|
ASSERT(("Suspending should not call schedule work item routine",
|
|
(wParam == STIMON_MSG_REFRESH_SUSPEND)));
|
|
|
|
DWORD dwSchedulerCookie = ::ScheduleWorkItem(
|
|
(PFN_SCHED_CALLBACK) ConfigChangeThread,
|
|
(LPVOID)dwParameter,
|
|
REFRESH_DELAY );
|
|
|
|
if ( dwSchedulerCookie ){
|
|
}
|
|
else {
|
|
ASSERT(("Refresh routine could not schedule work item", 0));
|
|
|
|
::WaitAndYield(::GetCurrentProcess(), REFRESH_DELAY);
|
|
RefreshDeviceList(wParam,(WORD)lParam);
|
|
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
|
|
if (InterlockedExchange(&lInRefresh,1L)) {
|
|
return 0;
|
|
}
|
|
|
|
ConfigChangeThread((LPVOID)dwParameter);
|
|
|
|
InterlockedExchange(&lInRefresh,0L);
|
|
|
|
#endif
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
VOID
|
|
ConfigChangeThread(
|
|
LPVOID lpParameter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG ulParam = PtrToUlong(lpParameter);
|
|
|
|
WORD wCommand = LOWORD(ulParam);
|
|
WORD wFlags = HIWORD(ulParam);
|
|
DWORD dwWait = 0;
|
|
|
|
DBG_FN(ConfigChangeThread);
|
|
|
|
#ifdef DELAY_ON_BOOT
|
|
|
|
STIMONWPRINTF(TEXT("Refreshing device list. Command:%d Flags :%x"),wCommand,wFlags);
|
|
|
|
//
|
|
// On boot refresh - delay updating device list , to keep some devices happy
|
|
//
|
|
if (wFlags & STIMON_MSG_BOOT ) {
|
|
|
|
DBG_TRC(("Delaying refresh on boot "));
|
|
::Sleep(BOOT_REFRESH_DELAY);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Wait for any pending refreshes to happen first. Only do the refresh once the other
|
|
// has completed.
|
|
// NOTE: For now, we always do the refresh - maybe we should skip if we timeout?
|
|
// One exception is if this is the first device enumeration (indicated by STIMON_MSG_BOOT)
|
|
// In this case, set the event so we don't timeout (the event is created unsignalled
|
|
// so WIA clients will wait on it).
|
|
//
|
|
|
|
|
|
if (!(wFlags & STIMON_MSG_BOOT)) {
|
|
dwWait = WaitForSingleObject(g_hDevListCompleteEvent, DEVICE_REFRESH_WAIT_TIME);
|
|
if (dwWait == WAIT_TIMEOUT) {
|
|
DBG_WRN(("::ConfigChangeThread, timed out while waiting for device list enumeration..."));
|
|
}
|
|
}
|
|
RefreshDeviceList(wCommand,wFlags);
|
|
|
|
//
|
|
// Update service status when necessary. If we are going to suspend - now it's time
|
|
// to let SCM know we are paused. Note, that it might be not only result of power management
|
|
// operation, but service pausing for any other reason.
|
|
//
|
|
if ( wCommand == STIMON_MSG_REFRESH_SUSPEND) {
|
|
// BUGBUG Service status should be updated only after everything paused
|
|
UpdateServiceStatus(SERVICE_PAUSED,NOERROR,0);
|
|
}
|
|
|
|
}
|
|
|
|
BOOL
|
|
OnAddNewDevice(
|
|
DEVICE_BROADCAST_INFO *psDevBroadcastInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
BOOL fRet;
|
|
|
|
fRet = (psDevBroadcastInfo != NULL) && (psDevBroadcastInfo->m_strDeviceName.GetLength() > 0);
|
|
|
|
if (fRet) {
|
|
|
|
//
|
|
// Create new device and add to the monitored list
|
|
//
|
|
DBG_TRC(("New device (%S) is being added to the list after PnP event",(LPCTSTR)psDevBroadcastInfo->m_strDeviceName));
|
|
|
|
fRet = AddDeviceByName((LPCTSTR)psDevBroadcastInfo->m_strDeviceName,TRUE);
|
|
|
|
// If device successfully recognized - broadcast it's appearance
|
|
if (fRet) {
|
|
|
|
BroadcastSTIChange(psDevBroadcastInfo,TEXT("STI\\Arrival\\"));
|
|
}
|
|
|
|
//
|
|
// Send delayed refresh message to pick up registry changes, happening in parallel
|
|
//
|
|
//
|
|
::PostMessage(g_hStiServiceWindow,
|
|
STIMON_MSG_REFRESH,
|
|
STIMON_MSG_REFRESH_REREAD,
|
|
STIMON_MSG_REFRESH_EXISTING | STIMON_MSG_REFRESH_NEW
|
|
);
|
|
|
|
//
|
|
// Fire the WIA device arrival event
|
|
//
|
|
|
|
if (psDevBroadcastInfo) {
|
|
|
|
// DBG_TRC(("WIA FIRE OnAddNewDevice : for device "));
|
|
//
|
|
// NotifyWiaDeviceEvent(T2W((LPTSTR)(LPCTSTR)psDevBroadcastInfo->m_strDeviceName),
|
|
// &WIA_EVENT_DEVICE_CONNECTED,
|
|
// NULL,
|
|
// 0,
|
|
// g_dwMessagePumpThreadId);
|
|
}
|
|
}
|
|
else {
|
|
DBG_ERR(("DevNode appears to be invalid, could not locate name"));
|
|
|
|
#ifdef WINNT
|
|
//
|
|
// Temporarily for NT make refresh , looking for new devices
|
|
//
|
|
::PostMessage(g_hStiServiceWindow,
|
|
STIMON_MSG_REFRESH,
|
|
STIMON_MSG_REFRESH_REREAD,
|
|
STIMON_MSG_REFRESH_NEW
|
|
);
|
|
#endif
|
|
|
|
}
|
|
|
|
return fRet;
|
|
|
|
}
|
|
|
|
BOOL
|
|
OnRemoveActiveDevice(
|
|
DEVICE_BROADCAST_INFO *psDevBroadcastInfo,
|
|
BOOL fRebroadcastRemoval
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DBG_FN(OnRemoveActiveDevice);
|
|
|
|
USES_CONVERSION;
|
|
|
|
BOOL fRet;
|
|
|
|
fRet = (psDevBroadcastInfo != NULL) && (psDevBroadcastInfo->m_strDeviceName.GetLength() > 0);
|
|
|
|
DBG_TRC(("OnRemoveActiveDevice : Entering for device (%S) ",
|
|
fRet ? (LPCTSTR)psDevBroadcastInfo->m_strDeviceName : TEXT("<Invalid>")));
|
|
|
|
if (fRet) {
|
|
|
|
if (fRebroadcastRemoval) {
|
|
BroadcastSTIChange(psDevBroadcastInfo,TEXT("STI\\Removal\\"));
|
|
}
|
|
|
|
DBG_TRC(("Device (%S) is being removed after PnP event",(LPCTSTR)psDevBroadcastInfo->m_strDeviceName));
|
|
|
|
//
|
|
// Mark the device as being removed
|
|
//
|
|
|
|
MarkDeviceForRemoval((LPTSTR)(LPCTSTR)psDevBroadcastInfo->m_strDeviceName);
|
|
|
|
//
|
|
// Fire the WIA device removal event
|
|
//
|
|
|
|
if (psDevBroadcastInfo) {
|
|
|
|
DBG_TRC(("WIA FIRE OnRemoveActiveDevice : for device %S", psDevBroadcastInfo->m_strDeviceName));
|
|
|
|
NotifyWiaDeviceEvent((LPWSTR)T2W((LPTSTR)(LPCTSTR)psDevBroadcastInfo->m_strDeviceName),
|
|
&WIA_EVENT_DEVICE_DISCONNECTED,
|
|
NULL,
|
|
0,
|
|
g_dwMessagePumpThreadId);
|
|
}
|
|
|
|
fRet = RemoveDeviceByName((LPTSTR)(LPCTSTR)psDevBroadcastInfo->m_strDeviceName);
|
|
}
|
|
else {
|
|
|
|
DBG_ERR(("DevNode appears to be invalid, could not locate name"));
|
|
|
|
#ifdef WINNT
|
|
//
|
|
// Temporarily for NT make refresh , looking for new devices
|
|
//
|
|
::PostMessage(g_hStiServiceWindow,
|
|
STIMON_MSG_REFRESH,
|
|
STIMON_MSG_REFRESH_REREAD,
|
|
STIMON_MSG_REFRESH_EXISTING | STIMON_MSG_REFRESH_NEW
|
|
);
|
|
#endif
|
|
|
|
}
|
|
|
|
return fRet;
|
|
|
|
}
|
|
|
|
VOID
|
|
BroadcastSTIChange(
|
|
DEVICE_BROADCAST_INFO *psDevBroadcastInfo,
|
|
LPTSTR lpszStiAction
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Rebroadcasts STI specific device change message.
|
|
This is done so that STI client applications have a way to update their
|
|
device information without resorting to complicated PnP mechanism .
|
|
|
|
Device name and action is broadcasted
|
|
|
|
Arguments:
|
|
|
|
psDevBroadcastInfo - structure describing broadcast
|
|
lpszStiAction - string , encoding action, performed on a device
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
USES_CONVERSION;
|
|
|
|
#ifdef USE_BROADCASTSYSTEM
|
|
|
|
DBG_FN(BroadcastSTIChange);
|
|
|
|
struct _DEV_BROADCAST_USERDEFINED *pBroadcastHeader;
|
|
|
|
StiCString strDeviceAnnouncement;
|
|
|
|
PBYTE pBroadcastString = NULL;
|
|
UINT uiBroadcastBufSize;
|
|
|
|
HANDLE hThread;
|
|
DWORD dwThread;
|
|
|
|
strDeviceAnnouncement.CopyString(lpszStiAction);
|
|
strDeviceAnnouncement+=psDevBroadcastInfo->m_strDeviceName;
|
|
|
|
uiBroadcastBufSize = sizeof(*pBroadcastHeader) + strDeviceAnnouncement.GetAllocLength();
|
|
pBroadcastString = new BYTE[uiBroadcastBufSize];
|
|
|
|
pBroadcastHeader =(struct _DEV_BROADCAST_USERDEFINED *)pBroadcastString;
|
|
|
|
if (pBroadcastHeader) {
|
|
|
|
pBroadcastHeader->dbud_dbh.dbch_reserved = 0;
|
|
pBroadcastHeader->dbud_dbh.dbch_devicetype = DBT_DEVTYP_OEM;
|
|
|
|
lstrcpyA(pBroadcastHeader->dbud_szName,T2A((LPTSTR)(LPCTSTR)strDeviceAnnouncement));
|
|
|
|
pBroadcastHeader->dbud_dbh.dbch_size = uiBroadcastBufSize;
|
|
|
|
DBG_TRC(("Broadcasting STI device (%S) action (%S)",
|
|
pBroadcastHeader->dbud_szName,
|
|
lpszStiAction));
|
|
|
|
hThread = ::CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)BroadcastSysMessageThreadProc,
|
|
(LPVOID)pBroadcastString,
|
|
0,
|
|
&dwThread);
|
|
|
|
if ( hThread )
|
|
CloseHandle(hThread);
|
|
}
|
|
|
|
#endif // USE_BROADCASTSYSTEM
|
|
|
|
} // endproc
|
|
|
|
|
|
VOID
|
|
BroadcastSysMessageThreadProc(
|
|
VOID *pContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD dwStartTime = ::GetTickCount();
|
|
|
|
DWORD dwRecepients = BSM_APPLICATIONS
|
|
// | BSM_ALLDESKTOPS
|
|
// | BSM_ALLCOMPONENTS
|
|
;
|
|
|
|
struct _DEV_BROADCAST_USERDEFINED *pBroadcastHeader =
|
|
(_DEV_BROADCAST_USERDEFINED *) pContext;
|
|
|
|
::BroadcastSystemMessage(BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG |
|
|
BSF_POSTMESSAGE | BSF_IGNORECURRENTTASK,
|
|
&dwRecepients, // Broadcast to all
|
|
WM_DEVICECHANGE,
|
|
DBT_USERDEFINED, // wParam
|
|
(LPARAM)pBroadcastHeader // lParam
|
|
);
|
|
|
|
DBG_TRC((" Broadcasted system message for (%S). Taken time (ms): %d ",
|
|
pBroadcastHeader->dbud_szName,
|
|
(::GetTickCount() - dwStartTime)
|
|
));
|
|
|
|
delete[] (BYTE *) pContext;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpDeviceChangeData(
|
|
HWND hWnd,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
Loads the window position structure from registry and resets
|
|
|
|
Returns:
|
|
Win32 error code. NO_ERROR on success
|
|
|
|
--*/
|
|
{
|
|
#ifdef MAXDEBUG
|
|
|
|
TCHAR szDbg[MAX_PATH];
|
|
|
|
OutputDebugString(TEXT("STISvc: WM_DEVICECHANGE message received\n"));
|
|
|
|
switch (wParam) {
|
|
case DBT_DEVICEARRIVAL:
|
|
OutputDebugString(TEXT(" DBT_DEVICEARRIVAL event\n"));
|
|
break;
|
|
|
|
case DBT_DEVICEREMOVECOMPLETE:
|
|
OutputDebugString(TEXT(" DBT_DEVICEREMOVECOMPLETE event\n"));
|
|
break;
|
|
|
|
case DBT_DEVICEQUERYREMOVE:
|
|
OutputDebugString(TEXT(" DBT_DEVICEQUERYREMOVE event\n"));
|
|
break;
|
|
|
|
case DBT_DEVICEQUERYREMOVEFAILED:
|
|
OutputDebugString(TEXT(" DBT_DEVICEQUERYREMOVEFAILED event\n"));
|
|
break;
|
|
|
|
case DBT_DEVICEREMOVEPENDING:
|
|
OutputDebugString(TEXT(" DBT_DEVICEREMOVEPENDING event\n"));
|
|
break;
|
|
|
|
case DBT_DEVICETYPESPECIFIC:
|
|
OutputDebugString(TEXT(" DBT_DEVICETYPESPECIFIC event\n"));
|
|
break;
|
|
|
|
case DBT_CUSTOMEVENT:
|
|
OutputDebugString(TEXT(" DBT_CUSTOMEVENT event\n"));
|
|
break;
|
|
|
|
case DBT_CONFIGCHANGECANCELED:
|
|
OutputDebugString(TEXT(" DBT_CONFIGCHANGECANCELED event\n"));
|
|
break;
|
|
case DBT_CONFIGCHANGED:
|
|
OutputDebugString(TEXT(" DBT_CONFIGCHANGED event\n"));
|
|
break;
|
|
case DBT_QUERYCHANGECONFIG:
|
|
OutputDebugString(TEXT(" DBT_QUERYCHANGECONFIG event\n"));
|
|
break;
|
|
case DBT_USERDEFINED:
|
|
OutputDebugString(TEXT(" DBT_USERDEFINED event\n"));
|
|
break;
|
|
|
|
default:
|
|
CHAR szOutput[MAX_PATH];
|
|
sprintf(szOutput, " DBT_unknown event, value (%d)\n", wParam);
|
|
OutputDebugStringA(szOutput);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!lParam || IsBadReadPtr((PDEV_BROADCAST_HDR)lParam,sizeof(DEV_BROADCAST_HDR))) {
|
|
return ;
|
|
}
|
|
|
|
switch (((PDEV_BROADCAST_HDR)lParam)->dbch_devicetype) {
|
|
case DBT_DEVTYP_DEVICEINTERFACE: {
|
|
PDEV_BROADCAST_DEVICEINTERFACE p = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
|
|
TCHAR * pString;
|
|
|
|
OutputDebugString(TEXT(" DBT_DEVTYP_DEVICEINTERFACE\n"));
|
|
wsprintf(szDbg, TEXT(" %s\n"), p->dbcc_name);
|
|
OutputDebugString(szDbg);
|
|
if (UuidToString(&p->dbcc_classguid, (RPC_STRING* )&pString) == RPC_S_OK)
|
|
{
|
|
wsprintf(szDbg, TEXT(" %s\n"), pString);
|
|
OutputDebugString(szDbg);
|
|
|
|
RpcStringFree((RPC_STRING* )&pString);
|
|
}
|
|
break;
|
|
}
|
|
case DBT_DEVTYP_HANDLE:
|
|
OutputDebugString(TEXT(" DBT_DEVTYP_HANDLE\n"));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
wsprintf(szDbg, TEXT(" wParam = %X lParam=%X\n"),wParam,lParam);
|
|
OutputDebugString(szDbg);
|
|
#endif
|
|
|
|
} // DumpDeviceChangeData
|