This works fine when my thumb drive is plugged in, but unfortunately it
is also activated when I turn on my printer or insert a CD or DVD.
I need it to only work for drive G:.
include \masm32\include\masm32rt.inc
CTEXT macro Text
local szText
.data
szText byte Text, 0
.code
exitm <offset szText>
endm
DBT_DEVICEARRIVAL equ 8000h
DBT_DEVICEREMOVECOMPLETE equ 8004h
.data
No_Batch_File db "Batch file is not present.",0
Batch_File db "C:\Bat\BAK_ALL.bat",0
AppName db "UsbToHD",0
szClassName BYTE "USB_Watcher", 0
.data?
StartupInfo STARTUPINFO <?>
szComspec db MAX_PATH dup(?)
szAppname db MAX_PATH dup(?)
ProcessInfo PROCESS_INFORMATION <?>
hInst DWORD ?
hMain DWORD ?
wc WNDCLASSEX <?>
msg MSG <?>
.code
USBWatcher:
invoke GetModuleHandle, NULL
mov hInst, eax
mov wc.hInstance, eax
mov wc.lpszClassName, offset szClassName
mov wc.lpfnWndProc, offset WndProc
mov wc.style, CS_DBLCLKS
mov wc.cbSize, sizeof WNDCLASSEX
mov wc.hIcon, NULL
mov wc.hIconSm, NULL
mov wc.hCursor, NULL
mov wc.lpszMenuName, NULL
mov wc.cbClsExtra, 0
mov wc.cbWndExtra, 0
mov wc.hbrBackground, NULL
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,
NULL, \ ; don't need this
offset szClassName, \
NULL, \
NULL, \ ; don't need a window style
0, 0, 0, 0, \ ; don't need top, left, width or height
NULL, \ ; message only window
NULL, \
hInst, \
NULL
mov hMain, eax
.while TRUE
invoke GetMessage,addr msg,NULL,0,0
.break .if !eax
invoke TranslateMessage,addr msg
invoke DispatchMessage,addr msg
.endw
invoke ExitProcess, 0
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.if uMsg==WM_DEVICECHANGE
.if wParam == DBT_DEVICEARRIVAL
;invoke MessageBox, NULL, offset szMsgConnected, offset szClassName, MB_OK or MB_ICONINFORMATION
; Check if batch file is present
invoke GetFileAttributes,offset Batch_File
.IF EAX == 0FFFFFFFFh
invoke MessageBox, 0, ADDR No_Batch_File, ADDR AppName,MB_ICONINFORMATION
invoke ExitProcess,NULL
.ENDIF
invoke GetStartupInfo, addr StartupInfo
invoke GetEnvironmentVariable, CTEXT('ComSpec'), addr szComspec, sizeof szComspec
invoke wsprintf, addr szAppname, CTEXT('"%s" /c "C:\Bat\BAK_ALL.bat"'), addr szComspec
invoke CreateProcess, 0, addr szAppname, 0, 0, FALSE, \
NORMAL_PRIORITY_CLASS, 0, 0, addr StartupInfo, addr ProcessInfo
invoke WaitForSingleObject, ProcessInfo.hProcess, INFINITE
.elseif wParam == DBT_DEVICEREMOVECOMPLETE
;invoke MessageBox, hWnd, offset szMsgDisCon, offset szClassName, MB_OK or MB_ICONINFORMATION
;invoke SendMessage, hWnd, WM_CLOSE, NULL, NULL
.endif
.elseif uMsg==WM_CLOSE
;invoke MessageBox, NULL, offset szMsgClose, offset szClassName, MB_OK or MB_ICONINFORMATION
;invoke PostQuitMessage, 0
ret
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax, eax
ret
WndProc endp
Check for drive G
GetLogicalDrives
I remember running into a user-mode sample application (the source code was from the DDK) that did something similar. It was called: USB View.
From the documentation: Usbview.exe is a Windows GUI application that allows you to browse all USB controllers and connected USB devices on your system.
The source code is in C. In that example, all the device controllers were enumerated, and information retrieved using repeated calls to: DeviceIoControl (http://msdn.microsoft.com/en-us/library/aa363216(v=vs.85).aspx).
It's obviously alot more intensive than what you need here; and, USB View does not enumerate devices on pre-Windows XP SP1-based computers.
look for lParam: it is an pointer to an struct containgin information about the device -> DBT_DEVICEARRIVAL Event (http://msdn.microsoft.com/en-us/library/aa363205(v=vs.85).aspx)
Quote from: qWord on March 26, 2011, 06:34:55 PM
look for lParam: it is an pointer to an struct containgin information about the device -> DBT_DEVICEARRIVAL Event (http://msdn.microsoft.com/en-us/library/aa363205(v=vs.85).aspx)
Out of interest did this not work?
http://www.masm32.com/board/index.php?topic=13899.msg109904#msg109904
I remember I had some problem recognising my MP3 player.... It has storage but did not register as a volume or somesuch....
This will work if I can figure out how to test if bit 6 has been set.
I looked at the info for test and some old code, but could not find what I was looking for.
CheckDriveC proc uses ebx esi edi ebp DriveList: DWORD
mov eax, DriveList
and eax, 4 ; if bit #2 is set -> C is available
shr eax,2 ; bit 6 is G:
Quote from: Magnum on March 26, 2011, 07:20:59 PM
This will work if I can figure out how to test if bit 6 has been set.
I looked at the info for test and some old code, but could not find what I was looking for.
CheckDriveC proc uses ebx esi edi ebp DriveList: DWORD
mov eax, DriveList
and eax, 4 ; if bit #2 is set -> C is available
shr eax,2 ; bit 6 is G:
bt instruction
Getting "Cannot nest procedures."
Code works, maybe I messed up some .if statement.
; Usb_Watcher.asm
;
include \masm32\include\masm32rt.inc
CheckDriveC proto :DWORD
CTEXT macro Text
local szText
.data
szText byte Text, 0
.code
exitm <offset szText>
endm
DBT_DEVICEARRIVAL equ 8000h
DBT_DEVICEREMOVECOMPLETE equ 8004h
.data
No_Batch_File db "Batch file is not present.",0
Batch_File db "C:\Bat\BAK_ALL.bat",0
AppName db "UsbToHD",0
szClassName BYTE "USB_Watcher", 0
.data?
StartupInfo STARTUPINFO <?>
szComspec db MAX_PATH dup(?)
szAppname db MAX_PATH dup(?)
ProcessInfo PROCESS_INFORMATION <?>
hInst DWORD ?
hMain DWORD ?
wc WNDCLASSEX <?>
msg MSG <?>
.code
USBWatcher:
invoke GetModuleHandle, NULL
mov hInst, eax
mov wc.hInstance, eax
mov wc.lpszClassName, offset szClassName
mov wc.lpfnWndProc, offset WndProc
mov wc.style, CS_DBLCLKS
mov wc.cbSize, sizeof WNDCLASSEX
mov wc.hIcon, NULL
mov wc.hIconSm, NULL
mov wc.hCursor, NULL
mov wc.lpszMenuName, NULL
mov wc.cbClsExtra, 0
mov wc.cbWndExtra, 0
mov wc.hbrBackground, NULL
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,
NULL, \ ; don't need this
offset szClassName, \
NULL, \
NULL, \ ; don't need a window style
0, 0, 0, 0, \ ; don't need top, left, width or height
NULL, \ ; message only window
NULL, \
hInst, \
NULL
mov hMain, eax
.while TRUE
invoke GetMessage,addr msg,NULL,0,0
.break .if !eax
invoke TranslateMessage,addr msg
invoke DispatchMessage,addr msg
.endw
invoke ExitProcess, 0
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.if uMsg==WM_DEVICECHANGE
.if wParam == DBT_DEVICEARRIVAL
; Check if batch file is present
invoke GetFileAttributes,offset Batch_File
.IF EAX == 0FFFFFFFFh
invoke MessageBox, 0, ADDR No_Batch_File, ADDR AppName,MB_ICONINFORMATION
invoke ExitProcess,NULL
.ENDIF
invoke GetLogicalDrives ; get drives
invoke CheckDriveC, eax ; check if drive G: is available
CheckDriveC proc uses ebx esi edi ebp DriveList: DWORD
mov eax, DriveList
bt eax, 6 ; check if bit 6 is set (Drive G:)
ret
CheckDriveC endp
.if (eax == 7Ch)
jmp continue
.else
invoke ExitProcess, 0
.endif
continue:
invoke GetStartupInfo, addr StartupInfo
invoke GetEnvironmentVariable, CTEXT('ComSpec'), addr szComspec, sizeof szComspec
invoke wsprintf, addr szAppname, CTEXT('"%s" /c "C:\Bat\BAK_ALL.bat"'), addr szComspec
invoke CreateProcess, 0, addr szAppname, 0, 0, FALSE, \
NORMAL_PRIORITY_CLASS, 0, 0, addr StartupInfo, addr ProcessInfo
invoke WaitForSingleObject, ProcessInfo.hProcess, INFINITE
.elseif wParam == DBT_DEVICEREMOVECOMPLETE
.endif
.elseif uMsg==WM_CLOSE
ret
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax, eax
ret
WndProc endp
end USBWatcher
You need to put:
CheckDriveC proc uses ebx esi edi ebp DriveList: DWORD
mov eax, DriveList
bt eax, 6 ; check if bit 6 is set (Drive G:)
ret
CheckDriveC endp
outside the WndProc PROC
I have to check more drives because drive letter depends on whether printer is turned on.
I got C:\masm32\SOURCE\Usb_Watcher.asm(111) : error A2170: directive must appear inside a macro
invoke GetLogicalDrives ; get drives
invoke CheckDriveG, eax ; check if drive G: is available
push eax ; save for later use
.if (eax == 7Ch)
; check if G:drive has a Backup directory
; G: may be the printer drive
invoke GetFileAttributes,offset G_USB_Directory
.IF (EAX == 0FFFFFFFFh)
goto check_4_H_Drive
.ENDIF
.endif
check_4_H_Drive: ; bit 7 is H: drive
pop eax
.if (eax == 0F8h)
invoke GetFileAttributes,offset H_USB_Directory
.IF (EAX == 0FFFFFFFFh)
invoke ExitProcess, 0
.endif
.endif
continue:
invoke GetStartupInfo, addr StartupInfo
invoke GetEnvironmentVariable, CTEXT('ComSpec'), addr szComspec, sizeof szComspec
invoke wsprintf, addr szAppname, CTEXT('"%s" /c "C:\Bat\BAK_ALL.bat"'), addr szComspec
invoke CreateProcess, 0, addr szAppname, 0, 0, FALSE, \
NORMAL_PRIORITY_CLASS, 0, 0, addr StartupInfo, addr ProcessInfo
invoke WaitForSingleObject, ProcessInfo.hProcess, INFINITE
.elseif wParam == DBT_DEVICEREMOVECOMPLETE
.endif
.elseif uMsg==WM_CLOSE
ret
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax, eax
ret
WndProc endp
CheckDriveG proc uses ebx esi edi ebp DriveList: DWORD
mov eax, DriveList
bt eax, 6 ; check if bit 6 is set (Drive G:)
ret
CheckDriveG endp
CheckDriveH proc uses ebx esi edi ebp DriveList: DWORD
mov eax, DriveList
bt eax, 7 ; check if bit 7 is set (Drive H:)
ret
CheckDriveH endp
end USBWatcher
Even MasmBasic has no GOTO, Andy ;-)
Hi Andy
I have your send already a source for detect a usb drive oder if disconnect
Detect USB device insertion:
http://www.winasm.net/forum/index.php?showtopic=3472
Yes, but I have to modify it for a new situation.
Ollydbg will load this, but won't run it.
I need to see if my code is properly detecting whether a drive has as a "backup" directory.
invoke GetLogicalDrives ; get drives
invoke CheckDriveG, eax ; check if drive G: is available
push eax ; save for later use
.if (eax == 7Ch) ;match3
; check if G:drive has a Backup directory
; G: may be the printer drive
invoke GetFileAttributes,offset G_USB_Directory
.IF (EAX == 0FFFFFFFFh) ;match4
jmp check_4_H_Drive
.ENDIF ;match3
.endif ;match4
check_4_H_Drive: ; bit 7 is H: drive
pop eax
.if (eax == 0F8h)
invoke GetFileAttributes,offset H_USB_Directory
.IF (EAX == 0FFFFFFFFh)
int 3
invoke ExitProcess, 0
.endif
.endif
continue:
bsf eax, [ebx].dbcv_unitmask
add eax, 65
mov esi, chr$("X:\backup\.")
mov [esi], al
invoke exist, esi
There is a slight error in this.... "Although the dbcv_unitmask member may specify more than one volume in any message".... I *think* this means a partitioned drive....
It also says "this does not guarantee that only one message is generated for a specified event".... ie I guess this might mean that your code could execute twice....
http://msdn.microsoft.com/en-us/library/aa363249(v=vs.85).aspx
Will sleep on this one.
it is simple but it works:
(user CTRL+SHIFT+Q to quit the program)
Quoteinclude masm32rt.inc
DBT_DEVICEARRIVAL EQU 8000h
DBT_DEVTYP_VOLUME EQU 2
DEV_BROADCAST_HDR struct
dbch_size DWORD ?
dbch_devicetype DWORD ?
dbch_reserved DWORD ?
DEV_BROADCAST_HDR ends
PDEV_BROADCAST_HDR typedef ptr DEV_BROADCAST_HDR
DEV_BROADCAST_VOLUME struct
dbcv_size DWORD ?
dbcv_devicetype DWORD ?
dbcv_reserved DWORD ?
dbcv_unitmask DWORD ?
dbcv_flags WORD ?
DEV_BROADCAST_VOLUME ends
PDEV_BROADCAST_VOLUME typedef ptr DEV_BROADCAST_VOLUME
WndProc proto hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
.data
szCmd db 'C:\windows\system32\xcopy.exe "C:\masm32" "G:\backup" /E /Y',0
.data?
hInstance HINSTANCE ?
pcbWndProc PVOID ?
.code
main proc
LOCAL msg:MSG
mov esi,rv(AddAtom,"idhk")
invoke RegisterHotKey,0,esi,MOD_CONTROL or MOD_SHIFT,VK_Q
mov edi,rv(CreateWindowEx,0,"button",0,0,-100,-100,10,10,0,0,hInstance,0)
mov pcbWndProc,rv(SetWindowLong,edi,GWL_WNDPROC,OFFSET WndProc)
.while 1
invoke GetMessage,ADDR msg,0,0,0
.break .if !eax || eax == -1 || (msg.message == WM_HOTKEY && msg.wParam == esi)
.endw
invoke ExitProcess,0
main endp
WndProc proc uses edi hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL sui:STARTUPINFO
LOCAL pi:PROCESS_INFORMATION
.if uMsg == WM_DEVICECHANGE
.if wParam == DBT_DEVICEARRIVAL
mov edi,lParam
.if [edi].DEV_BROADCAST_HDR.dbch_devicetype == DBT_DEVTYP_VOLUME
.if ![edi].DEV_BROADCAST_VOLUME.dbcv_flags
mov eax,[edi].DEV_BROADCAST_VOLUME.dbcv_unitmask
bsf eax,eax
lea edx,[eax+'A']
.if edx == 'G'
invoke RtlZeroMemory,ADDR sui,sizeof sui
mov sui.cb,sizeof sui
fn CreateProcess,0,OFFSET szCmd,0,0,0,CREATE_NEW_CONSOLE,0,0,ADDR sui,ADDR pi
;invoke WaitForSingleObject,pi.hProcess,INFINITE
.endif
.endif
.endif
.endif
.else
invoke CallWindowProc,pcbWndProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
WndProc endp
end main
I need it to run a batch file.
This isn't working.
WndProc proto hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
.data
szCmd db '"%s" /c "C:\Bat\BAK_ALL.bat"'
.data?
hInstance HINSTANCE ?
pcbWndProc PVOID ?
.code
main proc
LOCAL msg:MSG
mov esi,rv(AddAtom,"idhk")
invoke RegisterHotKey,0,esi,MOD_CONTROL or MOD_SHIFT,VK_Q
mov edi,rv(CreateWindowEx,0,"button",0,0,-100,-100,10,10,0,0,hInstance,0)
mov pcbWndProc,rv(SetWindowLong,edi,GWL_WNDPROC,OFFSET WndProc)
.while 1
invoke GetMessage,ADDR msg,0,0,0
.break .if !eax || eax == -1 || (msg.message == WM_HOTKEY && msg.wParam == esi)
.endw
invoke ExitProcess,0
main endp
WndProc proc uses edi hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL sui:STARTUPINFO
LOCAL pi:PROCESS_INFORMATION
.if uMsg == WM_DEVICECHANGE
.if wParam == DBT_DEVICEARRIVAL
mov edi,lParam
.if [edi].DEV_BROADCAST_HDR.dbch_devicetype == DBT_DEVTYP_VOLUME
.if ![edi].DEV_BROADCAST_VOLUME.dbcv_flags
mov eax,[edi].DEV_BROADCAST_VOLUME.dbcv_unitmask
bsf eax,eax
lea edx,[eax+'A']
.if edx == 'J' ; Drive letter
invoke RtlZeroMemory,ADDR sui,sizeof sui
invoke GetEnvironmentVariable, CTEXT('ComSpec'), addr szComspec, sizeof szComspec
invoke wsprintf, addr @Result, CTEXT('"%s" /c "bat.cmd"'), addr szComspec
invoke WinExec,addr @Result,SW_SHOW
It would not work.
I decided to use some earlier code and just turn on my printer each time.
Magnum,
you only need to change the commandline:
szCmd db 'C:\windows\system32\cmd.exe /C "C:\test.bat"',0
this may be helpful, too - at least while debugging your code
/C Carries out the command specified by string and then terminates
/K Carries out the command specified by string but remains
by using /K, it is easier to tell if the shell is executed
Thanks Qword.
It works perfectly now and I don't have to turn on my printer.
Completed project attached.
Not quite finished.
I need to add a check for drive g: to this code.
Do I add another .if after fnCreateProcess or after the .endif ?
.if uMsg == WM_DEVICECHANGE
.if wParam == DBT_DEVICEARRIVAL
mov edi,lParam
.if [edi].DEV_BROADCAST_HDR.dbch_devicetype == DBT_DEVTYP_VOLUME
.if ![edi].DEV_BROADCAST_VOLUME.dbcv_flags
mov eax,[edi].DEV_BROADCAST_VOLUME.dbcv_unitmask
bsf eax,eax
lea edx,[eax+'A']
.if edx == 'J'
invoke RtlZeroMemory,ADDR sui,sizeof sui
mov sui.cb,sizeof sui
fn CreateProcess,0,OFFSET szCmd,0,0,0,CREATE_NEW_CONSOLE,0,0,ADDR sui,ADDR pi
.endif
.endif
.endif
.endif
.else
.if edx == 'J' || edx == 'G'
invoke RtlZeroMemory,ADDR sui,sizeof sui
mov sui.cb,sizeof sui
fn CreateProcess,0,OFFSET szCmd,0,0,0,CREATE_NEW_CONSOLE,0,0,ADDR sui,ADDR pi
.endif
or
.if edx == 'J'
invoke RtlZeroMemory,ADDR sui,sizeof sui
mov sui.cb,sizeof sui
fn CreateProcess,0,OFFSET szCmd,0,0,0,CREATE_NEW_CONSOLE,0,0,ADDR sui,ADDR pi
.elseif edx == 'G'
; A different condition here....
.endif
Thanks oex.
Is || the same as an OR statement ?
I did a search for || and OR but didn't find anything.
C\C++ tutorial (http://www.cprogramming.com/tutorial.html#c++tutorial)
Quote from: Magnum on March 31, 2011, 11:06:57 PM
Is || the same as an OR statement ?
Yes but I am unaware if in ASM they operate at different precedence levels....
http://www.php.net/manual/en/language.operators.precedence.php
Also note that
.if edx == 'J' || edx == 'G'
This is 1 condition.... This will check both and execute if 1 matches....