PDA

Просмотр полной версии : Как аккуратно(!) обнаружить подключение флешки?


_nic
01.12.2008, 23:03
Как это сделать аккуратно?То есть что бы и флопик не тарахтел,и процессор излишне на слабых машинах не грузился ,и что бы не возникало никаких подозрительных симтопом при вставке\выбросе оптических дисков.
ЗЫ:ганять в цикле по алфавиту GetDriveType как то не очень хочется.

0verbreaK
02.12.2008, 03:00
Гоняй в цикле по алфавиту начиная с B по Z и не будет тарахтеть флопик

noobyara
02.12.2008, 05:33
Как это сделать аккуратно?То есть что бы и флопик не тарахтел,и процессор излишне на слабых машинах не грузился ,и что бы не возникало никаких подозрительных симтопом при вставке\выбросе оптических дисков.
ЗЫ:ганять в цикле по алфавиту GetDriveType как то не очень хочется.

возможно стоит посмотреть в строну WMI и Win32_DeviceChangeEvent(да и других событий), только все это дело под XP и выше.

neprovad
02.12.2008, 11:34
Предыдущий автор прав. Копать в сторону событий.
http://msdn.microsoft.com/en-us/library/aa363205(VS.85).aspx

_nic
02.12.2008, 17:37
Не совсем понял технологию.Это что надо перхватывать WindowProc и смотреть что там в uMsg ?

0x0c0de
02.12.2008, 18:03
>> Это что надо перхватывать WindowProc и смотреть что там в uMsg ?

нет. вы регистрируете свой обработчик. и система его вызовет, котгда устройство будет присоединено

http://msdn.microsoft.com/en-us/library/aa363432(VS.85).aspx

_nic
02.12.2008, 23:02
ВОт нагуглил более простой пример чем на МСДН

#include <windows.h>
#include <iostream>
#include <dbt.h>

class CatchAll
{
public:
LRESULT DeviceChange(DWORD event, PDEV_BROADCAST_HDR pHdr);
HWND m_hwnd;
};

LRESULT CatchAll::DeviceChange(DWORD event, PDEV_BROADCAST_HDR pHdr)
{
BOOL fEvent = FALSE ;
switch (event)
{
case DBT_DEVICEARRIVAL:
printf("Begin");
fEvent = TRUE ;
break ;
case DBT_DEVICEREMOVECOMPLETE:
printf( "End");
fEvent = TRUE ;
}

if (fEvent)
{
switch( pHdr->dbch_devicetype )
{
case DBT_DEVTYP_VOLUME:
PDEV_BROADCAST_VOLUME pDevVolume = (PDEV_BROADCAST_VOLUME)pHdr;
// do something...
printf ("WM_DEVICECHANGE hurra!!!");
break;
}
}
return 0;

}

LRESULT CALLBACK MessageLoopProc(HWND m_hwnd,UINT Message,WPARAM wParam,LPARAM lParam)
{
CatchAll ca;
switch ( Message )
{
case WM_DEVICECHANGE:
MessageBox(m_hwnd,TEXT("Device changed"),TEXT("Sys message"),MB_OK);
printf ("WM_DEVICECHANGE in MessageLoopProc!");
ca.DeviceChange( wParam, (PDEV_BROADCAST_HDR)lParam);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;

default:
return DefWindowProc(m_hwnd,Message,wParam,lParam);
}

return 0;

}

int main()
{

HINSTANCE hInst = GetModuleHandle(NULL);
WNDCLASSEX WndClass;
HWND m_hwnd;

char szClassName[] = "HiddenWindow";

WndClass.cbSize = sizeof(WNDCLASSEX);
WndClass.style=CS_HREDRAW | CS_VREDRAW;
WndClass.lpfnWndProc = /*(WNDPROC)*/MessageLoopProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInst;
WndClass.hIcon = 0l;
WndClass.hCursor = NULL;
WndClass.hbrBackground = NULL;
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = szClassName;
WndClass.hIconSm = 0l;

RegisterClassEx(&WndClass);

m_hwnd = CreateWindow( szClassName, "Hidden Window",
WS_OVERLAPPEDWINDOW,
0,
0,
10,
10,
NULL,
NULL,
hInst,
NULL);
ShowWindow(m_hwnd,SW_SHOW); // SW_HIDE
UpdateWindow(m_hwnd);


MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

/* return CatchAll().MessageLoop();*/
return 0;
}
только вот меня смущяет то что код хоть и выглядит гуевым но точка входа main :confused: Да и ещё непонятно почему мессагбокс вылазит раз 5 при вставке флешки.WM_DEVICECHANGE это что получается при вставке флэхи это событие происходит 5 раз подряд??

noobyara
02.12.2008, 23:43
ВОт нагуглил более простой пример чем на МСДН

#include <windows.h>
#include <iostream>
#include <dbt.h>

class CatchAll
{
public:
LRESULT DeviceChange(DWORD event, PDEV_BROADCAST_HDR pHdr);
HWND m_hwnd;
};

LRESULT CatchAll::DeviceChange(DWORD event, PDEV_BROADCAST_HDR pHdr)
{
BOOL fEvent = FALSE ;
switch (event)
{
case DBT_DEVICEARRIVAL:
printf("Begin");
fEvent = TRUE ;
break ;
case DBT_DEVICEREMOVECOMPLETE:
printf( "End");
fEvent = TRUE ;
}

if (fEvent)
{
switch( pHdr->dbch_devicetype )
{
case DBT_DEVTYP_VOLUME:
PDEV_BROADCAST_VOLUME pDevVolume = (PDEV_BROADCAST_VOLUME)pHdr;
// do something...
printf ("WM_DEVICECHANGE hurra!!!");
break;
}
}
return 0;

}

LRESULT CALLBACK MessageLoopProc(HWND m_hwnd,UINT Message,WPARAM wParam,LPARAM lParam)
{
CatchAll ca;
switch ( Message )
{
case WM_DEVICECHANGE:
MessageBox(m_hwnd,TEXT("Device changed"),TEXT("Sys message"),MB_OK);
printf ("WM_DEVICECHANGE in MessageLoopProc!");
ca.DeviceChange( wParam, (PDEV_BROADCAST_HDR)lParam);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;

default:
return DefWindowProc(m_hwnd,Message,wParam,lParam);
}

return 0;

}

int main()
{

HINSTANCE hInst = GetModuleHandle(NULL);
WNDCLASSEX WndClass;
HWND m_hwnd;

char szClassName[] = "HiddenWindow";

WndClass.cbSize = sizeof(WNDCLASSEX);
WndClass.style=CS_HREDRAW | CS_VREDRAW;
WndClass.lpfnWndProc = /*(WNDPROC)*/MessageLoopProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInst;
WndClass.hIcon = 0l;
WndClass.hCursor = NULL;
WndClass.hbrBackground = NULL;
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = szClassName;
WndClass.hIconSm = 0l;

RegisterClassEx(&WndClass);

m_hwnd = CreateWindow( szClassName, "Hidden Window",
WS_OVERLAPPEDWINDOW,
0,
0,
10,
10,
NULL,
NULL,
hInst,
NULL);
ShowWindow(m_hwnd,SW_SHOW); // SW_HIDE
UpdateWindow(m_hwnd);


MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

/* return CatchAll().MessageLoop();*/
return 0;
}
только вот меня смущяет то что код хоть и выглядит гуевым но точка входа main :confused: Да и ещё непонятно почему мессагбокс вылазит раз 5 при вставке флешки.WM_DEVICECHANGE это что получается при вставке флэхи это событие происходит 5 раз подряд??
да хоть nepohek назови главное указать это в параметрах линкера,флаг SUBSYSTEM отвечает за тип приложения (например /SUBSYSTEM:CONSOLE) и флаг ENTRY за точку входа(/ENTRY:"nepohek"). в студии это можно сделать через опции проекта( Linker->System->SubSystem b Linker->Advanced->Entry Point)

0x0c0de
03.12.2008, 06:08
да хоть nepohek назови главное указать это в параметрах линкера,флаг SUBSYSTEM отвечает за тип приложения (например /SUBSYSTEM:CONSOLE) и флаг ENTRY за точку входа(/ENTRY:"nepohek"). в студии это можно сделать через опции проекта( Linker->System->SubSystem b Linker->Advanced->Entry Point)


Или в самом коде...

#pragma comment(linker,"/ENTRY:main")

и

#pragma comment(linker,"/SUBSYSTEM:CONSOLE")

neprovad
03.12.2008, 20:27
все верно что 5 раз, просто из всего этого изобилия надо выбрать все что попадает под event = DBT_DEVICEARRIVAL

Suteki
20.05.2009, 01:34
Данный код отлично собирается как Win32 Application.

Подскажите как реализовать с использованием MFC :confused:

гугл выдал кусок кода:

Чтобы приложение основанное на MFC могло отловить и отроботать данное сообщение в карте сообщений необходимо написать следующее:

ON_MESSAGE(WM_DEVICECHANGE, OnDeviceChange)

Из значений которые может принимать wParam для интересующего нас случая важно следующее:
DBT_DEVICEARRIVAL – подключили новое устройство
DBT_DEVICEREMOVECOMPLETE – устройство было отключено

#include <dbt.h>

LRESULT OnDeviceChange(WPARAM wParam, LPARAM lParam)
{
// следует обратить внимание на эту строку:
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;

switch(wParam)
{
case DBT_DEVICEARRIVAL:
if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;

if (lpdbv -> dbcv_flags & DBTF_MEDIA)
{
MessageBox (NULL, _T(“Устройство подключено”), _T("WM_DEVICECHANGE"), MB_OK );
}
}
break;

case DBT_DEVICEREMOVECOMPLETE:
if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;

if (lpdbv -> dbcv_flags & DBTF_MEDIA)
{
MessageBox (NULL, _T(“Устройство отключено”), _T("WM_DEVICECHANGE"), MB_OK );
}
}
break;
}
}

НО код компилируется с ошибкой:
error C4716: 'OnDeviceChange' : must return a value Error executing cl.exe.

вставляю перед последний скобкой
return 0;

Появлятся 2 ошибки:
MainFrm.obj : error LNK2001: unresolved external symbol "public: long __thiscall CMainFrame::OnDeviceChange(unsigned int,long)" (?OnDeviceChange@CMainFrame@@QAEJIJ@Z)

Debug/FLA.exe : fatal error LNK1120: 1 unresolved externals

Suteki
21.05.2009, 03:24
Проблему решил. Привожу ниже мануал.
Мини-Мануал для MFC
1) В хайдер мейнфрейма (MainFrm.h) добавляем в описание класса прототип функции OnDeviceChange (в protected:)
BOOL OnDeviceChange( UINT nEventType, DWORD dwData );
2) В мейнфрейм (MainFrm.cpp) подключаем хайдер dbt.h
#include <dbt.h>
3) Дописываем в карту откликов после //}}AFX_MSG_MAP отклик ON_WM_DEVICECHANGE ()
ON_WM_DEVICECHANGE ()

4) В конец мейнфрейма дописываем следующий код:



bool inline IsBitSet (DWORD64 dwMask, UINT nTHBit)
{
DWORD64 dwBit = 1;
dwBit <<= nTHBit;
dwMask &= dwBit;
return dwMask ? true : false;
}

BOOL CMainFrame::OnDeviceChange( UINT nEventType, DWORD dwData )
{
BOOL bReturn = CWnd::OnDeviceChange (nEventType, dwData);

DEV_BROADCAST_VOLUME *volume = (DEV_BROADCAST_VOLUME *)dwData;
CString log;

if (nEventType == DBT_DEVICEARRIVAL)
{
if (volume->dbcv_devicetype == DBT_DEVTYP_VOLUME)
{
for (int n = 0; n < 32; n++)
{
if (IsBitSet (volume->dbcv_unitmask, n))
{
log.Format ("Drive %c: Inserted\n", n + 'A');
::AfxMessageBox(log);

log.Format ("%c", n + 'A');
// Флешка подключена. Имя флешки в системе содержит строковая переменная log
}
}
}
}

if (nEventType == DBT_DEVICEREMOVECOMPLETE)
{
if (volume->dbcv_devicetype == DBT_DEVTYP_VOLUME)
{
for (int n = 0; n < 32; n++)
{
if (IsBitSet (volume->dbcv_unitmask, n))
{
log.Format ("Drive %c: Removed\n", n + 'A');
::AfxMessageBox(log);

log.Format ("%c", n + 'A');
// Флешка извлечена. Имя флешки в системе содержит строковая переменная log
}
}
}
}

return bReturn;
}



Файл проекта + собранный exe (http://debibi.narod.ru/MFC.rar)