📄 autolaunch.cpp
字号:
static int retries = 0;
if (retries++ > 5)
{ // can't create tray icon
TRACE(TSVCNAME _T(" - Shell_NotifyIcon failed - %d\n"), GetLastError());
DestroyWindow();
} // can't create tray icon
SetTimer(1, 10000, NULL);
} // CAutoLaunch::CreateTrayIcon
///////////////////////////////////////////////////////////////////////////////
int CAutoLaunch::OnCreate(LPCREATESTRUCT csp)
{ // CAutoLaunch::OnCreate
Log(_T("Starting service"));
// Register to receive notifications when device drivers enable a GUID_AUTOLAUNCH_NOTIFY
// interface. Note that we discard the notification handle because we can't unregister
// it without making Win98 unstable.
DEV_BROADCAST_DEVICEINTERFACE filter = {0};
filter.dbcc_size = sizeof(filter);
filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
filter.dbcc_classguid = GUID_AUTOLAUNCH_NOTIFY;
HDEVNOTIFY hNotification = RegisterDeviceNotification(m_hWnd, (PVOID) &filter, DEVICE_NOTIFY_WINDOW_HANDLE);
if (!hNotification)
{ // can't register for notifications
TRACE(TSVCNAME _T(" - RegisterDeviceNotification failed - %d\n"), GetLastError());
return -1;
} // can't register for notifications
// Create a tray icon to give the end user a way to shut this service down
CreateTrayIcon();
// Create an initially invisible modeless dialog for asking permission to
// close the service. If we were just to call MessageBox in the OnMenuClose
// function, it wouldn't return the first time if we happen to be launched
// via WinExec from a device driver. The second or third time the user tries to
// close the service, the call would return to find this object already deleted,
// and a crash would ensue. This took a while to figure out, I can tell you!
m_shutdown = new CShutdownDlg(this);
return 0;
} // CAutoLaunch::OnCreate
///////////////////////////////////////////////////////////////////////////////
void CAutoLaunch::OnDestroy()
{ // CAutoLaunch::OnDestroy
Log(_T("Shutting service down"));
NOTIFYICONDATA nid = {sizeof(NOTIFYICONDATA)};
nid.hWnd = m_hWnd;
Shell_NotifyIcon(NIM_DELETE, &nid);
PostQuitMessage(0);
CWnd::OnDestroy();
} // CAutoLaunch::OnDestroy
///////////////////////////////////////////////////////////////////////////////
BOOL CAutoLaunch::OnDeviceChange(UINT evtype, DWORD dwData)
{ // CAutoLaunch::OnDeviceChange
HandleDeviceChange(evtype, (_DEV_BROADCAST_HEADER*) dwData);
return TRUE;
} // CAutoLaunch::OnDeviceChange
///////////////////////////////////////////////////////////////////////////////
LRESULT CAutoLaunch::OnNotifyIcon(WPARAM wParam, LPARAM lParam)
{ // CAutoLaunch::OnNotifyIcon
if (lParam == WM_RBUTTONDOWN)
{ // display context menu
SetForegroundWindow(); // KB Q135788
CMenu menu;
menu.LoadMenu(IDR_CONTEXT);
CMenu* popup = menu.GetSubMenu(0);
POINT pt;
UINT flags = TPM_RIGHTBUTTON;
GetCursorPos(&pt);
popup->TrackPopupMenu(flags, pt.x, pt.y, this);
PostMessage(WM_NULL, 0, 0); // KB Q135788
} // display context menu
return 0;
} // CAutoLaunch::OnNotifyIcon
///////////////////////////////////////////////////////////////////////////////
void CAutoLaunch::OnMenuClose()
{ // CAutoLaunch::OnMenuClose
m_shutdown->ShowWindow(SW_SHOW);
} // CAutoLaunch::OnMenuClose
///////////////////////////////////////////////////////////////////////////////
void CAutoLaunch::OnTimer(UINT id)
{ // CAutoLaunch::OnTimer
KillTimer(id);
CreateTrayIcon();
} // CAutoLaunch::OnTimer
///////////////////////////////////////////////////////////////////////////////
void CAutoLaunch::PostNcDestroy()
{ // CAutoLaunch::PostNcDestroy
CWnd::PostNcDestroy();
delete this;
} // CAutoLaunch::PostNcDestroy
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
BOOL CAutoLaunchApp::InitInstance()
{ // CAutoLaunchApp::InitInstance
// Avoid running two instances of this module
m_hMutex = CreateMutex(NULL, FALSE, _T("AUTOLAUNCH_MUTEX"));
if (GetLastError() == ERROR_ALREADY_EXISTS)
{ // already running
CloseHandle(m_hMutex);
return FALSE;
} // already running
// Create an invisible window to receive WM_DEVICECHANGE messages
CAutoLaunch* dummy = new CAutoLaunch;
if (!dummy->CreateEx(0, AfxRegisterWndClass(0), _T("Device Driver Service"), WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL))
return FALSE; // give up if can't create window
m_pMainWnd = dummy;
return TRUE;
} // CAutoLaunchApp::InitInstance
///////////////////////////////////////////////////////////////////////////////
int CAutoLaunchApp::ExitInstance()
{ // CAutoLaunchApp::ExitInstance
CloseHandle(m_hMutex);
return 0;
} // CAutoLaunchApp::ExitInstance
#endif // NOT NTSERVICE
//=============================================================================
//=============================================================================
// B O T H C O N F I G U R A T I O N S
//=============================================================================
//=============================================================================
VOID CAutoLaunch::EnumerateExistingDevices(const GUID* guid)
{ // CAutoLaunch::EnumerateExistingDevices
HDEVINFO info = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
if (info == INVALID_HANDLE_VALUE)
return;
SP_INTERFACE_DEVICE_DATA ifdata;
ifdata.cbSize = sizeof(ifdata);
DWORD devindex;
for (devindex = 0; SetupDiEnumDeviceInterfaces(info, NULL, guid, devindex, &ifdata); ++devindex)
{ // for each device
DWORD needed;
SetupDiGetDeviceInterfaceDetail(info, &ifdata, NULL, 0, &needed, NULL);
PSP_INTERFACE_DEVICE_DETAIL_DATA detail = (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc(needed);
if (!detail)
continue;
detail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
SP_DEVINFO_DATA devdata = {sizeof(SP_DEVINFO_DATA)};
if (!SetupDiGetDeviceInterfaceDetail(info, &ifdata, detail, needed, NULL, &devdata))
{ // can't get detail info
free((PVOID) detail);
continue;
} // can't get detail info
CString devname = detail->DevicePath;
free((PVOID) detail);
OnNewDevice(devname, info, &devdata);
} // for each device
SetupDiDestroyDeviceInfoList(info);
} // CAutoLaunch::EnumerateExistingDevices
///////////////////////////////////////////////////////////////////////////////
DWORD CAutoLaunch::HandleDeviceChange(DWORD evtype, _DEV_BROADCAST_HEADER *dbhdr)
{ // CAutoLaunch::HandleDeviceChange
if (!dbhdr || dbhdr->dbcd_devicetype != DBT_DEVTYP_DEVICEINTERFACE)
return 0; // ignore all other events
// Extract symbolic link name of the device that's arrived. In NT, the service always
// receives the UNICODE version of the notification structure
#ifdef NTSERVICE
PDEV_BROADCAST_DEVICEINTERFACE_W p = (PDEV_BROADCAST_DEVICEINTERFACE_W) dbhdr;
#else
PDEV_BROADCAST_DEVICEINTERFACE p = (PDEV_BROADCAST_DEVICEINTERFACE) dbhdr;
#endif
CString devname = p->dbcc_name;
// If device is departing, remove its name from our list
if (evtype == DBT_DEVICEREMOVECOMPLETE)
{ // device removed
for (int i = 0; i < m_devices.GetSize(); )
if (devname.CompareNoCase(m_devices[i]) == 0)
m_devices.RemoveAt(i);
else
++i;
} // device removed
// If device is arriving, check for the need to launch a command automatically
else if (evtype == DBT_DEVICEARRIVAL)
{ // interface arrival event
HDEVINFO info = SetupDiCreateDeviceInfoList(NULL, NULL);
if (info == INVALID_HANDLE_VALUE)
return 0;
SP_DEVICE_INTERFACE_DATA ifdata = {sizeof(SP_DEVICE_INTERFACE_DATA)};
SP_DEVINFO_DATA devdata = {sizeof(SP_DEVINFO_DATA)};
if (SetupDiOpenDeviceInterface(info, devname, 0, &ifdata)
&& (SetupDiGetDeviceInterfaceDetail(info, &ifdata, NULL, 0, NULL, &devdata)
|| GetLastError() == ERROR_INSUFFICIENT_BUFFER))
OnNewDevice(devname, info, &devdata);
SetupDiDestroyDeviceInfoList(info);
} // interface arrival event
return 0;
} // CAutoLaunch::HandleDeviceChange
///////////////////////////////////////////////////////////////////////////////
void CAutoLaunch::OnNewDevice(const CString& devname, HDEVINFO info, PSP_DEVINFO_DATA devdata)
{ // CAutoLaunch::OnNewDevice
// Prevent duplicate launches
for (int i = 0; i < m_devices.GetSize(); )
if (devname.CompareNoCase(m_devices[i]) == 0)
return;
else
++i;
m_devices.Add(devname);
// Open the hardware key for this device
HKEY hkey = SetupDiOpenDevRegKey(info, devdata, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if (!hkey)
{ // can't open key
CString msg;
msg.Format(_T("Can't open registry key for %s"), (LPCTSTR) devname);
Log(msg);
return;
} // can't open key
// Get the AutoLaunch parameter from the registry
DWORD junk;
TCHAR buffer[_MAX_PATH];
DWORD size = sizeof(buffer);
CString Command;
if (RegQueryValueEx(hkey, _T("AutoLaunch"), NULL, &junk, (LPBYTE) buffer, &size) != 0)
{ // no AutoLaunch
CString msg;
msg.Format(_T("No AutoLaunch parameter for %s"), (LPCTSTR) devname);
Log(msg);
RegCloseKey(hkey);
return;
} // no AutoLaunch
Command = buffer;
// Determine the device's friendly name
CString FriendlyName;
size = sizeof(buffer);
if (!SetupDiGetDeviceRegistryProperty(info, devdata, SPDRP_FRIENDLYNAME, NULL, (PBYTE) buffer, sizeof(buffer), NULL)
|| !SetupDiGetDeviceRegistryProperty(info, devdata, SPDRP_DEVICEDESC, NULL, (PBYTE) buffer, sizeof(buffer), NULL))
buffer[0] = 0; // no friendly name or description
FriendlyName.Format(_T("\"%s\""), buffer);
RegCloseKey(hkey);
// Format and invoke the command
ExpandEnvironmentStrings(Command, buffer, arraysize(buffer));
CString name;
name.Format(_T("\"%s\""), (LPCTSTR) devname);
Command.Format(buffer, (LPCTSTR) name, (LPCTSTR) FriendlyName);
STARTUPINFO si = {sizeof(STARTUPINFO)};
si.lpDesktop = _T("WinSta0\\Default"); // name of interactive session's desktop
si.wShowWindow = SW_SHOW;
PROCESS_INFORMATION pi;
if (CreateProcess(NULL, (LPTSTR) (LPCTSTR) Command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{ // launched okay
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
Log(Command);
} // launched okay
else
{ // error launching command
CString msg;
msg.Format(_T("Error %d trying to execute %s"), GetLastError(), (LPCTSTR) Command);
Log(msg);
} // error launching command
} // CAutoLaunch::OnNewDevice
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -