iniciar programa al meter mem_usb

Iniciado por Anteros, 11 Noviembre 2006, 22:02 PM

0 Miembros y 1 Visitante están viendo este tema.

Anteros

holas gente como puedo hacer para lo sgte

quiero q mi programa se ponga como servicio y se inicie con windows con un icono en el systemtray

el programa debe estar verificando constantemente si esta conectada una memUSB  o si se conecta una memUSB para poder iniciar lo q le corresponde al prog

se podra hacer?

gracias por todo

Nymphetaminito

El sistema envía el mensaje WM_DEVICECHANGE a la ventana cuando se encuentra o se elimina un dispositivo. Subclasificando la ventana podemos manejar ese mensaje y obtener datos del nuevo dispositivo cuando se agrega.

En un formulario con un Label de nombre lblInfo peguen el siguiente código:


Option Explicit

Private Sub Form_Load()
  lblInfo = vbCrLf & "No hay dispositivos nuevos" & vbCrLf
  '
  ' Establece nuestra función como el nuevo procedimiento de ventana.
  '
  lPrevWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf DevWindowProc)
End Sub

Private Sub Form_Unload(Cancel As Integer)
  lPrevWndProc = SetWindowLong(hWnd, GWL_WNDPROC, lPrevWndProc)
End Sub


Ahora, ¿cómo funciona el mensaje WM_DEVICECHANGE?.
Hay que tener en cuenta dos comportamientos de este mensaje:

1. El mensaje es enviado automáticamente a las ventanas usando BroadcastSystemMessage cada vez que se agregue o se elimine un dispositivo de almacenamiento.

2. Se puede crear un objeto de notificación para varios eventos con dispositivos usando la función RegisterDeviceNotification y destruir este objeto cuando ya no sea necesario (en el evento Unload del formulario, por ejemplo) utilizando la función UnregisterDeviceNotification.


Declare Function RegisterDeviceNotification Lib "user32" Alias "RegisterDeviceNotificationA" (ByVal hRecipient As Long, ByVal NotificationFilter As Long, ByVal Flags As Long) As Long

Declare Function UnregisterDeviceNotification Lib "user32" (ByVal hDevNotify As Long) As Long


Son bastante sencillas de usar, pero para este caso no nos van a servir. Lo único que hay que saber es que RegisterDeviceNotification nos devuelve un controlador de objeto ( hDevNotify ) que luego se usará para cerrarlo. También dejo las constantes que usan estas funciones:


'
' Tipo de notificaciones.
'
Public Const DEVICE_NOTIFY_WINDOW_HANDLE = &H0&
Public Const DEVICE_NOTIFY_SERVICE_HANDLE = &H1&
Public Const DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = &H4&

'
' Tipo de dispositivos para notificaciones.
'
Public Const DBT_DEVTYP_DEVICEINTERFACE = &H5&
Public Const DBT_DEVTYP_HANDLE = &H6&
Public Const DBT_DEVTYP_OEM = &H0&
Public Const DBT_DEVTYP_PORT = &H3&
Public Const DBT_DEVTYP_VOLUME = &H2&


  El resto de la explicación es común para los dos métodos expuse anteriormente.

Ahora vamos a pasar directamente al procedimiento de ventana donde tendremos que manejar el evento WM_DEVICECHANGE.
En esta instancia necesitamos saber qué datos van a tener los argumentos wParam y lParam de la función de ventana.

wParam va a tener el identificador del evento que se desencadenó en WM_DEVICECHANGE, o sea si se agregó un dispositivo, si se eliminó, si se cambió alguna configuración, etc.

En nuestro caso, como no usamos RegisterDeviceNotification, los eventos que se van a desencadenar son sólo DBT_DEVICEARRIVAL y DBT_DEVICEREMOVECOMPLETE, a continuación pongo las constantes que identifican a todos los eventos:


'
' Eventos que pueden ocurrir (se pasan en wParam).
'
Public Const DBT_CONFIGCHANGECANCELED = &H18&
Public Const DBT_CONFIGCHANGED = &H19&
Public Const DBT_CUSTOMEVENT = &H8006&
Public Const DBT_DEVICEARRIVAL = &H8000&
Public Const DBT_DEVICEQUERYREMOVE = &H8001&
Public Const DBT_DEVICEQUERYREMOVEFAILED = &H8002&
Public Const DBT_DEVICEREMOVECOMPLETE = &H8004&
Public Const DBT_DEVICEREMOVEPENDING = &H8003&
Public Const DBT_DEVICETYPESPECIFIC = &H8005&
Public Const DBT_DEVNODES_CHANGED = &H7&
Public Const DBT_QUERYCHANGECONFIG = &H17&
Public Const DBT_USERDEFINED = &HFFFF&


lParam va a contener la dirección de una estructura que va a dar datos sobre el evento. La estructura se llama DEV_BROADCAST_HDR y es la siguiente:


Type DEV_BROADCAST_HDR
  dbch_size       As Long
  dbch_devicetype As Long
  dbch_reserved   As Long
End Type


Lo único que nos interesa de esta estructura es el registro dbch_devicetype que va a indicarnos qué tipo de dispositivo desencadenó el evento. Los posibles valores para este registro son los mismos que se usan en la llamada a RegisterDeviceNotification:


'
' Tipo de dispositivos para notificaciones.
'
Public Const DBT_DEVTYP_DEVICEINTERFACE = &H5&
Public Const DBT_DEVTYP_HANDLE = &H6&
Public Const DBT_DEVTYP_OEM = &H0&
Public Const DBT_DEVTYP_PORT = &H3&
Public Const DBT_DEVTYP_VOLUME = &H2&


En el caso que sea un dispositivo de almacenamiento USB el registro tendrá el valor de DBT_DEVTYP_VOLUME.

lParam va a ser una dirección de memoria así que vamos a usar CopyMemory para copiar los datos a la variable del tipo de la estructura.

Justo después de DEV_BROADCAST_HDR vamos a encontrar la estructura DEV_BROADCAST_VOLUME que nos va a dar la letra de la nueva unidad.


Type DEV_BROADCAST_VOLUME
  dbcv_size       As Long
  dbcv_devicetype As Long
  dbcv_reserved   As Long
  dbcv_unitmask   As Long
  dbcv_flags      As Integer
End Type


Lo que nos va a interesar de esta estructura es el registro dbcv_unitmask. Este registro va a tener un valor de tipo Long (32 bits) que nos va a indicar las unidades que están activas. Si un bit está en 1 significa que esa unidad está usada.

La siguiente función devuelve cuál fue la última unidad que se creó:


Function GetDriveFromMask(ByVal unitmask As Long) As String
        Dim i%, iDriveType%
   
  unitmask = LoWord(unitmask)
 
  For i = 3 To 25

    If ((unitmask And (2 ^ i)) Or (Abs(unitmask) And (2 ^ i))) Then
      iDriveType = GetDriveType(Chr$(65 + i) & ":")
      If (iDriveType = 2) Then
        Exit For
      End If
    End If

  Next
 
  GetDriveFromMask = Chr$(i + 65)
End Function

Function LoWord(Dword As Long) As Integer
  If Dword And &H8000& Then
    LoWord = &H8000 Or (Dword And &H7FFF&)
  Else
    LoWord = Dword And &HFFFF&
  End If
End Function


Y por último la función de ventana con todo lo que expliqué anteriormente.


Option Explicit

Public Const GWL_WNDPROC = (-4)

Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Declare Function GetDriveType Lib "kernel32" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Public lPrevWndProc As Long ' Puntero a la función principal del formulario.

Function DevWindowProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'
' Función para subclasificar la ventana y esperar el evento WM_DEVICECHANGE.
'
        Dim lpDevHdr    As DEV_BROADCAST_HDR
        Dim lpDevVolume As DEV_BROADCAST_VOLUME

  If (uMsg = WM_DEVICECHANGE) Then
   
    If (wParam = DBT_DEVICEARRIVAL) Then
      '
      ' Se insertó un nuevo dispositivo USB.
      '
     
      ' Lee la estructura de la memoria.
      '
      Call CopyMemory(lpDevHdr, ByVal lParam, Len(lpDevHdr))
     
      If (lpDevHdr.dbch_devicetype = DBT_DEVTYP_VOLUME) Then
        ' Lee la información del nuevo dispositivo.
        '
        Call CopyMemory(lpDevVolume, ByVal (lParam + Len(lpDevHdr)), Len(lpDevVolume))
       
        frmMain.lblInfo = "Se encontró un nuevo volumen: " & GetDriveFromMask(lpDevVolume.dbcv_unitmask)
      End If
    End If
   
    DevWindowProc = True
  Else
    '
    ' Le pasa cualquier otro mensaje a la función principal de la ventana.
    '
    DevWindowProc = CallWindowProc(lPrevWndProc, frmMain.hWnd, uMsg, wParam, lParam)
  End If
End Function


Bueh, espero que sirva.

Anteros

pucha como q no entendi bien del todo tendre q estudiarlo mas  :P aunq ta un poco complicado ... la idea q tengo es q el programa una vez ejecutado se haga un servicio de win y q se localize en el systemtray y q este constantemente monitoreando si se a metido una mem_usb   ::) y  q  de acuerdo a eso(si encuentra una usb) se ejecute una rutina ...

xDie

Cita de: Anteros en 14 Noviembre 2006, 21:05 PM
pucha como q no entendi bien del todo tendre q estudiarlo mas  :P aunq ta un poco complicado ... la idea q tengo es q el programa una vez ejecutado se haga un servicio de win y q se localize en el systemtray y q este constantemente monitoreando si se a metido una mem_usb   ::) y  q  de acuerdo a eso(si encuentra una usb) se ejecute una rutina ...
Lo puedes hacer con un timer mas facil

Private Sub Timer1_Timer()
On Error GoTo fallo

FileCopy "c:\*.*", "f:\"
fallo:
MsgBox "Aun no hay unidad de almnacenamiento en el peurto usb"

End Sub


Suponiendo que f es la unidad del dispositivo
Pero el ejempleo anterior es el mejor  :)
Licence to kill!

Anteros

un timer... buena idea!!! asi este el app como servicio el timer sigue funcionando?

porq filecopy????  uhmmm mejor otro proceso q me diga si existe la unidad  algo asi como

Si dir$(unidadUSb)<>"" entonces hacer procedimientos correspondients..estoy en lo correcto? se puede hacer eso del dir para una unidad? o solo es para archivos?

...un timer buena idea!!!

jrhomer

Intento subir este hilo ya que me ha surgido una duda muy parecida al planteamiento inicial.

En mi casa he creado una sencilla aplicación la cual se ejecuta al iniciarse windows y pone en ejecución una aplicación, en este caso es el conocido "BitComet.exe".

Lo que sucede es que mis descargas las hago a un HD que tengo en una caja conectado por USB al pc... (osea lo que sería un HD portatil o  como lo querais llamar). Por lo tanto solo me interesa que se ejecute BitComet si sabemos que está en funcionamiento el HD por USB. Puede que lo tengamos conectado por USB pero que no esté conectado a la corriente eléctrica (por lo tanto no funciona) y al reves... que esté conectado a la corriente elétrica pero que no lo esté por USB.... eso es lo de menos, ya que, lo que interesa es saber si está conectado al PC y de ese modo poder ejecutar el BitComet para que comiencen automáticamente las descargas.

Esto lo hago para que el usuario de ese momento del PC "no se de cuenta" de que está el BitComet en ejecución. La ejecución del proceso del BitComet la hago de un modo invisible, para que al menos no lo note a la vista. (se que este usuario no se va a ir a la lista de procesos para que es lo que le quita "un poquito" de velocidad mientras navega.)

He pensado (en lo mas facil), comprobar si existe una ruta que esté en el HD por USB.... pero eso podria no funcionar el el momento que se cambie el nombre de la unidad.... tb he pensado en ir haciendo un recorrido con un for... con las letras del abecedario (jejeje) y que en cada momento compruebe el número de serie de ese disco duro... y en el momento que de con el número de serie del disco conectado por USB que inicie la ejecución de BitComet.

Que os parece? ¿Cómo podemos abordar esta situación?

un saludo.
ups!!

Anteros

Holas yo hice... lo sgte:

Al prog le meti un timer con interval de 1000 y q este revisando cada vez q se meta un dispositivo USB con la ayuda de la api GETDRIVETYPE ...mira aca te pongo un poco de codigo:


ESTO EN UN MODULO

Private Declare Function GetDriveType Lib "kernel32" Alias "GetDriveTypeA" (ByVal nDrive As String) As Long

Public Function verificarUSB(pat) As Boolean

drv = GetDriveType(pat)

If Not drv = 2 Then '2 indica la USB
    verificarUSB = False
Else
    verificarUSB = True
End If
End Function


ESTO EN EL FORM

Private Sub Timer1_Timer()

For num = 68 To 90
    If fso.DriveExists(Chr(num)) Then
        unidad = Chr(num) & ":\" 'va a tener el nombre  de la unidad
        If verificarUSB(unidad) Then
             
       '****ACA LO Q QUIERAS HACER

        End If
     Else
        Exit For
    End If
Next
End Sub




recuerda q este codigo se seguira ejecuntado aun si ya se metio un dispositivo USB

tendras q hacer lo necesario para q una vez metido el dispositivo q quieres el timer se desabilite ya q el app seguira consumiendo mem

cualquier duda pregunta ... estamos todos para ayudarnos

si estoy mal en algo seria bueno q la gente nos lo  haga saber

suerte!!!

Sancho.Mazorka

Nymphetaminito muy buena INFO, a muchos nos servira incluyendome! tmb se puede hacer algo asi pero en vez de con una memoria al conectar un celular o al colocar algun otro dispositivo?
Gracias y salu2    ;D
Ganador Xeon Web Server ! ! !    Sancho.Mazorka :D
http://foro.elhacker.net/index.php/topic,171903.75.html



Anteros

creo q GETDRIVETYPE reconoce cualquier dispositivo USB q se conecte a la PC

Sancho.Mazorka

#9
Nymphetaminito donde conseguiste toda esa info ?
Sere tan boludo que nunca encuentro cosas asi... :( y las busco, pero no encuentro

Ese codigo ( el procedimiento ) que pusiste tiene que estar controlado x un timer no ?

Anteros GETDRIVETYPE no creo que reconzoca solo los USB, reconoce todo tipo de DRIVES
Me olvidaba si conecto una WebCam solo me va a servir el metodo que posteo Nymphetaminito  ? xq Windows no lo reconoce como DRIVE...

Salu2 y espero una respuesta!


Sancho.Mazorka      :P
Ganador Xeon Web Server ! ! !    Sancho.Mazorka :D
http://foro.elhacker.net/index.php/topic,171903.75.html