Perform an action when a specific USB device is attached?

Just starting out? Need help? Post your questions and find answers here.
jak64
Enthusiast
Enthusiast
Posts: 625
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Re: Perform an action when a specific USB device is attached?

Post by jak64 »

Hello,
I'm looking for A to J but you know it's for a 9 year old visually impaired kid's computer and he won't put anything else on his computer.
ZX80
Enthusiast
Enthusiast
Posts: 365
Joined: Mon Dec 12, 2016 1:37 pm

Re: Perform an action when a specific USB device is attached?

Post by ZX80 »

@jak64.

Okay. Do not rush. Now I have to go.
And all the changes will be only tomorrow (at best case).

added:
Yes I know. All the same, it is necessary to provide for different cases for universality.
jak64
Enthusiast
Enthusiast
Posts: 625
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Re: Perform an action when a specific USB device is attached?

Post by jak64 »

Hello ZX80,

Here is the information requested:

1) E:\MesFilms.exe (or D:\ or F:\...)
2) MesFilms (1 single Windows window in my program)
3) HDD
4) FILMS
5) NTFS
6) 9E9C-9D6C
ZX80
Enthusiast
Enthusiast
Posts: 365
Joined: Mon Dec 12, 2016 1:37 pm

Re: Perform an action when a specific USB device is attached?

Post by ZX80 »

Hello, jak64.

About the second point: If I understand correctly, this is the title only (no window class).
Okay. Hope your program has a unique title text. That is, there are no more windows with the same title in the system. Didn't do any additional testing. Hope this will be enough.

There are many places in the code where the 'Debug' is used. If this bothers you, then you can painlessly remove them all. But I put a lot of them so that you can see what is happening.

Test the code with different disks, flash drives. Try using them at the same time and see if the target is correctly defined. You can also pre-copy your program to each of them, using the same path. In this case, to the root of the disk. You no longer have to worry about guessing what letter your target drive will be. It's not need (only the path to the program). You can also experiment with deliberately changing the target letter.

Well...
Hope this helps you. Just copy and run this code. I have already entered your information in it.
Also I'm waiting for your report if it works or not for you.

Code: Select all

Structure DiskInfo
  type.i
  type_str.s
  DriveLetter.s
  FileSystem.s{256}
  VolName.s{256}
  Serial.l
  Serial_str.s
EndStructure

Enumeration #PB_EventType_FirstCustomValue
  #EventType_Attach
  #EventType_Detach
EndEnumeration

Enumeration
  #Window_0
  #Editor
EndEnumeration

Global Dim AttachedDrives.DiskInfo(25)
Global TargetDrive.DiskInfo
Global testdisk.DiskInfo
Global TimeOUT = #True, Eject = #False
Global AllDrive$, Old_DriveLetter$
#time_out  = 1000
#separator = "------------"

Define path$   = "\MesFilms.exe"  ; relative path (without drive letter / without root), because the drive letter can change over time.
Define ptitle$ = "MesFilms"       ; put all or part of the window title here (my own program).

With TargetDrive
  \type_str   = "HDD"       ; or FLASH
  \VolName    = "FILMS"     ; check it in the drive properties window from "My Computer"
  \FileSystem = "NTFS"      ; check it in the drive properties window from "My Computer"
  \Serial_str = "9E9C-9D6C" ; check it in the command line by selecting the desired drive and running the 'dir' command.
  ; you will find it in the listing. The serial number is assigned To the drive when it is formatted.
  ; or you can see all the data of the desired disk in the debug window !!!
EndWith

Macro GetTimeStamp
  FormatDate("%dd-%mm-%yyyy   %hh:%ii:%ss", Date()) + #CRLF$
EndMacro

Macro Writelog
  AddGadgetItem(#Editor, -1, logtxt)
  If GetWindowLongPtr_(GadgetID(#Editor), #GWL_STYLE) & #WS_VSCROLL
    SendMessage_(GadgetID(#Editor), #EM_SCROLL, #SB_BOTTOM, 0)
  EndIf
EndMacro

Macro oCheck
  IsTarget = #False
  If testdisk\type_str=TargetDrive\type_str And testdisk\VolName=TargetDrive\VolName And testdisk\FileSystem=TargetDrive\FileSystem And testdisk\Serial_str=TargetDrive\Serial_str
    IsTarget = #True
  EndIf
EndMacro

Macro EjectDrive
  Debug testdisk\type_str + " drive was disconnected: " + testdisk\DriveLetter
  oCheck
  If IsTarget = #True
    If PostEvent(#EventType_Detach) = 0
      Debug "Failed to send message to main thread  :("
    EndIf
  EndIf
  AllDrive$ = RemoveString(AllDrive$, Old_DriveLetter$)
  Debug #separator
EndMacro

Macro GetVolumeInformation
  If scan = 0
    ClearStructure(@testdisk, DiskInfo)
    If Mask = 0
      i = 1
      testdisk\DriveLetter = "A:"
    Else
      For i = 1 To 26
        If Mask & 1
          Break
        EndIf
        Mask = Mask >> 1
      Next
    EndIf
    testdisk\DriveLetter = Chr(i + 64)+ ":"
    DriveLetter = testdisk\DriveLetter + "\"
    i-1
  EndIf
  
  If action = #DBT_DEVICEARRIVAL
    testdisk\type = GetDriveType_(DriveLetter)
    If testdisk\type = 2
      testdisk\type_str = "FLASH"
    ElseIf testdisk\type = 3
      testdisk\type_str = "HDD"
    EndIf

    GetVolumeInformation_(@DriveLetter, @testdisk\VolName, 255, @testdisk\Serial, 0, 0, @testdisk\FileSystem, 255)
    testdisk\Serial_str = RSet(Hex(PeekW(@testdisk\Serial + 2) & $FFFF), 4, "0") + "-" + RSet(Hex(PeekW(@testdisk\Serial) & $FFFF), 4, "0")
    If scan = 0 : CopyStructure(@testdisk, @AttachedDrives(i), DiskInfo) : EndIf
  EndIf
EndMacro

Procedure CallBack_NewDevice(WindowID, Message, wParam, lParam)
	Protected *db.DEV_BROADCAST_HDR
	Protected *dbv.DEV_BROADCAST_VOLUME
	Protected Mask.l
	Protected Result, IsTarget, action, scan=0, i
	Protected.s DriveLetter, logtxt
	
	Result = #PB_ProcessPureBasicEvents
	Select Message

		Case #WM_DEVICECHANGE
			If wParam = #DBT_DEVICEARRIVAL
				*db = lParam : action = #DBT_DEVICEARRIVAL
				If *db\dbch_devicetype = #DBT_DEVTYP_VOLUME
				  *dbv = lParam : Mask = *dbv\dbcv_unitmask : GetVolumeInformation : oCheck
				  Debug "action:  connect drive"
				  
				  With testdisk
				    If IsTarget = #True
				      If TimeOUT = #False
				        If Eject = #True
				          RemoveWindowTimer(#Window_0, 100) : Eject = #False
				        EndIf
				        If \DriveLetter <> TargetDrive\DriveLetter
				          If FindString(AllDrive$, TargetDrive\DriveLetter) = 0
				            Goto label
				          EndIf
				          Debug "***  target drive letter changed to: " + \DriveLetter
				          Debug Old_DriveLetter$ + "  =>  " + \DriveLetter
				          Debug #separator
				          logtxt = GetTimeStamp + "target device changed the drive letter to: (" + \DriveLetter + ")" + #CRLF$ + Old_DriveLetter$ + "  =>  " + \DriveLetter + #CRLF$
				          AllDrive$ = RemoveString(AllDrive$, Old_DriveLetter$) : AllDrive$ + \DriveLetter
				          TargetDrive\DriveLetter = \DriveLetter
				          Writelog
				        EndIf
				      Else
				        label:
				        Debug "New " + \type_str + " drive connected: " + \DriveLetter
				        Debug "FileSystem:  " + \FileSystem
				        Debug "VolName:  " + \VolName
				        Debug "Serial:  " + \Serial_str
  			        Debug "" : Debug "               caught !!!" : Debug ""
  			        TargetDrive\DriveLetter = \DriveLetter
  			        AllDrive$ + \DriveLetter
  			        If PostEvent(#EventType_Attach) = 0
		    	        Debug "Failed to send message to main thread  :("
			            Debug #separator
			          EndIf
				      EndIf
				    Else
				      If TimeOUT = #False
				        If Eject = #True
				          RemoveWindowTimer(#Window_0, 100) : Eject = #False
				        EndIf
				        If \DriveLetter <> Old_DriveLetter$
				          If FindString(AllDrive$, Old_DriveLetter$) = 0
				            Goto label2
				          EndIf
				          Debug "***  drive letter changed to: " + \DriveLetter
				          Debug Old_DriveLetter$ + "  ->  " + \DriveLetter
				          AllDrive$ = RemoveString(AllDrive$, Old_DriveLetter$)
				          AllDrive$ + \DriveLetter
				        EndIf
				      Else
				        label2:
  				      Debug "New " + \type_str + " drive connected: " + \DriveLetter
	  			      Debug "FileSystem:  " + \FileSystem
		  		      Debug "VolName:  " + \VolName
		  		      Debug "Serial:  " + \Serial_str
		  		      AllDrive$ + \DriveLetter
			  	    EndIf
			  	    Debug #separator
				    EndIf
				  EndWith
				EndIf
				
			ElseIf wParam = #DBT_DEVICEREMOVECOMPLETE
				*db = lParam : action = #DBT_DEVICEREMOVECOMPLETE
				If *db\dbch_devicetype = #DBT_DEVTYP_VOLUME
				  *dbv = lParam : Mask = *dbv\dbcv_unitmask : GetVolumeInformation
				  Old_DriveLetter$ = testdisk\DriveLetter
				  Debug "action:  eject drive"
				  
				  If AttachedDrives(i)\DriveLetter <> ""
				    CopyStructure(@AttachedDrives(i), @testdisk, DiskInfo)
				    ClearStructure(@AttachedDrives(i), DiskInfo)
	  	      TimeOUT = #False : Eject = #True
  		      AddWindowTimer(#Window_0, 100, #time_out)
				  Else
				    Debug "Unknown USB drive was disconnected: " + testdisk\DriveLetter
				    Debug #separator
				  EndIf
				EndIf
			EndIf

	EndSelect

	ProcedureReturn Result
EndProcedure

Procedure target_search()
  Protected Mask.l = GetLogicalDrives_()
  Protected Result = #False, i, action = #DBT_DEVICEARRIVAL
  Protected scan = 1, type, IsTarget
  Protected DriveLetter.s

  For i = 1 To 26
    If Mask & 1
      testdisk\DriveLetter = Chr(i + 64)+ ":"
      DriveLetter = testdisk\DriveLetter + "\"
      type = GetDriveType_(DriveLetter)
      If type = 2 Or type = 3
        GetVolumeInformation
        
        With testdisk
          Debug \type_str + " drive connected: " + \DriveLetter
			    Debug "FileSystem:  " + \FileSystem
			    Debug "VolName:  " + \VolName
			    Debug "Serial:  " + \Serial_str
          Debug ""

          CopyStructure(@testdisk, @AttachedDrives(i-1), DiskInfo)
          AllDrive$ + \DriveLetter
          If Result = #False
            oCheck
            If IsTarget = #True
              TargetDrive\DriveLetter = \DriveLetter
              Result = #True
            EndIf
			    EndIf
			  EndWith
      EndIf
    EndIf
    Mask = Mask >> 1
  Next
  Debug "All drives:   " + AllDrive$
  Debug "=============================="
  Debug ""
  ProcedureReturn Result
EndProcedure

Procedure FindWin(Title$) ;code by RASHAD
  text$ = Space(#MAX_PATH)
  Repeat
    hwnd = FindWindowEx_(0, hwnd, 0, 0)     
    GetWindowText_(hwnd, @Text$, #MAX_PATH)
    If FindString(LCase(Text$), LCase(Title$), 1) <> 0
       findwin = hWnd
       Break
     EndIf
     x + 1
  Until findwin Or x > 1000
  ProcedureReturn findwin
EndProcedure


Define.i Event, Exit, Result, hWnd
Define.s logtxt
Define my_app$

hWnd = OpenWindow(#Window_0, 0, 0, 500, 300, "Detect events of a specific USB device", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If hWnd
  EditorGadget(#Editor, 10, 10, WindowWidth(#Window_0)-20, WindowHeight(#Window_0)-20)
  logtxt = GetTimeStamp + "watchdog started" + #CRLF$
  If target_search() = #True
    Debug "target device is already connected (" + TargetDrive\DriveLetter + ")"
    logtxt = logtxt + "target device is already connected (" + TargetDrive\DriveLetter + ")" + #CRLF$
    AddWindowTimer(#Window_0, 101, #time_out)
  Else
    logtxt = logtxt + "target device not found" + #CRLF$
  EndIf
  Writelog
  
  SetWindowCallback(@CallBack_NewDevice(), #Window_0)

  
  Repeat
    Event = WaitWindowEvent()

    Select Event
      Case #PB_Event_CloseWindow
        Exit = #True
        
      Case #PB_Event_Timer
        If EventTimer() = 100
          TimeOUT = #True
          RemoveWindowTimer(#Window_0, 100)
          If Eject = #True
            Eject = #False
            EjectDrive
          EndIf
        Else
          RemoveWindowTimer(#Window_0, 101)
          If FindWin(ptitle$)
            Debug "... and your program is already running. Do nothing."
            Debug #separator
          Else
            Debug "Do you want to run the program ?"
            Result = MessageRequester("Info", "The target device has been detected."+#CRLF$+"Would you like to launch your program now?", #PB_MessageRequester_YesNo)
            If Result = #PB_MessageRequester_Yes
              Debug "Your answer:  YES"
              If PostEvent(#EventType_Attach) = 0
                Debug "Failed to send message to main thread  :("
                Debug #separator
              EndIf
            Else
              Debug "Your answer:  No"
              Debug #separator
            EndIf
          EndIf
        EndIf
        
        
      Case #EventType_Attach
        SendMessage_(#HWND_BROADCAST, #WM_SYSCOMMAND, #SC_HOTKEY, hWnd)
        my_app$ = TargetDrive\DriveLetter + path$
        If Result = #PB_MessageRequester_Yes
          Result = #False
        Else
          logtxt = GetTimeStamp + "target device has been connected (" + TargetDrive\DriveLetter + ")" + #CRLF$ : Writelog
          Debug "Sleep_(" + Str(#time_out) + ")"
          Sleep_(#time_out)
        EndIf

        If FindWin(ptitle$) ; In case the program is already running from another place
          Debug "... and your program is already running. Do nothing."
        Else
          If FileSize(my_app$) = -1
            Debug "file  " + #DQUOTE$ + my_app$ + #DQUOTE$ + "  was not found  :("
          Else
            Debug "launching...  " + #DQUOTE$ + my_app$ + #DQUOTE$
            RunProgram(my_app$)
          EndIf
        EndIf
        Debug #separator

      Case #EventType_Detach
        SendMessage_(#HWND_BROADCAST, #WM_SYSCOMMAND, #SC_HOTKEY, hWnd)
        logtxt = GetTimeStamp + "target device has been disconnected (" + TargetDrive\DriveLetter + ")" + #CRLF$ : Writelog
        TargetDrive\DriveLetter = Str(#Null)

    EndSelect
  Until Exit
EndIf
Good luck!

P.S. In the future, you can easily change this code to hide the program window in the system tray, if needed.
jak64
Enthusiast
Enthusiast
Posts: 625
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Re: Perform an action when a specific USB device is attached?

Post by jak64 »

Hello,
thank you for your work, it works but I think I expressed myself badly.

I would like the program that is on the HDD to run automatically as soon as the HDD disk is connected (without launching any other program and without doing anything else, nothing, nothing at all).
But you have to launch your program for it to work, in this case, if you have to run a program, you might as well run the program directly on the HDD.
AZJIO
Addict
Addict
Posts: 2175
Joined: Sun May 14, 2017 1:48 am

Re: Perform an action when a specific USB device is attached?

Post by AZJIO »

Haha, even if you write 2000 lines of code, it still won't run. You should have discussed in your topic, since this topic has a different focus - the reaction to connecting a flash drive. And your topic is how to force a file to run from a USB flash drive when it is inserted. You have already been told that this is not possible.
jak64
Enthusiast
Enthusiast
Posts: 625
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Re: Perform an action when a specific USB device is attached?

Post by jak64 »

Ok, thanks but I still learned some things with the ZX80 code, so it's not lost (for me anyway)
Marc56us
Addict
Addict
Posts: 1600
Joined: Sat Feb 08, 2014 3:26 pm

Re: Perform an action when a specific USB device is attached?

Post by Marc56us »

I said it :wink:
https://www.purebasic.fr/english/viewto ... 00#p581100
See sample
https://albertassaad.medium.com/know-if ... 177758cf73
Just fill "actions" tab with your program

That said, I tried to do it but my PC doesn't show anything in the log when I insert a key. But I've changed it so much since I got it that I probably disabled too many things.
In this example it creates a log filter, but in the possible actions there is also launch a program. It is enough (to try) to launch your program on the key. If it is not there because it is another key, nothing will happen.
:wink:
ZX80
Enthusiast
Enthusiast
Posts: 365
Joined: Mon Dec 12, 2016 1:37 pm

Re: Perform an action when a specific USB device is attached?

Post by ZX80 »

@jak64

You are welcome.
I have been asking you about it from the very beginning.
I think it's possible, but you have to understand that the program that monitors usb connections must be running all the time. Watch dog in the background. Does it suit you?
here.
AZJIO
Addict
Addict
Posts: 2175
Joined: Sun May 14, 2017 1:48 am

Re: Perform an action when a specific USB device is attached?

Post by AZJIO »

ZX80
Your code is not installed by itself and is not added to autostart. And what you gave I gave a long time ago, right after your post. But even when you do everything, I will not be surprised that you will be told that it does not work.
Axolotl
Addict
Addict
Posts: 830
Joined: Wed Dec 31, 2008 3:36 pm

Re: Perform an action when a specific USB device is attached?

Post by Axolotl »

Hey jak64,
i think all the programming tricks have been shown here by the professionals.
More info on this topic: you can enter the following in your favorite search engine "autorun and autoplay".
There are many pages explaining how, where, and what the so-called removable devices are all about.
Good luck.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
jak64
Enthusiast
Enthusiast
Posts: 625
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Re: Perform an action when a specific USB device is attached?

Post by jak64 »

Hi Axolotl

Tank you
ZX80
Enthusiast
Enthusiast
Posts: 365
Joined: Mon Dec 12, 2016 1:37 pm

Re: Perform an action when a specific USB device is attached?

Post by ZX80 »

AZJIO,

I assumed that my resident program would be launched along with the start of the operating system. Yes, I also thought about setting the registry flag - "run at the next OS boot". And every time you run the watchdog (my prog), install it again. Thus, it turns out that we need to run the watchdog program only once. And then everything will be done in a cycle automatically. Only there is a condition that the watchdog program is always available. That is, on some section of the client machine. I don't understand what's wrong with doing it this way.
But even when you do everything, I will not be surprised that you will be told that it does not work.
I already understood it. Large bold letters and red link color as a consequence. Yes, everything has a reason. I know it's not necessary to do this. Sorry. Red is the admin color. Not for the average user. This is a good tone in other forums.

offtopic:
I also suffer with my eyes(never said it here). And I wanted to show solidarity with the guy for whom this was done. Also in one of the topics jak64 (I'm already confused) said that he was already many years old. And this also played an important role.
Well... Still, it was an exciting journey. And there are many uses for this. For example, protecting a program with an iron key. I understand that in this form it looks childish. However, this is only one of the options.
In any case, if at least one person will use it, then everything was not in vain.


@jak64
I have nothing more to offer you. It's true. I'm very sorry.

That's all.
jak64
Enthusiast
Enthusiast
Posts: 625
Joined: Sat Aug 15, 2020 5:02 pm
Location: Ciboure (France)

Re: Perform an action when a specific USB device is attached?

Post by jak64 »

Hello ZX89,
Thank you for all you have done, it was very kind of you to take the time to try to help me.
Good continuation and see you soon to give me other advice on lots of subjects, there is so much to learn and I love using Purebasic.
ZX80
Enthusiast
Enthusiast
Posts: 365
Joined: Mon Dec 12, 2016 1:37 pm

Re: Perform an action when a specific USB device is attached?

Post by ZX80 »

Hello, jak64.

I'll tell you a secret: each hard drive has a mini OS. Do not tell anyone... tsss... be quiet :mrgreen:
One part of the firmware is stored in a chip, and the other on pancakes. At least at Seagate it is. You can connect to the disk via arduino and give commands to it. The hard disk has a separate service connector consisting of four pins (especially for these purposes). I did this in the terminal program 'putty' with my old hard drive (5.25 inch disk). For research purposes only. Maybe this info will be a clue for you. But I have no idea how can this info be applied to your task. And... is it even possible? Please don't ask me about it. I also do not recommend you to do this and just forget it. This is very dangerous and you need to understand what you are doing. Otherwise, you will not even have time to blink an eye as you kill your hard drive. To do this, just enter the wrong command.
Try reading about mbr, partition table, etc. This information is outdated these days, but it's interesting to know how it works anyway.

Another variant. Perhaps, your task can be done by editing the driver. But then you will lose the signature and trust of the system. For 64-bit systems, this is 100% true! Since they are very sensitive to the absence of a signature.
I'm not helping you here either. These are just thoughts spoken out loud.


P.S. Nobody said it would be easy if you follow all your desires. You need to understand and accept some limitations. And come to a compromise solution.
Some members will say it's trolling. And they will be right, but only slightly. :D
However, this post contains some useful information.
Post Reply