Nur auf ein bestimmtes USB-Gerät reagieren



  • Hallo miteinander.

    Ich möchte ein kleines Programm schreiben das beim Einstecken einer bestimmten USB-Festplatte damit beginnt, Daten zu sichern.

    Habe schon einiges via Google und auch im Forum gefunden. Das Reagieren auf USB-Geräte im Allgemeinen geht auch. Zur Identifikation versuche ich aber schon seit zwei Tagen die Seriennummer aus einem USB-Gerät (zum Test ein Stick) zu lesen. Allerdings wird die entsprechende Struktur nicht weiter durch den Aufruf von DeviceIoControl gefüllt. Ich glaube auch, dass die Geräteangabe (1. Parameter an CreateFile) inkorrekt sein könnte. Versuche als 1. Parameter einen String aus dem Gerätemanager zu nutzen (PID, VID, GUID-Klasse) sind mir auch fehlgeschlagen.

    Hier mal das Codelisting. Da, wo ich versuche die Seriennummer auszulesen, steht der Kommentar "Seriennummer auslesen":

    #include "BT-Funktion.h"
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpStrCmdLine, int iShow)
    {
    	HWND	 hwnd;
    	WNDCLASS wndClass;
    	MSG		 msg;
    	wchar_t	 szApp[] = L"Sicherung";
    
    	wndClass.style = CS_HREDRAW | CS_VREDRAW;
    	wndClass.lpfnWndProc = WndProc;
    	wndClass.cbClsExtra = 0;
    	wndClass.cbWndExtra = 0;
    	wndClass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
    	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    	wndClass.hInstance = hInstance;
    	wndClass.lpszClassName = szApp;
    	wndClass.lpszMenuName = NULL;
    
    	if(!RegisterClass(&wndClass))
    	{
    		MessageBox(NULL, L"Unicode-Fehler", szApp, MB_ICONERROR);
    		return 0;
    	}
    
    	hwnd = CreateWindow(szApp,
    						L"Sicherung",
    						WS_OVERLAPPEDWINDOW,
    						CW_USEDEFAULT, CW_USEDEFAULT,
    						CW_USEDEFAULT, CW_USEDEFAULT,
    						NULL,
    						NULL,
    						hInstance,
    						NULL);
    
    	ShowWindow(hwnd, iShow);
    	UpdateWindow(hwnd);
    
    	while(GetMessage(&msg, NULL, 0, 0))
    	{
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
    
    	return msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	PAINTSTRUCT	ps;
    	HDC			hdc;
    	//********
    	HANDLE		hHCDev;
    	//********
    	PDEV_BROADCAST_HDR dev;
    
    	static bool		bUSBIn;
    	static wchar_t	buffer[2][100];
    
    	switch(message)
    	{
    	case WM_CREATE:		
    						return 0;
    
    	case WM_PAINT:		hdc = BeginPaint(hwnd, &ps);
    
    						if(bUSBIn)
    						{
    							TextOut(hdc, 10, 10, buffer[0], wcslen(buffer[0]));
    							TextOut(hdc, 10, 30, buffer[1], wcslen(buffer[1]));
    						}
    						else
    							TextOut(hdc, 10, 10, buffer[0], wcslen(buffer[0]));
    
    						EndPaint(hwnd, &ps);
    
    						return 0;
    
    	case WM_DEVICECHANGE:
    						switch(wParam)
    						{
    						case DBT_DEVICEARRIVAL: bUSBIn=true;
    												wcscpy_s(buffer[0], sizeof(buffer[0]), L"Gerät eingehängt");
    												dev=(PDEV_BROADCAST_HDR)lParam;
    												if(dev->dbch_devicetype == DBT_DEVTYP_VOLUME)
    													wcscpy_s(buffer[1], sizeof(buffer), L"Platte");
    
    												//********* Seriennummer auslesen *******************
    
    												hHCDev = CreateFile(L"\\\\.\\HCD0",
    																	GENERIC_READ,
    																	FILE_SHARE_READ,
    																	NULL,
    																	OPEN_EXISTING,
    																	FILE_FLAG_OVERLAPPED,
    																	NULL);
    
    												if(hHCDev != INVALID_HANDLE_VALUE)
    												{
    													DWORD dwReturn=0;
    													MEDIA_SERIAL_NUMBER_DATA msnd={0};
    
    													DeviceIoControl(hHCDev, IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER, NULL, 0, &msnd, sizeof(msnd), &dwReturn, NULL);
    													//Seriennummer sichern
    													unsigned char *test = msnd.SerialNumberData;
    												}
    												else
    													MessageBox(hwnd, L"Fehler bei Geräteerkennung", L"FEHLER", MB_ICONERROR);
    
    												//********* Seriennummer auslesen (ENDE) *******************
    
    												break;
    
    						case DBT_DEVICEREMOVECOMPLETE:
    												bUSBIn=false;
    												wcscpy_s(buffer[0], sizeof(buffer[0]), L"kein Gerät eingehängt");
    												wcscpy_s(buffer[1], sizeof(buffer[1]), L"");
    
    												break;
    						}
    
    						InvalidateRect(hwnd, NULL, TRUE);
    						return 0;
    
    	case WM_DESTROY:	PostQuitMessage(0);
    
    						return 0;
    
    	}
    
    	return DefWindowProc(hwnd, message, wParam, lParam);
    }
    

    Danke für's reinschauen.

    Gruß
    Kai



  • Auf dein Problem bezogen weiß ich keinen Rat, jedoch könntest du das Backup einfach dadurch auslösen, dass auf dem Datenträger eine bestimmte Datei zu finden sein muss. Die kann dazu zusätzliche nützliche Informationen wie die Backupquellen etc. enthalten.



  • Ich würde sagen das ist ein guter Rat.

    Man kann zwar durchaus an die gesuchten Informationen drankommen (Datenträger Seriennummer etc.)*, aber es ist viel aufwendiger als ein Tag-File zu verwenden.
    Und vermutlich ist es auch weniger robust. Es gibt z.B. immer wieder mal Datenträger die keine oder keine brauchbare Seriennummer melden (z.B. wenn bei jedem Datenträger eines bestimmten Modells immer die selbe Seriennummer gemeldet wird).

    *: Ich hab' den entsprechenden Code dazu nicht hier, und auswendig weiss ich es auch nicht mehr, daher kann ich leider kein Beispiel posten.



  • Ich danke euch für eure schnellen Antworten.

    Das mit der Datei auf dem Datenträger war so mein erster Gedanke. Allerdings würde ich jetzt, wo ich damit angefangen habe, schon gerne wissen wie das mit C++ funktioniert - ist halt so eine Macke von mir.

    Gruß
    Kai





  • Den Typcast von lParam nach PDEV_BROADCAST_HDR nutze ich auch schon. Der gibt mir aber, soweit ich das hier peile, nicht die Infos die mir fehlen.

    Die Nachricht DBT_DEVTYP_DEVICEINTERFACE, von der da auch noch die Rede ist, erhalte ich nicht.



  • Vielleicht musst du noch RegisterDeviceNotification aufrufen? Mich juckt es ja schon in den Fingern, das mal selber zu probieren 🕶 😋



  • Bei mir springt er mit diesem Code:

    case WM_CREATE:
    	DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
    
    	ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
    	NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    	NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    
    	notifyHandle = RegisterDeviceNotification
    	(
    		hWnd
    		, &NotificationFilter
    		, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES
    	);
    
    	if (notifyHandle == NULL)
    	{
    		MessageBox(hWnd, L"Error registering for notification", L"", MB_OK);
    		ExitProcess(1);
    	}
    
    	break;
    

    ... hier in die MessageBox rein, wo dann VID und PID und noch anderer Kram drin steht:

    case WM_DEVICECHANGE:
    	if (wParam == DBT_DEVICEARRIVAL)
    	{
    		DEV_BROADCAST_HDR *devBroadcastHdr = (DEV_BROADCAST_HDR *)lParam;
    
    		if (devBroadcastHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
    		{
    			DEV_BROADCAST_DEVICEINTERFACE *devBroadcastDeviceInterface = (DEV_BROADCAST_DEVICEINTERFACE *)lParam;
    
    			MessageBox(hWnd, devBroadcastDeviceInterface->dbcc_name, L"", MB_OK);
    		}
    	}
    
    	break;
    

    Der Code is alles andere als schön oder vollständig, aber er sollte verdeutlichen, was nötig ist, damit du dein gewünschtes Verhalten herzaubern kannst.

    Geklaut hab ich da: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363432(v=vs.85).aspx



  • Mit FileTags währs einfacher...aber wenn du unbedingt SerienNummer ermitteln willst, dann schau hier rein:
    https://oroboro.com/usb-serial-number/

    Mein Tipp:
    Beim ersten einschalten von USB HD Ser.Nr ermitteln(seihe link) und zwischen speichern. Sobald irgend-ein USB Gerät eingeschaltet wird Ser.Nr ermittel, danach vergleichen mit zwischen gespeicherten Ser.Nr, wenn übereinstimmt BackUp erstellen.


Anmelden zum Antworten