Hola a tod@s...por favor, quisiera que me ayuden con los siguiente: Cómo abrir un perfil específico google desde un botón con Visual Basic; uso este código pero sólo abre el perfil por defecto, supongo que me falta algún argumento...
Private Sub Command1_Click()
Shell "C:\Program Files\Google\Chrome\Application\chrome.exe", vbNormalFocus
End Sub
Hola!
Revisa éste post: https://superuser.com/questions/377186/how-do-i-start-chrome-using-a-specified-user-profile (https://superuser.com/questions/377186/how-do-i-start-chrome-using-a-specified-user-profile)
Saludos!
Cita de: MCKSys Argentina en 27 Julio 2021, 19:44 PM
Hola!
Revisa éste post: https://superuser.com/questions/377186/how-do-i-start-chrome-using-a-specified-user-profile (https://superuser.com/questions/377186/how-do-i-start-chrome-using-a-specified-user-profile)
Saludos!
ya he intentado con el argumento --user-data-dir= pero no ha funcionado...para medio resolver lo que hice fue desde un botón abrir un archivo .bat el cual contiene la instrucción para abrir el perfil requerido y (que capricho!!) en el archivo .bat si funciona ese argumento
esto es lo que usé en el botón de visual basic:
Private Sub Command1_Click()
Shell "C:\Users\yuner\Desktop\Perfiles\P1.bat"
End Sub
esto es lo que use en el archivo .bat:
start chrome.exe --user-data-dir="C:\Users\yuner\AppData\Local\Google\Chrome\User Data\Profile 1"
Tendrías que poner la sentencia exacta que no te funciona para revisarlo, supongo que no estás poniendo o escapando las comillas, lo siguiente debería funcionar:
Private Sub Command1_Click()
Shell "C:\Program Files\Google\Chrome\Application\chrome.exe --profile-directory=""Profile 1""", vbNormalFocus
End Sub
- Para escapar las comillas se deben poner dos veces
Cita de: EdePC en 27 Julio 2021, 23:00 PM
Tendrías que poner la sentencia exacta que no te funciona para revisarlo, supongo que no estás poniendo o escapando las comillas, lo siguiente debería funcionar:
Private Sub Command1_Click()
Shell "C:\Program Files\Google\Chrome\Application\chrome.exe --profile-directory=""Profile 1""", vbNormalFocus
End Sub
- Para escapar las comillas se deben poner dos veces
Diste en el clavo..eran las comillas...ahora en el caso de tener varios perfiles abiertos al mismo tiempo, como se haría para cerrar de forma individual cada perfil??...
Siguiendo el código facilitado por EdePC, he armado lo siguiente para abrir varios perfiles dando un lapso de 5 segundos entre las aperturas de los mismos:
Option Explicit
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Sub Command1_Click()
'abrir el perfil 1
Shell "C:\Program Files\Google\Chrome\Application\chrome.exe --profile-directory=""Profile 1""", vbNormalFocus
'esperar 5 segundos
Sleep 5000
'abrir el perfil 2
Shell "C:\Program Files\Google\Chrome\Application\chrome.exe --profile-directory=""Profile 2""", vbNormalFocus
'esperar 5 segundos
Sleep 5000
End Sub
pero no se como cerrar los perfiles uno a uno...
Cita de: yunernunez en 28 Julio 2021, 19:50 PM
pero no se como cerrar los perfiles uno a uno...
Hola!
En vez de usar Shell podrías usar la API CreateProcess para obtener el pid del proceso del navegador y luego cerrarlo (junto con los procesos "hijos", ya que cada tab crea un proceso nuevo).
Busca en inet cómo usar dicha API y cómo terminar un proceso y sus "hijos" (usando API's también).
Saludos!
Ahí ya lo complicas bastante porque en realidad Shell si hace su trabajo y devuelve el PID que deberías usar para cerrar el proceso PERO Chrome administra sus propios procesos y el PID original ya ni va ha existir después.
En circunstancias normales esto debería funcionar:
Dim pid As Double
pid = Shell("C:\Program Files\Google\Chrome\Application\chrome.exe --profile-directory=""Profile 1""", vbNormalFocus)
Shell "TaskKill /Pid " & pid
- Pero no funciona porque Chrome administra sus propios procesos, es decir, el primer Shell llama a Chrome y recibe el PID pero luego el propio Chrome abre otros procesos con varios PID y el PID original se cierra solo.
Incluso si intentas capturar los procesos en un Proceso Padre no funciona porque Chrome recicla sus procesos activos haciendo imposible saber por ahí cual es el PID del proceso nuevo, y si cierras el proceso padre, cierras todo el Chrome XD
Tampoco veo nada significante en la línea de comandos de los procesos creados para identificar a que Perfil pertenece, habrá que pensar en otra cosa
Gracias MCKSys Argentina y EdePC me han orientado muchísimo..seguiré investigando
chicos pues he seguido buscando como cerrar un perfil chrome desde visual basic y hasta los momentos no he encontrado una respuesta (o mejor decir: un código) así que pensé en una "solución gráfica", la idea es cerrar el perfil por medio de un clic en la X de la ventana del perfil. Se que hay softwares autoclickers que se programan por medio de coordenadas en pantalla, el detalle es que tendría que ejecutar dos programas (el visual basic para abrir el perfil y el autoclicker para cerrarlo) y no esa no es la idea....buscando me encontré con este código que creo hace clic en las coordenadas dadas pero no lo comprendo, pudiera alguien explicarme como usarlo?
moverlo con la api SetCursorPos X, Y
Private Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As Long
y con este api es para forzar el click
Private Declare Sub mouse_event Lib "USER32"(ByVal dwFlags As Long, ByVal dx As Long,ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)
estas son las vanderas
Private Const MOUSEEVENTF_LEFTDOWN = &H2
Private Const MOUSEEVENTF_LEFTUP = &H4
y esto es para que presione y levante el click
mouse_event(MOUSEEVENTF_LEFTDOWN, X, Y, 0, 0)
mouse_event(MOUSEEVENTF_LEFTUP, X, Y, 0, 0)
Hola, lo que yo haría en tu caso si es que no fuese posible lograr lo que querés desde visual basic, usaría un lenguaje auxiliar, por lo que seguiría usando visual basic pero con la ayuda de otro lenguaje que si pueda hacer esa operación.
El método primero sería saber que lenguaje puede hacerlo, por ejemplo Python, C, C++, Powershell (aunque este último no sea un lenguaje pero puede tener posibles funciones) etc., luego crear el código que cumpla la función necesaria, entonces teniendo eso listo, podrías poner ese mismo código dentro de tu código vb y cuando haga falta ese código se copié por ejemplo en un directorio temporal de Windows creando un archivo para ejecutar las instrucciones y luego se borre o se borre cuando sea necesario.
En el caso de ser un programa ejecutable de por ejemplo un programa compilado como C++, se podría codificarlo en base64 y guardarlo dentro de tu código de vb, luego cuando se lo necesite usar, entonces se decodifica creando un archivo/programa ejecutable en algún directorio que puede ser en el mismo directorio dónde está tu script o en otro, por ejemplo en el directorio de archivos temporales de Windows.
Tal vez te preguntes si eso funcionaria y la respuesta es sí porque lo que un lenguaje no pueda hacer, lo hará otro que sí pueda, solamente tiene que llamar a ese otro código/programa, y el tema podríamos decir más complicado y el que más hay que tener en cuenta es el tema de la sincronización, los dos tienen que estar sincronizados y eso ya lo ves vos cómo hacerlo, podes hacerlo por ejemplo mediante archivos de texto o archivos de configuración ini, mientras uno escribe la información, el otro la lee, o hasta incluso usar sockets para la comunicación, yo en mis épocas he creado métodos como éstos y me han funcionado perfectamente.
Saludos
Cita de: Danielㅤ en 30 Julio 2021, 16:24 PM
Hola, lo que yo haría en tu caso si es que no fuese posible lograr lo que querés desde visual basic, usaría un lenguaje auxiliar, por lo que seguiría usando visual basic pero con la ayuda de otro lenguaje que si pueda hacer esa operación.
El método primero sería saber que lenguaje puede hacerlo, por ejemplo Python, C, C++, Powershell (aunque este último no sea un lenguaje pero puede tener posibles funciones) etc., luego crear el código que cumpla la función necesaria, entonces teniendo eso listo, podrías poner ese mismo código dentro de tu código vb y cuando haga falta ese código se copié por ejemplo en un directorio temporal de Windows creando un archivo para ejecutar las instrucciones y luego se borre o se borre cuando sea necesario.
En el caso de ser un programa ejecutable de por ejemplo un programa compilado como C++, se podría codificarlo en base64 y guardarlo dentro de tu código de vb, luego cuando se lo necesite usar, entonces se decodifica creando un archivo/programa ejecutable en algún directorio que puede ser en el mismo directorio dónde está tu script o en otro, por ejemplo en el directorio de archivos temporales de Windows.
Tal vez te preguntes si eso funcionaria y la respuesta es sí porque lo que un lenguaje no pueda hacer, lo hará otro que sí pueda, solamente tiene que llamar a ese otro código/programa, y el tema podríamos decir más complicado y el que más hay que tener en cuenta es el tema de la sincronización, los dos tienen que estar sincronizados y eso ya lo ves vos cómo hacerlo, podes hacerlo por ejemplo mediante archivos de texto o archivos de configuración ini, mientras uno escribe la información, el otro la lee, o hasta incluso usar sockets para la comunicación, yo en mis épocas he creado métodos como éstos y me han funcionado perfectamente.
Saludos
Se me ocurre con winapi listas los procesos, obtener el "comando" con el que fue ejecutado y todos los PID de ese ejecución pues será de ese perfil...
Una imagen dice mil palabras (el código de abajo esta enfocado en buscar esos comandos)
(https://i.postimg.cc/cLWZD7QW/admon-taks.png) (https://postimg.cc/xc6W8zxp)
Pasos:
Listas procesos activos inspeccionando "PED".
Si vez que tienen los parámetros del perfil los matas
Este es un visor en C/C++
C/C++ :: https://www.codeproject.com/Articles/19685/Get-Process-Info-with-NtQueryInformationProcess
Debes listar los procesos (aquí un código que te puede servir https://www.vbforums.com/showthread.php?251163-How-can-you-terminate-a-process-by-its-name&s=&highlight=terminateprocess) y obtener su handle después el handle lo puedes pasar a estos código que te dejo y que deberás adaptar según requieras.
Para inspeccionar las ejecuciones desde el handle podrías usar esto:
Option Explicit
Private Const ProcessBasicInformation As Long = 0
Private Type LARGE_INTEGER
lowpart As Long
highpart As Long
End Type
Public Type LIST_ENTRY64
Flink As LARGE_INTEGER
Blink As LARGE_INTEGER
End Type
Private Type UNICODE_STRING64
Length As Integer
MaxLength As Integer
lPad As Long
lpBuffer As LARGE_INTEGER
End Type
Private Type PROCESS_BASIC_INFORMATION64
ExitStatus As Long
Reserved0 As Long
PebBaseAddress As LARGE_INTEGER
AffinityMask As LARGE_INTEGER
BasePriority As Long
Reserved1 As Long
uUniqueProcessId As LARGE_INTEGER
uInheritedFromUniqueProcessId As LARGE_INTEGER
End Type
Public Type PEB64
InheritedAddressSpace As Byte
ReadImageFileExecOptions As Byte
BeingDebugged As Byte
Spare As Byte
lPad01 As Long
Mutant As LARGE_INTEGER
ImageBaseAddress As LARGE_INTEGER
LoaderData As LARGE_INTEGER
ProcessParameters As LARGE_INTEGER
SubSystemData As LARGE_INTEGER
ProcessHeap As LARGE_INTEGER
FastPebLock As LARGE_INTEGER
AtlThunkSListPtr As LARGE_INTEGER
IFEOKey As LARGE_INTEGER
CrossProcessFlags As Long
ProcessBits As Long
KernelCallBackTable As LARGE_INTEGER
EventLogSection As Long
EventLog As Long
FreeList As LARGE_INTEGER
TlsBitMapSize As Long
lPad02 As Long
TlsBitMap As LARGE_INTEGER
TlsBitMapData(1) As Long
ReadOnlySharedMemoryBase As LARGE_INTEGER
ReadOnlySharedMemoryHeap As LARGE_INTEGER
ReadOnlyStaticServerData As LARGE_INTEGER
InitAnsiCodePageData As LARGE_INTEGER
InitOemCodePageData As LARGE_INTEGER
InitUnicodeCaseTableData As LARGE_INTEGER
NumberOfProcessors As Long
NtGlobalFlag As Long
CriticalSectionTimeout As LARGE_INTEGER
HeapSegmentReserve As LARGE_INTEGER
HeapSegmentCommit As LARGE_INTEGER
HeapDeCommitTotalFreeThreshold As LARGE_INTEGER
HeapDeCommitFreeBlockThreshold As LARGE_INTEGER
NumberOfHeaps As Long
MaxNumberOfHeaps As Long
ProcessHeapsList As LARGE_INTEGER
GdiSharedHandleTable As LARGE_INTEGER
ProcessStarterHelper As LARGE_INTEGER
GdiDCAttributeList As Long
lPad03 As Long
LoaderLock As LARGE_INTEGER
NtMajorVersion As Long
NtMinorVersion As Long
NtBuildNumber As Integer
NtPlatformId As Integer
PlatformId As Long
ImageSubsystem As Long
ImageMajorSubsystemVersion As Long
ImageMinorSubsystemVersion As Long
lPad09 As Long
AffinityMask As LARGE_INTEGER
GdiHandleBuffer(29) As LARGE_INTEGER
PostProcessInitRoutine As LARGE_INTEGER
TlsExpansionBitmap As LARGE_INTEGER
TlsExpansionBitmapBits(31) As Long
SessionId As LARGE_INTEGER
AppCompatFlags As LARGE_INTEGER
AppCompatFlagsUser As LARGE_INTEGER
ShimData As LARGE_INTEGER
AppCompatInfo As LARGE_INTEGER
CSDVersion As UNICODE_STRING64
ActivationContextData As LARGE_INTEGER
ProcessAssemblyStorageMap As LARGE_INTEGER
SystemDefaultActivationData As LARGE_INTEGER
SystemAssemblyStorageMap As LARGE_INTEGER
MinimumStackCommit As Long
lPad05 As Long
FlsCallBack As LARGE_INTEGER
FlsListHead As LIST_ENTRY64
FlsBitmap As LARGE_INTEGER
FlsBitmapBits(3) As Long
FlsHighIndex As Long
lPad06 As Long
WerRegistrationData As LARGE_INTEGER
WerShipAssertPtr As LARGE_INTEGER
End Type
Private Declare Function NtWow64QueryInformationProcess64 Lib "ntdll" ( _
ByVal hProcess As Long, _
ByVal ProcessInformationClass As Long, _
ByRef pProcessInformation As Any, _
ByVal uProcessInformationLength As Long, _
ByRef puReturnLength As Long) As Long
Private Declare Function NtWow64ReadVirtualMemory64 Lib "ntdll" ( _
ByVal hProcess As Long, _
ByVal BaseAddressL As Long, _
ByVal BaseAddressH As Long, _
ByRef Buffer As Any, _
ByVal BufferLengthL As Long, _
ByVal BufferLengthH As Long, _
ByRef ReturnLength As LARGE_INTEGER) As Long
Sub Main()
Dim tPBI As PROCESS_BASIC_INFORMATION64
Dim tPeb As PEB64
Dim lStatus As Long
Dim hProcess As Long
Dim liRet As LARGE_INTEGER
' // Your handle
hProcess = -1
lStatus = NtWow64QueryInformationProcess64(hProcess, ProcessBasicInformation, tPBI, Len(tPBI), 0)
If lStatus < 0 Then
MsgBox "Error 0x" & Hex$(lStatus)
Exit Sub
End If
lStatus = NtWow64ReadVirtualMemory64(hProcess, tPBI.PebBaseAddress.lowpart, tPBI.PebBaseAddress.highpart, tPeb, Len(tPeb), 0, liRet)
If lStatus < 0 Then
MsgBox "Error 0x" & Hex$(lStatus)
Exit Sub
End If
End Sub
Este código los mata por nombre (busca por nombre los ejecutables obtiene su pid y los mata, en tu caso debes remover el codigo que busca por nombre y solo pasar el PID).
Public Function KillAppByName(MyName As String) As Boolean 'kills applications by name
Const PROCESS_ALL_ACCESS = 0
Dim uProcess As PROCESSENTRY32
Dim rProcessFound As Long
Dim hSnapshot As Long
Dim szExename As String
Dim exitCode As Long
Dim AppKill As Long
Dim i As Integer
Dim lProcHnd As Long
Dim hWnd As Long
On Local Error GoTo ErrTrap
If winVersion = "WNT3" Or winVersion = "WNT4" Then Exit Function
Const TH32CS_SNAPPROCESS As Long = 2&
uProcess.dwSize = Len(uProcess)
hSnapshot = CreateToolhelpSnapshot(TH32CS_SNAPPROCESS, 0&)
rProcessFound = ProcessFirst(hSnapshot, uProcess)
Do While rProcessFound
i = InStr(1, uProcess.szexeFile, Chr(0))
szExename = LCase$(Left$(uProcess.szexeFile, i - 1))
If Right$(szExename, Len(MyName)) = LCase$(MyName) Then
lProcHnd = OpenProcess(PROCESS_TERMINATE, 0&, uProcess.th32ProcessID)
AppKill = TerminateProcess(lProcHnd, exitCode)
Call CloseHandle(lProcHnd)
End If
rProcessFound = ProcessNext(hSnapshot, uProcess)
Loop
Call CloseHandle(hSnapshot)
Exit Function
End Function
Dulces lunas!¡.