(https://i.postimg.cc/3xnLdz2z/Classname-Explorer.jpg) (https://postimages.org/)
Hola a todos;
Estoy haciendo un programa que carga imágenes, las salva en una carpeta, y luego las procesa.
Después visualiza, utilizando el Visualizador de fotos de Windows, las originales y las procesadas para poder compararlas, conmutando las 2 imágenes pulsando los botones 3 o 5, en la imagen del Visualizador de fotos de Windows, o pulsando las teclas Dcha o Izq del teclado.
Pero hay que cerrar las ventanas que enumero mas abajo, para que el usuario no pueda utilizar los menúes, ni los botones 1, 2, 4, 6, 7 y 8 de la imagen.
Se como obtener los Hwnd de las ventanas del Visualizador de fotos de Windows de estas clases, que se ven en la imagen:
photos_navigationpane
photos_navigationbar
photos_commandbar
photos_buttonex
Pero dentro de la ventana photos_buttonex (color naranja en la imagen)
Hay 8 button numerados del 1 al 8 en la imagen, que en realidad tambien son ventanas, por que tienen Hwnd cada uno.
Y necesito obtener el Hwnd de cada uno, y no veo la forma de hacerlo.
Por que con el código que utilizo para obtener los Hwnd de las clases(ventanas)
photos_navigationpane, photos_navigationbar, photos_commandbar, y photos_buttonex, no me sirve por que no detecta los 8 botones.
El código es este:
Public Sub EnumChildProc(ByVal hWnd As Long)
Dim hChild As Long, ret As Long, Caption As String, i As Integer
Form5.ListMemoRuta.Clear
hChild = FindWindowEx(hWnd, 0, vbNullString, vbNullString)
1:
Do While hChild <> 0
DoEvents
'Llenamos un Buffer
ClassName = Space$(128)
'Recupera el Classname y lo devuelve en el Buffer
ret = GetClassName(hChild, ClassName, 128)
'Extraemos el nombre de la clase
ClassName = LCase(Left$(ClassName, ret))
Caption = String(GetWindowTextLength(hChild), Chr$(0))
If InStr(ClassName, "photos_navigationpane") Then
If Todo Then Form5.ListMemoRuta.AddItem hChild
navigationpane = hChild
ElseIf InStr(ClassName, "photos_commandbar") Then
Form5.ListMemoRuta.AddItem hChild
ElseIf InStr(ClassName, "atl:") Then
Form5.ListMemoRuta.AddItem hChild
ElseIf InStr(ClassName, "photos_navigationbar") Then
If Todo Then Form5.ListMemoRuta.AddItem hChild
navigationbar = hChild
ElseIf InStr(ClassName, "photo_lightweight_viewer") Then
'Form5.ListMemoRuta.AddItem hChild
viewer = hChild
ElseIf ClassName = "photos_buttonex" Then
buttonex = hChild
End If
hChild = GetNextWindow(hChild, 2)
Loop
'lista de clases que hay que cerrar
2:
For i = 0 To Form5.ListMemoRuta.ListCount - 1
hChild = Form5.ListMemoRuta.List(i)
Call SendMessage(hChild, WM_SYSCOMMAND, SC_CLOSE, ByVal 0&)
Form5.ListMemoRuta.RemoveItem (i)
GoTo 2
Next
Pero con un timer y este código:
'Obtiene la coordenada del Mouse
ret = GetCursorPos(Cor)
'Recuperamos el HWND de la ventana asociada a esa coordenada
Handle = WindowFromPoint(Cor.x, Cor.y)
'Para calcular el ancho actual de la ventana
Call GetClientRect(Handle, rct)
If ClassName = "photos_buttonex" Then
If rct.Right = 51 And rct.Bottom = 25 Then
'son los botones de 3 y 5 de la imagen
'no hace nada, por que son los que utiliza el programa
Else
'cierra estas ventanas(botones), para que no el usuario no pueda pulsarlos
Call SendMessage(Handle, WM_SYSCOMMAND, SC_CLOSE, ByVal 0&)
End If
End If
Al pasar el cursor del ratón encima del área de los botones 1, 2, 4, 6, 7 y 8, se cierran, por que solo de esta forma consigo obtener los Hwnd de cada uno, en la variable Handle del código.
Alguien sabe como conseguir los Hwnd de los botones 1, 2, 4, 6, 7 y 8 con código, sin tener que pasar el cursor del ratón encima de cada uno.
Y en el caso de que no se pueda o nadie lo sepa:
Alguien puede sugerirme el código para que el programa ponga el cursor del ratón encima del centro de cada uno de estos botones del Visualizador de fotos de Windows(tengo las coordenadas X,Y de cada uno), para poder obtener el Handle, y así poder cerrarlos con Call SendMessage(Handle,WM_SYSCOMMAND, SC_CLOSE, ByVal 0&)
Por que no he conseguido nada que funcione.
Espero que me podáis ayudar a conseguirlo.
Gracias y un saludo.
Subclassing?
hola
has tenido suerte porque hace, no si más de diez años que no toco VB. El caso es que me he puesto a ayudar a un compañero y recién he instalado vB6 y he hecho un programa con él.
No puedes encontrar en handle (hwnd) porque tienes que obtenerlo de forma descendente, primero el padre que es la ventana, luego el panel que contiene el objeto, luego el objeto y luego sus botones y todo a partir del primero. Es decir con el primero obtienes el segundo, con el segundo el tercero, con el tercero el cuarto.
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
(ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
(ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetNextWindow Lib "user32" Alias "GetWindow" _
(ByVal hwnd As Long, ByVal wFlag As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Const GW_HWNDNEXT = 2
Const GW_CHILD = 5
Private Sub Command2_Click()
Dim TITULODELAVENTANA As String
Dim hPhoto_Lightweight_Viewer As Long
Dim hPhotos_NavigationPane As Long
Dim hPhotos_NavigationBar As Long
Dim hPhotos_ButtonEx_1 As Long
Dim hPhotos_ButtonEx_2 As Long
Dim hPhotos_ButtonEx_3 As Long
Dim hPhotos_ButtonEx_4 As Long
Dim hPhotos_ButtonEx_5 As Long
TITULODELAVENTANA = "24TL510V.jpg - Visualizador de fotos de Windows"
'Orden de padre a hijos
'1.Photo_Lightweight_Viewer
'-----Photos_NavigationPane
'------------Photos_NavigationBar
'----------------------Photos_ButtonEx
'//handle de la ventana
hPhoto_Lightweight_Viewer = FindWindow("Photo_Lightweight_Viewer", TITULODELAVENTANA)
'//handle del panel
'handle de Photo_Lightweight_Viewer
handlePhotos_NavigationPane = FindWindowEx(hPhoto_Lightweight_Viewer, ByVal 0&, "Photos_NavigationPane", vbNullString)
'//Handle del control de botones
'handle de hPhotos_NavigationBar
handlePhotos_NavigationBar = FindWindowEx(handlePhotos_NavigationPane, ByVal 0&, "Photos_NavigationBar", vbNullString)
'//BOTONES
'//Como Photos_ButtonEx no tiene hijos a partir de aquí se usa GW_HWNDNEXT
'//para obtener el handle del siguiente botón (ventana)
'handle de Photos_ButtonEx (la lupa)
hPhotos_ButtonEx_1 = FindWindowEx(handlePhotos_NavigationBar, ByVal 0&, "Photos_ButtonEx", vbNullString)
'handle de Photos_ButtonEx (botón maximizar)
hPhotos_ButtonEx_2 = GetWindow(hPhotos_ButtonEx_1, GW_HWNDNEXT)
'handle de Photos_ButtonEx (botón "izquierda")
hPhotos_ButtonEx_3 = GetWindow(hPhotos_ButtonEx_2, GW_HWNDNEXT)
'handle de Photos_ButtonEx (botón diapositivas)
hPhotos_ButtonEx_4 = GetWindow(hPhotos_ButtonEx_3, GW_HWNDNEXT)
'handle de Photos_ButtonEx (botón "derecha")
hPhotos_ButtonEx_5 = GetWindow(hPhotos_ButtonEx_4, GW_HWNDNEXT)
MsgBox "LUPA = " & Hex(hPhotos_ButtonEx_1)
MsgBox "MAXIMIZAR = " & Hex(hPhotos_ButtonEx_2)
MsgBox "IZQUIERDA = " & Hex(hPhotos_ButtonEx_3)
MsgBox "DIAPOSITIVAS = " & Hex(hPhotos_ButtonEx_4)
MsgBox "DERECHA = " & Hex(hPhotos_ButtonEx_5)
End Sub
luego a partir de Photos_ButtonEx debes buscar el siguiente porque Photos_ButtonEx es el classname de todos los botones
Había otra manera para conseguir todos los handles de una ventan pero no me acuerdo, voy a ver si tengo algún snippet por ahí
Otra cosa, no necesitas ese código del timer para ver los handles, VB6 viene tine SPY++ con el que puedes encontrar los handles e información de las ventanas e hijos. Deberías ver una acceso directo en el menú incio\programas, en"Herramientas de Microsoft Visual Studio 6.0" y si no en "C:\Program Files\Microsoft Visual Studio\Common\Tools\SPYXX.EXE"
(https://i.stack.imgur.com/XP6lu.png)
(//)
y te digo otra cosa, no te lo puedo asegurar pero creo que si importas los botones por separado no te van a hacer nada, ya me contarás.
Para comparar las imágenes puedes usar ImageMagik para vb.net, he visto por ahí códigos simples de 20 líneas que lo hacen. También hay apis online a las que les envías las imágenes y te devuelven el resultado de la comparación.
Cita de: Fran1946 en 4 Febrero 2020, 13:39 PM
...Después visualiza, utilizando el Visualizador de fotos de Windows, las originales y las procesadas para poder compararlas...
Me temo que estás cazando moscas a cañonazos...
Define adecuadamente eso de: "...procesarlas para compararlas..."
Cita de: NEBIRE en 5 Febrero 2020, 03:24 AM
Me temo que estás cazando moscas a cañonazos...
Define adecuadamente eso de: "...procesarlas para compararlas..."
yo entiendo que se refiere con procesarlas a editarlas, cambiar brillo, contraste y estas cosas, puede que incluso el formato o compresión. Después compara una imagen "procesada" con otra original que no ha recibido cambios. ¿para qué? pues él sabrá.
de momento a mi eso me parece irrelevante, me he limitado a centrarme en el tema de la programación, ¿quiere obtener el handle de los botones pero no los consigue? pues ahí está, aunque recuerdo un código que tenía que lo hacía de forma escalonada hasta obtener todos los handles y classname de una ventana, pero no lo encuentro, eran como 6 u 8 líneas y lo hacía.
Hola FJDA:
;-) ;-) ;-)
Tienes razón he tenido mucha suerte con tu respuesta.
Es excelente, exactamente lo que necesitaba saber.
Y también por SPY++ , nunca lo había utilizado.
Pero tengo una duda, que te explico.
Este es el árbol, he añadido las clases que tu no mencionas.
'Orden de padre a hijos
'1.Photo_Lightweight_Viewer
'-----Photos_commandbar
'-----Photos_photocanvas Este handle no lo necesito
'-----Photos_NavigationPane
'---------Photos_NavigationBar
'--------------Photos_ButtonEx
Yo supongo que de la ventana padre '1.Photo_Lightweight_Viewer' ...
sale estas 3:
Photos_commandbar este handle no se como conseguirlo, con tu código
Photos_photocanvas Este handle no lo necesito, es la imagen
Photos_NavigationPane, este y sus hijos está claro
Me podrías decir como conseguir Photos_commandbar, por que esta ventana alberga los menúes que no puede utilizar el usuario, y esta ventana el programa tiene que cerrarla.
Muchísimas gracias por tu ayuda.
Cita de: FJDA en 5 Febrero 2020, 09:34 AM
yo entiendo que se refiere con procesarlas a editarlas, cambiar brillo, contraste y estas cosas, puede que incluso el formato o compresión. Después compara una imagen "procesada" con otra original que no ha recibido cambios. ¿para qué? pues él sabrá.
Una vez más has acertado, hago un proceso bastante complicado, que es irrelevante.
Y por cierto NEBIRE, yo no mato moscas a cañonazos, mi pregunta está muy clara, al menos para FJDA.
Pués si, matas moscas a cañonazos.... te guste o no aceptarlo.
Querer controlar mediante programación la interfaz de usuario de otra aplicación, es matar moscas a cañonazos.
La interfaz de usuario, como su nombre indica está pensada para ser utilizada por personas... para aplicaciones hay multitud de librerías que permiten invocar su funcionalidad, para hacer lo que pretendas hacer (modificar brillo, contraste, saturación, girar imagen, etc...), con sus respectivos parámetros... sin complicaciones estúpidas que uno se impone como una barrera...
Entiendo que uno no quiera implementar determinada funcionalidad, porque o bien no sabe como hacerlo o bien no quiere perder demasiado tiempo en hacerlo, pero perderlo en pretender controlar la interfaz de otro programa además tan limitado... es lo que es.
Te preguntaba en mi mensaje anterior, por la funcionalidad, simplemente para sugerirte opciones más amplias, sencillas (de usar) y válidas, si se tratara (por ejemplo) de algo como girar una imagen cambiar brillo, guardar una imagen, etc, pués ofrecerte ejemplos de código, si fueran demasiadas cosas o bien más complejas sugerirte alguna librería... pero si prefieres no dar explicaciones en tu "proceso bastante complicado, que es irrelevante", entonces sigue con el camino que llevas...
En realidad te equivocas respecto al árbol. Por esta razón no encuentras Photos_commandbar. No has entendido el concepto de ventanas Parents y Childs.
Realmente el árbol sería así:
Photo_Lightweight_Viewer
- Photos_CommandBar
- Photos_ButtonEx (Arc&hivo)
- Photos_ButtonEx (&Imprimir)
- Photos_ButtonEx (Correo &electrónico)
- Photos_ButtonEx (&Grabar)
- Photos_ButtonEx (&Abrir)
- Photos_ButtonEx ("") objeto oculto
- Photos_ButtonEx ("") objeto oculto
- Photos_PhotoCanvas
- ATL:568ED690
- Photos_ButtonEx ("") objeto oculto
- Photos_ButtonEx ("") objeto oculto
- Photos_ButtonEx ("") objeto oculto
- Photos_NavigationPane
- Photos_NavigationBar
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
Entonces, Photo_Lightweight_Viewer tiene cuatro hijos que son Photos_CommandBar, Photos_PhotoCanvas, ATL:568ED690 (no se lo que es) y Photos_NavigationPane
Con mi código lo que hice fue encontrar primero Photo_Lightweight_Viewer y luego el hijo Photos_NavigationPane mediante éste encuentro su hijo Photos_NavigationBar y despues los botones.
Para encontrar Photos_CommandBar necesito el handle (hwnd) del padre que es Photo_Lightweight_Viewer.
Por lo tanto para encontrarlo primero encuentras el padre que es
hPhoto_Lightweight_Viewer = FindWindow("Photo_Lightweight_Viewer", TITULODELAVENTANA)
y después uno de sus hijos que en este caso te interesa Photos_CommandBar
hPhotos_commandbar = FindWindowEx(hPhoto_Lightweight_Viewer, ByVal 0&, "Photos_commandbar", vbNullString)
Demostración:
Dim TITULODELAVENTANA As String
Dim hPhoto_Lightweight_Viewer As Long
Dim hPhotos_commandbar As Long
TITULODELAVENTANA = "demo.jpg - Visualizador de fotos de Windows"
hPhoto_Lightweight_Viewer = FindWindow("Photo_Lightweight_Viewer", TITULODELAVENTANA)
hPhotos_commandbar = FindWindowEx(hPhoto_Lightweight_Viewer, ByVal 0&, "Photos_commandbar", vbNullString)
MsgBox "barra = " & Hex(hPhotos_commandbar)
Por si te sirve te dejo este código para ajustar colores (brillo, contraste, escala de grises, etc)
https://mega.nz/#!fBlyUCpQ!Kemdm1iZ52dScMcYy6cfak2VzEV4jZ8pBlByvkrLK_0 (https://mega.nz/#!fBlyUCpQ!Kemdm1iZ52dScMcYy6cfak2VzEV4jZ8pBlByvkrLK_0)
demostración:
(https://i.postimg.cc/B6n9Qx3r/Demo-Set-Color-Adjustment.jpg)
Te preguntaba en mi mensaje anterior, por la funcionalidad, simplemente para sugerirte opciones más amplias, sencillas (de usar) y válidas, si se tratara (por ejemplo) de algo como girar una imagen cambiar brillo, guardar una imagen, etc, pués ofrecerte ejemplos de código, si fueran demasiadas cosas o bien más complejas sugerirte alguna librería... pero si prefieres no dar explicaciones en tu "proceso bastante complicado, que es irrelevante", entonces sigue con el camino que llevas...
[/quote]
Hola NEBIRE:
Lamento si te ha molestado mi respuesta, no es mi intención, simplemente no doy detalles de el tipo de procesos que hago con las imágenes por que es irrelevante y no guarda relación con mi consulta y tampoco tiene nada que ver con cambios de color, brillo, girar o comprimir, amén de que sería muy largo de explicar y haría mas difícil que alguien se interesara por responder.
Pero si debo de explicar, debido a tu interés por ayudar, por que he decidido utilizar el visor de Windows.
Yo utilizaba para ver la comparación un PictureBox, que sería más logico utilizar, pero este control tiene muchos problemas de errores al cargar ciertas imágenes con nombres muy raros, como estos ejemplos que son reales:
!B,wfDHgBGk~$(KGrHgoOKj!EjlLmZDmvBKs6y)CFe!~~_3.jpg
鋼拉絲Steel Brushed Stainless.jpg
MATI BELEN, COVA Y ROSANA, CON ADRIANA, Y JOSE ANTONIO.jpg
Ninguno de estos archivos los carga PictureBox sin dar error, y por supuesto no los visualiza. Y además no puedo evitar ni sortear el error, si se produce, sin que se cierre el programa.
También necesitaba, que al comparar las imágenes originales y procesadas, pudiera hacer zoom para apreciar mejor ciertas diferencias, también esto ya lo tenía resuelto con barras scroll, que no me gustan nada.
Y todo esto y alguna cosilla más, lo tengo resuelto utilizando el visor de Windows, por las siguientes razones:
Los archivos raros los carga sin problema y sin error
Tengo el zoom, mejor del mundo, con la rueda del ratón, nada que ver con 2 scrollV y H
Mover la imagen, con cursor de icono de mano incluido, por muy grande que esta sea de forma perfecta, poder redimensionar el visor o maximizarlo, minimizarlo.
Y todo esto manejando simplemente 10 Hwnd's del visor de Windows, 35 líneas de código.
Cita de: FJDA en 5 Febrero 2020, 15:20 PM
En realidad te equivocas respecto al árbol. Por esta razón no encuentras Photos_commandbar. No has entendido el concepto de ventanas Parents y Childs.
Realmente el árbol sería así:
Photo_Lightweight_Viewer
- Photos_CommandBar
- Photos_ButtonEx (Arc&hivo)
- Photos_ButtonEx (&Imprimir)
- Photos_ButtonEx (Correo &electrónico)
- Photos_ButtonEx (&Grabar)
- Photos_ButtonEx (&Abrir)
- Photos_ButtonEx ("") objeto oculto
- Photos_ButtonEx ("") objeto oculto
- Photos_PhotoCanvas
- ATL:568ED690
- Photos_ButtonEx ("") objeto oculto
- Photos_ButtonEx ("") objeto oculto
- Photos_ButtonEx ("") objeto oculto
- Photos_NavigationPane
- Photos_NavigationBar
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
- Photos_ButtonEx (control de navegación)
Entonces, Photo_Lightweight_Viewer tiene cuatro hijos que son Photos_CommandBar, Photos_PhotoCanvas, ATL:568ED690 (no se lo que es) y Photos_NavigationPane
Con mi código lo que hice fue encontrar primero Photo_Lightweight_Viewer y luego el hijo Photos_NavigationPane mediante éste encuentro su hijo Photos_NavigationBar y despues los botones.
Para encontrar Photos_CommandBar necesito el handle (hwnd) del padre que es Photo_Lightweight_Viewer.
Por lo tanto para encontrarlo primero encuentras el padre que es
hPhoto_Lightweight_Viewer = FindWindow("Photo_Lightweight_Viewer", TITULODELAVENTANA)
y después uno de sus hijos que en este caso te interesa Photos_CommandBar
hPhotos_commandbar = FindWindowEx(hPhoto_Lightweight_Viewer, ByVal 0&, "Photos_commandbar", vbNullString)
Demostración:
Dim TITULODELAVENTANA As String
Dim hPhoto_Lightweight_Viewer As Long
Dim hPhotos_commandbar As Long
TITULODELAVENTANA = "demo.jpg - Visualizador de fotos de Windows"
hPhoto_Lightweight_Viewer = FindWindow("Photo_Lightweight_Viewer", TITULODELAVENTANA)
hPhotos_commandbar = FindWindowEx(hPhoto_Lightweight_Viewer, ByVal 0&, "Photos_commandbar", vbNullString)
MsgBox "barra = " & Hex(hPhotos_commandbar)
Por si te sirve te dejo este código para ajustar colores (brillo, contraste, escala de grises, etc)
https://mega.nz/#!fBlyUCpQ!Kemdm1iZ52dScMcYy6cfak2VzEV4jZ8pBlByvkrLK_0 (https://mega.nz/#!fBlyUCpQ!Kemdm1iZ52dScMcYy6cfak2VzEV4jZ8pBlByvkrLK_0)
demostración:
(https://i.postimg.cc/B6n9Qx3r/Demo-Set-Color-Adjustment.jpg)
Hola de nuevo:
He llegado tarde..
Ya lo había resuelto, después de estudiar tu código, no funcionaba por que tenía la variable de clase nueva 'Photos_commandbar' escrita como 'hPhotos_commandbar' y el resultado era 0.
Y como todos estos hijos:
- Photos_ButtonEx (Arc&hivo)
- Photos_ButtonEx (&Imprimir)
- Photos_ButtonEx (Correo &electrónico)
- Photos_ButtonEx (&Grabar)
- Photos_ButtonEx (&Abrir)
- Photos_ButtonEx ("") objeto oculto
- Photos_ButtonEx ("") objeto oculto
Tienen que estar prohibidos utilizarlos, simplemente cierro la ventana padre:
- Photos_CommandBar
Y de nuevo muchas gracias por el SetColorAdjustment.zip, este yo lo tenía yo.
Hay un cierto problemilla:
Después de cargar la imagen en el visor, llamo al Call de leer los Hwnd's
Y después se cierran las ventanas que no quiero, pero no siempre devuelve el Hwnd de algunas ventanas retorna = 0, pero si intercalo un delay de algunos milisegundos (tengo que probar cantos para que no retrase mucho) entre lecturas si devuelve valores correctos.
Alguna sugerencia a este respecto?.
Gracias de nuevo.
Cita de: Fran1946 en 5 Febrero 2020, 17:35 PM
Después de cargar la imagen en el visor, llamo al Call de leer los Hwnd's
Y después se cierran las ventanas que no quiero, pero no siempre devuelve el Hwnd de algunas ventanas retorna = 0, pero si intercalo un delay de algunos milisegundos (tengo que probar cantos para que no retrase mucho) entre lecturas si devuelve valores correctos.
Alguna sugerencia a este respecto?.
usa un do While
Do While HWNDParent = 0
HWNDParent = [Buscar handle visualizador de windows]
DoEvents '//esto es para evitar que la apliación se quede pillada
Loop
'Do While hwnd = 0
'[Abrir imagen en el visualizador de windows correspondiente]
'DoEvents
'Loop
Cita de: Fran1946 en 5 Febrero 2020, 17:35 PM
Y como todos estos hijos:
- Photos_ButtonEx (Arc&hivo)
- Photos_ButtonEx (&Imprimir)
- Photos_ButtonEx (Correo &electrónico)
- Photos_ButtonEx (&Grabar)
- Photos_ButtonEx (&Abrir)
- Photos_ButtonEx ("") objeto oculto
- Photos_ButtonEx ("") objeto oculto
Tienen que estar prohibidos utilizarlos, simplemente cierro la ventana padre:
- Photos_CommandBar
:huh: pues no se que habrás hecho :xD
Usa ShowWindow y el comando HIDE_WINDOW = 0. Si lo has usado no funciona es que no lo harás bien digo yo. miratelo
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
(ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
(ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetNextWindow Lib "user32" Alias "GetWindow" _
(ByVal hwnd As Long, ByVal wFlag As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Const HIDE_WINDOW = 0
Const SHOW_OPENWINDOW = 1
Const GW_HWNDNEXT = 2
Const GW_CHILD = 5
Dim TITULODELAVENTANA As String
Dim hPhoto_Lightweight_Viewer As Long
Dim hPhotos_NavigationPane As Long
Dim hPhotos_NavigationBar As Long
Dim hPhotos_ButtonEx_1 As Long
Dim hPhotos_ButtonEx_2 As Long
Dim hPhotos_ButtonEx_3 As Long
Dim hPhotos_ButtonEx_4 As Long
Dim hPhotos_ButtonEx_5 As Long
Private Sub Command1_Click()
TITULODELAVENTANA = "Desierto.jpg - Visualizador de fotos de Windows"
'Orden de padre a hijos
'1.Photo_Lightweight_Viewer
'-----Photos_NavigationPane
'------------Photos_NavigationBar
'----------------------Photos_ButtonEx
'//handle de la ventana
hPhoto_Lightweight_Viewer = FindWindow("Photo_Lightweight_Viewer", TITULODELAVENTANA)
'//handle del panel
'handle de Photo_Lightweight_Viewer
handlePhotos_NavigationPane = FindWindowEx(hPhoto_Lightweight_Viewer, ByVal 0&, "Photos_NavigationPane", vbNullString)
'//Handle del control de botones
'handle de hPhotos_NavigationBar
handlePhotos_NavigationBar = FindWindowEx(handlePhotos_NavigationPane, ByVal 0&, "Photos_NavigationBar", vbNullString)
'//BOTONES
'//Como Photos_ButtonEx no tiene hijos a partir de aquí se usa GW_HWNDNEXT
'//para obtener el handle del siguiente botón (ventana)
'handle de Photos_ButtonEx (la lupa)
hPhotos_ButtonEx_1 = FindWindowEx(handlePhotos_NavigationBar, ByVal 0&, "Photos_ButtonEx", vbNullString)
'handle de Photos_ButtonEx (botón maximizar)
hPhotos_ButtonEx_2 = GetWindow(hPhotos_ButtonEx_1, GW_HWNDNEXT)
'handle de Photos_ButtonEx (botón "izquierda")
hPhotos_ButtonEx_3 = GetWindow(hPhotos_ButtonEx_2, GW_HWNDNEXT)
'handle de Photos_ButtonEx (botón diapositivas)
hPhotos_ButtonEx_4 = GetWindow(hPhotos_ButtonEx_3, GW_HWNDNEXT)
'handle de Photos_ButtonEx (botón "derecha")
hPhotos_ButtonEx_5 = GetWindow(hPhotos_ButtonEx_4, GW_HWNDNEXT)
'quitar hPhotos_ButtonEx_1
Call ShowWindow(hPhotos_ButtonEx_1, HIDE_WINDOW)
'quitar hPhotos_ButtonEx_2
Call ShowWindow(hPhotos_ButtonEx_2, HIDE_WINDOW)
'quitar hPhotos_ButtonEx_5
Call ShowWindow(hPhotos_ButtonEx_5, HIDE_WINDOW)
End Sub
Private Sub Command2_Click()
'mostrar hPhotos_ButtonEx_1
Call ShowWindow(hPhotos_ButtonEx_1, SHOW_OPENWINDOW)
'mostrar hPhotos_ButtonEx_2
Call ShowWindow(hPhotos_ButtonEx_2, SHOW_OPENWINDOW)
'mostrar hPhotos_ButtonEx_5
Call ShowWindow(hPhotos_ButtonEx_5, SHOW_OPENWINDOW)
End Sub
(https://i.postimg.cc/Rh5F0bWq/demobuttons.gif)
Cita de: FJDA en 5 Febrero 2020, 17:48 PM
usa un do While
Do While HWNDParent = 0
HWNDParent = [Buscar handle visualizador de windows]
DoEvents '//esto es para evitar que la apliación se quede pillada
Loop
'Do While hwnd = 0
'[Abrir imagen en el visualizador de windows correspondiente]
'DoEvents
'Loop
Hola de nuevo:
Si yo tengo algo parecido, esto:
Public Function EjecutaShell(file As String) As Boolean
Shell ("explorer.exe " & file)
HwndOrg = 0
tm = 0
Timer2.Interval = 1
Timer2.Enabled = True
Do While HwndOrg = 0
HwndOrg = FindWindow("photo_lightweight_viewer", vbNullString) ' consigo el hwnd
DoEvents
If tm = 100 And HwndOrg = 0 Then 'si no obtiene HwndOrg, sale a los 100 ms
GoTo sal
End If
Loop
sal:
Timer2.Interval = 0
Timer2.Enabled = False
End Function
Y una cosa que se me olvidó...
Tampoco he conseguido, que no salgan los menues del visor, al pulsar botón dcho del ratón
(https://i.postimg.cc/W4QwZ7PZ/Menu.jpg) (https://postimages.org/)
Se puede hacer?.
pues tengo una ligera idea de que quizás si se pueda. Espera a que pruebe.
Usa ShowWindow y el comando HIDE_WINDOW = 0. Si lo has usado no funciona es que no lo harás bien digo yo. miratelo
Esto está resuelto y funciona perfecto.
Gracias.
a ver, esto lo que hace es inhabilitar la ventana Photos_PhotoCanvas que contiene la imagen. De este modo no se puede usar el ratón (solo en Photos_PhotoCanvas)
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
(ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function EnableWindow Lib "user32" _
(ByVal hwnd As Long, ByVal fEnable As Long) As Long
Private Sub Command1_Click()
Dim hPhotos_PhotoCanvas As Long
Dim hPhoto_Lightweight_Viewer As Long
TITULODELAVENTANA = "Desierto.jpg - Visualizador de fotos de Windows"
'//handle de la ventana
hPhoto_Lightweight_Viewer = FindWindow("Photo_Lightweight_Viewer", TITULODELAVENTANA)
'//handle del Photos_PhotoCanvas
hPhotos_PhotoCanvas = FindWindowEx(hPhoto_Lightweight_Viewer, ByVal 0&, "Photos_PhotoCanvas", vbNullString)
Call EnableWindow(hPhotos_PhotoCanvas, vbFalse)
End Sub
Fantástico, es perfecto.
Tu ayuda ha sido extraordinaria, todo funciona como un reloj.
;-) ;-) ;-)
Que opinas sobre los argumentos que le respondí a NEBIRE.
Crees que un PictureBox puede hacer lo que hago con el visor, me refiero a que no sea capaz de cargar y visualizar archivos de jpg, son los únicos que maneja mi programa, con nombres largo, con caracteres raros y/o símbolos que no acepta?.
Y tampoco entiendo que después de muchas horas buscando en Internet, no he conseguido la info que tu me has dado, buscando específicamente lo referente a Ventanas padre e hijos.
Me reitero, mil gracias.
Un saludo.
Cita de: Fran1946 en 5 Febrero 2020, 19:43 PM
Fantástico, es perfecto.
Tu ayuda ha sido extraordinaria, todo funciona como un reloj.
;-) ;-) ;-)
Que opinas sobre los argumentos que le respondí a NEBIRE.
Crees que un PictureBox puede hacer lo que hago con el visor, me refiero a que no sea capaz de cargar y visualizar archivos de jpg, son los únicos que maneja mi programa, con nombres largo, con caracteres raros y/o símbolos que no acepta?.
Y tampoco entiendo que después de muchas horas buscando en Internet, no he conseguido la info que tu me has dado, buscando específicamente lo referente a Ventanas padre e hijos.
Me reitero, mil gracias.
Un saludo.
Con los rifirafes que tengas con otro usuario yo ahí no me meto, menos si es del staff de este foro que no se si será, que aquí son muy susceptibles. ::)
En cuanto a lo del picture el error se produce porque para cargar una imagen debes hacer uso de LoadPicture() para la propiedad Picture de la imagen. Al cargar un nombre extraño no entiende determinados carácteres y se reemplazan por interrogantes, por ejemplo [C:\directorio\鋼拉絲Steel Brushed Stainless.jpg] queda como [C:\directorio\???Steel Brushed Stainless.jpg]. Dado que el archivo ???Steel Brushed Stainless.jpg no existe da error. Da igual el cuadro de diálogo que uses al final debes meterlo en la propiedad la cual va a recibir un directorio que no existe. Por no hablar que no cargar algunos tipos de imagen como imágenes PNG.
Abría que investigar un poco el tema, ahora mismo no se me ocurre nada al respeto para solucionarlo.
Aquí tienes la explicación, realmente no es un problema del Picture si no de VB6:
http://www.cyberactivex.com/UnicodeTutorialVb.htm
Cita de: http://www.cyberactivex.com/UnicodeTutorialVb.htm
Aunque Visual Basic 6.0 almacena cadenas internamente como Unicode (UTF-16), tiene varias limitaciones:
- Se envía con controles solo ANSI (Etiqueta, Cuadro de texto, etc.).
- La ventana de propiedades en IDE es solo ANSI. Las cadenas Unicode se muestran como '????'
- PropertyBag convierte automáticamente cadenas Unicode a ANSI.
- Las funciones del portapapeles son solo ANSI.
- Los menús son solo ANSI.
Cita de: Fran1946 en 5 Febrero 2020, 17:14 PM
...Yo utilizaba para ver la comparación un PictureBox, que sería más logico utilizar, pero este control tiene muchos problemas de errores al cargar ciertas imágenes con nombres muy raros, como estos ejemplos que son reales:
!B,wfDHgBGk~$(KGrHgoOKj!EjlLmZDmvBKs6y)CFe!~~_3.jpg
鋼拉絲Steel Brushed Stainless.jpg
MATI BELEN, COVA Y ROSANA, CON ADRIANA, Y JOSE ANTONIO.jpg
Ninguno de estos archivos los carga PictureBox sin dar error, y por supuesto no los visualiza. Y además no puedo evitar ni sortear el error, si se produce, sin que se cierre el programa.
Bueno, en efecto, VB6 no se las lleva bien cuando en un nombre se colocan caracteres ANSI y UNICODE...
Lo cual no quiere decir que no tenga solución.
Te pongo un código de ejemplo que soluciona el caso, mediante una simple API...
Y luego una imagen... nota que la imagen es una captura de tu mensaje, pero el nombre d ela imagen es el mismo que tu tienes ahí arriba y nota como la imagen se carga perfectamente con este modo...
Private Const INVALID_HANDLE_VALUE As Long = -1
Private Const MAX_PATH As Long = 260
Private Const SHORT_PATH As Long = 14
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
Private Type WIN32_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName As String * MAX_PATH
cAlternate As String * SHORT_PATH
End Type
Private Declare Function FindFirstFile Lib "kernel32" Alias "FindFirstFileA" (ByVal lpFileName As String, lpFindFileData As WIN32_FIND_DATA) As Long
' Código dle botón que carga la imagen:
Private Sub Command1_Click()
Dim Ruta As String
cdlg.ShowOpen ' Cdlg, es un control CommonDialog...
If (Len(cdlg.FileName) > 0) Then
Ruta = ResuelveRuta(cdlg.FileName)
if (len(ruta)>0) then
Set Picture1.Picture = LoadPicture(Ruta)
end if
End If
End Sub
' Función que resuelve el problema de los nombres con caracteres Unicode dentro del nombre...
Private Function ResuelveRuta(ByVal Ruta As String) As String
Dim j As Long, k As Long, WFD As WIN32_FIND_DATA
j = FindFirstFile(Ruta, WFD)
If (j <> INVALID_HANDLE_VALUE) Then
k = InStrRev(Ruta, "\")
If (Left$(WFD.cAlternate, 1) <> Chr(0)) Then
ResuelveRuta = Left$(Ruta, k) & WFD.cAlternate
Else
ResuelveRuta = Left$(Ruta, k) & WFD.cFileName
End If
Else
ResuelveRuta = ""
End If
End Function
Private Sub Form_Load()
cdlg.InitDir = App.Path
End Sub
(https://i.imgur.com/QKsFApT.png)
Otros problemas que tengas con los picturebox, se pueden ir viendo, si describes el problema en cuestión.
Citar
Te pongo un código de ejemplo que soluciona el caso, mediante una simple API...
Y luego una imagen... nota que la imagen es una captura de tu mensaje, pero el nombre de la imagen es el mismo que tu tienes ahí arriba y nota como la imagen se carga perfectamente con este modo...
Otros problemas que tengas con los picturebox, se pueden ir viendo, si describes el problema en cuestión.
Hola NEBIRE:
Gracias por tu ayuda.
Efectivamente este código soluciona el problema.
Y esto me sugiere que podría volver a utilizar un PictureBox como visor...
Pero necesito un código para poder hacer zoom con la rueda del ratón, y poder mover la imagen con zoom pulsando el botón Iqdo del ratón y mover.
Tengo código para mover imagen pero con scroll H-V, y esto no me gusta nada, es muy limitado e incómodo.
Y tengo código de Lupa pero en una ventana externa, no ampliando imagen en el Picture.
Puedes ayudarme en esto, sería perfecto.
Por que con esta solución solucionaría el problema de que el usuario pueda pulsar botón dcho y acceder a los menues que permiten hacer lo mismo que yo inhabilito.
Por que la solución que me dio FJDA de inhabilitar la ventana de la imagen
Call EnableWindow(hPhotos_PhotoCanvas, vbFalse)
Funciona, pero inutiliza poder hacer zoom y mover la imagen, es lógico, pero esto no me sirve.
Cita de: FJDA en 5 Febrero 2020, 19:22 PM
a ver, esto lo que hace es inhabilitar la ventana Photos_PhotoCanvas que contiene la imagen. De este modo no se puede usar el ratón (solo en Photos_PhotoCanvas)
Pues lo siento pero inutiliza poder hacer zoom y mover la imagen, es lógico, pero esto no me sirve.
Gracias.
Escribe "mouse wheel picturebox vb6" en google.
Acostúmbrate a buscar info en inglés porque la mayoría de las cosas están en inglés
https://www.recursosvisualbasic.com.ar/htm/listado-api/215-usar-rueda-del-mouse-en-flexgrid-datagrid.htm (https://www.recursosvisualbasic.com.ar/htm/listado-api/215-usar-rueda-del-mouse-en-flexgrid-datagrid.htm)
Mírate la sección: "Ejemplo 4 - Ejemplo para usar la rueda del mouse en controles Scrollbar"
puedes descargar el código en la página
(https://www.recursosvisualbasic.com.ar/htm/listado-api/img/usar-rueda-de-mouse-en-scrollbar-2.jpg)
Nota: No te va a hacer zoom pero cambiando los parámentros puedes hacer que te haga zoom.
En cualquier buscador puedes encontrar un buen montón de ejemplos, es una de las cosas más demandadas, por principiantes; hacer zoom, redimiensonar, mover el scrolll, voltear, usar el wheel etc.
Aquí tienes para el zoom
https://www.recursosvisualbasic.com.ar/htm/listado-api/71-zoom-imagen-stretchbit.htm (https://www.recursosvisualbasic.com.ar/htm/listado-api/71-zoom-imagen-stretchbit.htm)
(https://www.recursosvisualbasic.com.ar/htm/listado-api/img/zoom-imagen.gif)
mas cosas aquí como hacer una lupa
Dim StartX As Single, StartY As Single
Private Sub Form_Activate()
MousePointer = 11
Picture2.PaintPicture Form1.Picture, 0, 0
Picture1.PaintPicture Picture2.Image, -20, -20, Picture1.Width + 100, Picture1.Height + 100, _
Picture1.Left, Picture1.Top, Picture1.Width, Picture1.Height
Picture1.Line (0, 0)-(Picture1.Width - 1, Picture1.Height - 1), 0, B
MousePointer = 0
End Sub
Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
StartX = X
StartY = Y
Picture1.AutoRedraw = False
End Sub
Private Sub Picture1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = 1 Then
Picture1.Left = IIf(X < StartX, Picture1.Left - (StartX - X), Picture1.Left + (X - StartX))
Picture1.Top = IIf(Y < StartY, Picture1.Top - (StartY - Y), Picture1.Top + (Y - StartY))
Picture1.PaintPicture Picture2.Image, -20, -20, Picture1.Width + 100, Picture1.Height + 100, _
Picture1.Left, Picture1.Top, Picture1.Width, Picture1.Height
Picture1.Line (0, 0)-(Picture1.Width - 1, Picture1.Height - 1), 0, B
End If
End Sub
Private Sub Picture1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Picture1.AutoRedraw = True
End Sub
https://mega.nz/#!6N0lAQDJ!dkAZKkUnQxmX9xS7ZF6Kz-fnQdb1O1-TES9kaB3w9so
(https://i.postimg.cc/gjPfVGTh/demolupa.gif)
62 - Redimensionar imágenes en un PictureBox al estilo Vista previa de imagen (https://www.recursosvisualbasic.com.ar/htm/trucos-codigofuente-visual-basic/62.htm)
(https://www.recursosvisualbasic.com.ar/htm/trucos-codigofuente-visual-basic/imagenes/thumbnail-imagen-en-picturebox.gif)
En este enlace un buen montón de códigos para tratamiento de imágenes.
https://onedrive.live.com/?authkey=%21AGLMrn20g0JGtX0&id=C9DBA2BC5A16373B%21115&cid=C9DBA2BC5A16373B (https://onedrive.live.com/?authkey=%21AGLMrn20g0JGtX0&id=C9DBA2BC5A16373B%21115&cid=C9DBA2BC5A16373B)
Cita de: Fran1946 en 6 Febrero 2020, 10:42 AM
...Efectivamente este código soluciona el problema.
Y esto me sugiere que podría volver a utilizar un PictureBox como visor...
Pero necesito un código para poder hacer zoom con la rueda del ratón, y poder mover la imagen con zoom pulsando el botón Iqdo del ratón y mover.
Y tengo código de Lupa pero en una ventana externa, no ampliando imagen en el Picture.
Puedes ayudarme en esto, sería perfecto.
Vayamos por partes...
Para el zoom, basta una lupa...
He desempolvado un viejo control de usuario, le he retirado cosas que lo harían complicado (otros controles que no vienen al caso), hasta dejarlo en su más simple expresión... y puesto en un proyecto de prueba, para que trastees las propiedades y veas que tal va y si te satisface así.
(nota que el proyecto a falta de conocer donde tienes imágenes las toma de %windir% \web\wallpaper\*.jpg tu podrías suplirlo con una ruta alternativa si te place o no tienes localizada dicha ruta)
Las propiedades básicamente son:
- Aumento: 0'04 hasta 4'00 (admite dos decimales).
- AnchoExplora: Píxeles de ancho captura
- AltoExplora: Píxeles de alto que captura
(las medidas de la lupa resultan de la multiplicación de estos valores por el zoom).
- ModoRastreo: Normal/Invertido (invertido es en negativo).
El resto de funcionalidad ya la ves sobre el propio proyecto.... Basta una lupa para múltiples ventanas, si fuera el caso. Se incluye un segundo form, sin controles que 'toma prestado la lupa' del primario, para examinar el asunto.
Descarga del control y el proyecto de prueba: https://workupload.com/file/8jaeBw22
Y una simple captura de pantalla (dado que la lupa si no se mueve en una imagen estática puede pasar desapercibida, he activado el modo inverso, antes de hace rla captura):
(https://i.imgur.com/QdsgNMp.png)
Si no termina de gustarte, hay muchas lupas por la red que puedas probar y usar... seguramente en foros como:
-www.planet-source-code.com
-www.vbforums.com
-www.freevbcode.com
-forums.codeguru.com
-www.recursosvisualbasic.com.ar
-www.vb-helper.com
-etc, etc...
Solventa lo de la lupa, y luego expones el siguiente problema que tengas...
(https://i.postimg.cc/zGzkb4kR/No-vale.jpg) (https://postimages.org/)
(https://i.postimg.cc/SsC9tGrh/Raros.jpg) (https://postimages.org/)
Hola NEBIRE:
Pues yo da daba por supuesto que el código que me pasaste, solucionaba el asunto de los nombres raros, pero como yo parece que tengo archivos jpg con nombres que nadie tiene, pues las pruebas hasta ahora me reconocía todos, pues recorriendo las carpetas escaneadas por el programa, me encuentro una que no tiene archivos jpg, pero si los tiene, solo que el programa al encontrarlos (son 3) no los añade a la lista dcha azul, por que los nombres no son válidos, tu código devuelve "" vacío.
Pero estos 3 jpg se visualizan perfectamente en el visor de Win clicados en su carpeta.
Mira las imágenes del programa y de la ruta de los 3 archivos.
Estos nombre son estos:
Výstřižek1.JPG
Výstřižek3.JPG
Výstřižek4l.JPG
Y nombres chinos si los acepta, no lo entiendo.
Posiblemente me encuentre otros, es muy dificil chequearlso todos, tengo mas de 65000 imágenes jpg a procesar.
Gracias tengo un código de lupa que usaba con el Picture, pero este me gusta, creo que es el mismo que me ha pasado FJDA
OK... les hecho un vistazo a esos nombres parecen caracteres cirílicos...
He notado también que hay ficheros que pueden tener uno o más null al final del mismo, y si aparece al final, no los retira, ya que VB considera los BString que acaban en null, no considera el último en tanto sea 1 byte por carácter (ANSI)... así que aprovecho de darle un repaso ambos casos.
La lupa que he subido es totalmente hecho por mí, y salvo a mi sobrino que fue quien me lo pidió hace 10 o 12 años, no recuerdo haberlo compartido antes, luego debe tratarse de otra lupa distinta. De todos modos son códigos muy sencillos, pués básicamente son APIs BitBlt, copiando y pegando constantemente... pero que requiere sus líneas de código y no es plan copiar y pegar en cada proyecto...
Los controles de usuario resultan cómodos, porque una vez los compilas, los registras y usas y reutilizas donde haga falta con pocas líneas...
Cita de: NEBIRE en 7 Febrero 2020, 01:14 AM
La lupa que he subido es totalmente hecho por mí, y salvo a mi sobrino que fue quien me lo pidió hace 10 o 12 años, no recuerdo haberlo compartido antes, luego debe tratarse de otra lupa distinta.
aaah amigo tienes razón no son la misma lupa, la mía le da mil vueltas a la tuya :xD
Cita de: Fran1946 en 6 Febrero 2020, 19:43 PM
Mira las imágenes del programa y de la ruta de los 3 archivos.
Estos nombre son estos:
Výstřižek1.JPG
Výstřižek3.JPG
Výstřižek4l.JPG
Y nombres chinos si los acepta, no lo entiendo.
Esa r, definitivamente es un carácter checo...
Tienen solución, básicamente es la misma presentada... solicitar el 'shortname' del fichero, esto es, los antiguos nombres MS-DOS: "8.3"
Piensa que el modo de solventar problemas con caracteres es dejarlos aparte en lo posible y hacer referencia ello con algo ajeno a los caracteres explícitos, por ejemplo: un handle (una dirección de memoria), un índice en un array... así el contenido de dicho string, puede ser lo que sea, mientras no se 'toque' no hay conversión (errónea por truncamiento), que luego falle su referencia en una búsqueda posterior. Aún así he crerado una función que analiza los caracteres aún siendo disitntos en origen... es complicado explicar por qué funciona sin tener una base profunda del fundamento de los caracteres, codificación, la plataforma y el lenguaje de programación usado... de hecho mucha gente habrá tratado múltiples ideas y modificaciones sin resultados.
...pero como digo tiene solución, el caso previo se puede alojar en el nuevo sin distinción de cual de ellos se da, son pocas líneas más de código, sin embargo como dices que tienes varios miles de imágenes en la carpeta, no es muy eficiente que cada vez que se localice un fichero con un nombre así, deba recorrerse todo un array para tomar su shortname (el 8.3). Esto exige 3 cosas...
La primera repensarlo todo y rehacer una especie de 'fileCommonDialog' que al leer el contenido de una carpeta, tome el array de dichos ficheros, así luego puede referenciarse el mismo por su índice en el array...
La segunda cuestión es que dado que esos nombres 'raros', ralentizan innecesariamente su procesado una y otra vez, lo ideal es que cada vez que localice uno, lo renombre ... si lleva caracteres del 'primer tipo', eliminandolos, si lleva caracteres Unicode 'del segundo tipo', truncarlos, lógicamente antes de ese renombrado se debería comprobar si el nombre a asignar existe ya o no, para decidir otro si ese está ocupado y que no falle el renombrado. Y por supuesto dicho renombrado sería un parámetro opcional. Aunque pueda parecer no necesario, ese renombrado posibilitaría que otros programas que tuvieren problemas con tales ficheros en tu equipo quedara resuelto (hacelro manulamente cuando son muchos es tedioso, claro). Y también habría que considerar que no todos los ficheros deben ser renombrables, los de librerías y aplicaciones podrían inutilizar la aplicación de la que son parte, por lo que debería limitarse a los 'documentos de usuarios' y eso cada uno sabe cuales son conforme a las carpetas que los mantiene en su equipo.
En fin crear un fileCommonDialog, son algo más que 4 líneas, y se sale un poco del tiempo que uno puede dedicar a ayudar a otros (otra cosa es cuando ya tienes uno montado de tiempo atrás)...
Si no te basta con la solución que te aporto a continación, pués con dicho código y el resto demis comentarios, tú mismo podrías montarte un FileCommonDialog para la ocasión... la clave para lograr todo esto es recurrir a al objeto FileSystemObject... que hay que añadirlo al proyecto como una referencia:
Y ahora el código:
(nota que excepto la función del mismo nombre el resto es añadido (a lo que ya te dí), la función 'ResuelveRuta' remplaza a la existente)...
' previamente hay que añadir la referencia al proyecto de: FileSystemObject
Private fso As New FileSystemObject
Private fold As Folder
Private f As File
' 'primer' y 'segundo' tipo, es solo una connotación para la solución y el tiempo que lleva cada caso.
Private Function ResuelveRuta(ByVal Ruta As String, Optional ByRef SegundoIntento As Boolean) As String
Dim k As Integer, j As Integer, fichero As String
If Existe(Ruta) Then
k = InStrRev(Ruta, "\")
If (Left$(WFD.cAlternate, 1) <> Chr(0)) Then
' Aqui CAZA: caracteres Unicode (del primer tipo) en el nombre del fichero.
j = InStr(WFD.cAlternate, Chr(0)) ' este campo tiene 14 caracteres, en nombres muy cortos, tipo 3.jpg, todavía podría haber caracteres null al final del mismo.
If (j > 0) Then
ResuelveRuta = Left$(Ruta, k) & Left$(WFD.cAlternate, j - 1)
Else
ResuelveRuta = Left$(Ruta, k) & WFD.cAlternate
End If
Else
ResuelveRuta = Ruta ' Left$(Ruta, k) & WFD.cFileName
End If
Else
If (SegundoIntento = False) Then
SegundoIntento = True
k = InStrRev(Ruta, "\")
j = Len(Ruta)
If (k < j) Then
' Aqui CAZA: caracteres Unicode (del segundo tipo) en el nombre del fichero.
fichero = Right$(Ruta, j - k)
Set fold = fso.GetFolder(Left$(Ruta, k))
For Each f In fold.Files
If (StrCompUnicode(f.Name, (fichero)) = True) Then
ResuelveRuta = ResuelveRuta(Left$(Ruta, k) & f.ShortName)
' usar f.ShortPath si además de los ficheros, las carpetas también tuvieran 'caracteres raros'...
SegundoIntento = False
Exit Function
End If
Next
ResuelveRuta = ""
Else
ResuelveRuta = ""
End If
SegundoIntento = False
Else
ResuelveRuta = ""
End If
End If
End Function
Private Function Existe(ByVal Ruta As String) As Boolean
Existe = (FindFirstFile(Ruta, WFD) <> INVALID_HANDLE_VALUE)
End Function
' Hace una comparación binaria de los bytes pares
' OJO: No modificar un ápice esta función, basta retirar los 'ASC()' para que falle, lo mismo si se hace una conversión a arrays...
' ejemplos que fallan:
' StrCompUnicode = (Str1 = Str2) Then
' StrCompUnicode = Strcom(str1, str2, vbTextCompare) ó vbBinaryCompare
' If (Mid$(Str1, k, 1)) <> (Mid$(Str2, k, 1))) Then Exit Function
Private Function StrCompUnicode(ByRef Str1 As String, ByRef Str2 As String) As Boolean
Dim k As Long, j As Long
k = Len(Str1): j = Len(Str2)
If (k = j) Then
For k = 1 To j
'Debug.Print CStr(Asc(Mid$(Str1, k, 1))),
'Debug.Print CStr(Asc(Mid$(Str2, k, 1)))
If (Asc(Mid$(Str1, k, 1)) <> Asc(Mid$(Str2, k, 1))) Then Exit Function
Next
StrCompUnicode = True
End If
End Function
...puedes tirar con esto, o basarte en esto y mis comentarios previos para montarte tú mismo un FileCommonDialog, que use precisamente el FilesystemObject como el eje de la solución... de todos modos aún con miles de ficheros en una carpeta, con la potencia d elos equipos de hoy, no debería notarse lentitud apreciable en el tratamiento, aunque claramente ese bucle es preferible que se hicera una única vez (cuando se accede a la carpeta y no con cada fichero que tenga caracteres Unicode del 'segundo tipo'...
está bien como investigación y creo que muchísisma gente ya ha intentado algún hack para que VB6 no pase de Unicode a ANSI, como trabajar con bytes para evitar la conversión. Pero ¿no sería mejor que renombraras por lotes los archivos JPG que tienes? Si esas fotos son de porno o algo así, hay programas de terceros como XnView (gratuito) con el que puedes renombrar por lotes.
En cuanto a lo del ratón que no puedes ampliar y eso, tendrías que hacer Hook a la ventana de la imagen, a la ventana Photos_PhotoCanvas y bloquear el mensaje de pulsación del ratón con el botón derecho, o inhabilitar el botón en esa ventana. Pero para eso hay que usar mucha API, y me llevaría un rato, la verdad no tengo ganas.
https://www.recursosvisualbasic.com.ar/htm/listado-api/217-subclasificar-combobox-eventos-de-mouse.htm (https://www.recursosvisualbasic.com.ar/htm/listado-api/217-subclasificar-combobox-eventos-de-mouse.htm)
http://www.vbforums.com/showthread.php?677868-RESOLVED-VB6-about-Hook-windows-api-procedure (http://www.vbforums.com/showthread.php?677868-RESOLVED-VB6-about-Hook-windows-api-procedure)
Parece que ya sabes programar así que no te vamos a hacer todo el trabajo, investiga un poco. Otra cosa es que pongas un código y digas, esto no me funciona o me da error aquí y no se por qué.
Saludos
edito:
y añado en mi caso, que no soy programador y me refiero que no me dedico a ello, solo pasaba por aquí vi tu pregunta y te contesté gustosamente.
He tardado un poco en responder por que he estado estudiando y probando el código que me habéis suministrado.
Ante todo muchísimas gracias, por vuestra ayuda.
NEBIRE:
El código nuevo (ampliado) tampoco funciona con los malditos nombres raros, pero el anterior si funciona para nombres chinos y alguno mas, así que utilizo este, y en los casos de archivos que no los pueda reconocer, pues simplemente no los añade a la lista, en mi caso solo tengo esos 3 archivos que son checos.
FJDA:
La opción que sugieres de renombrar archivos es inviable, tienen que conservar sus nombres originales, por que algunas imágenes jpg se utilizan en alguna aplicación y si cambian el nombre las consecuencias pueden ser desastrosas.
Ya tengo todo resuelto excepto este código que pongo aquí (Solo hay una línea de código que no consigo que funcione), y es la que tiene este comentario:
'Aquí necesito obtener Hwnd de los MenuID, para añadirlos a List1
El código:
Private Sub Command1_Click()
Dim Handle As Long
Dim hWnd As Long
Dim hMainMenu As Long
Dim hMenu As Long
Dim MenuID As Long
Dim szbuf As String * 128
Dim szBufM As String * 128
Dim I, Z, X
List1.Clear
List2.Clear
List3.Clear
List4.Clear
Z = 2 'Posición del menú
I = 0 'Posición del submenú
For I = 0 To 30
hWnd = FindWindow("SDPaintApp", vbNullString) 'handle Ventana aplicación
If hWnd = 0 Then Exit Sub
hMainMenu = GetMenu(hWnd)
hMenu = GetSubMenu(hMainMenu, Z)
MenuID = GetMenuItemID(hMenu, I)
Call GetMenuString(hMenu, MenuID, szbuf, 128, MF_BYPOSITION & MF_POPUP)
If MenuID > 0 Then
List1.AddItem hMainMenu
List2.AddItem hMenu
List3.AddItem MenuID
List4.AddItem szbuf 'Nombre del menú
'X = SendMessage(hWnd, WM_COMMAND, MenuID, 0&) esto ejecuta el MenuID
'Aquí necesito obtener Hwnd de cada MenuID, para añadirlos a un ListBox
End If
Next
End Sub
Espero que esto sea muy fácil para vosotros.
Gracias.
(https://i.postimg.cc/BnjFBsBd/image.jpg) (https://postimages.org/)
Cita de: Fran1946 en 13 Febrero 2020, 19:19 PM
'Aquí necesito obtener Hwnd de cada MenuID, para añadirlos a un ListBox
No te lo puedo asegurar pero los submenus si es a lo que te refieres no tiene handle. Para diregirte a ellos usa MenuID tal como has hecho.
Este código rastrea todos los menús y submenus, es similar al tuyo. Pero tal como muestro la información te quedará más claro.En un nuevo proyecto, crea 4 listbox tal como lo pusistes y un botón y pega este código.
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetMenu Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetMenuItemID Lib "user32" _
(ByVal hMenu As Long, ByVal nPos As Long) As Long
Private Declare Function GetSubMenu Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function GetMenuString Lib "user32" Alias "GetMenuStringA" _
(ByVal hMenu As Long, ByVal wIDItem As Long, ByVal lpString As String, _
ByVal nMaxCount As Long, ByVal wFlag As Long) As Long
Const WM_COMMAND = &H111
Const WM_SYSCOMMAND = &H112
Const MF_BYPOSITION = &H400&
Const MF_POPUP = &H10&
Const SW_NORMAL = 1
Const SW_HIDE = 0
Private Sub Command1_Click()
Dim n As Variant
Dim hMainMenu As Long
Dim hMenu As Long
Dim MenuID As Long
Dim MenuCount As Long
Dim stringmenu As String
Dim szbuff As String * 128
Dim cabBuff As String * 128
Dim HwndParent As Long
Dim nPos As Integer
Dim nID As Integer
HwndParent = FindWindow("Notepad", vbNullString)
If HwndParent = 0 Then Exit Sub
hMainMenu = GetMenu(HwndParent) 'Obtiene el handle del menú de Notepad
MenuCount = GetMenuItemCount(hMainMenu) 'Cuenta el número de menús (no submenus)
For nPos = 0 To MenuCount - 1 'Bucle como tantos menús tenga notepad (son 5: 0,1,2,3,4)
'//Obtiene las cabeceras
Call GetMenuString(hMainMenu, nPos, cabBuff, 128, MF_BYPOSITION)
List1.AddItem nPos & ": " & cabBuff
For nID = -1 To 1000 'Como no se cuantos submenus tiene bucleo desde -1 al 1000 (se empieza desde -1)
hMenu = GetSubMenu(hMainMenu, nPos) 'Obtiene el handle del submenú del menú Z
MenuID = GetMenuItemID(hMenu, nID) 'Obtiene el ID del submenú
If MenuID > -1 And MenuID > 0 Then
Call GetMenuString(hMenu, MenuID, szbuff, 128, MF_BYPOSITION & MF_POPUP)
List2.AddItem "cab:" & nPos & "-> " & hMenu '//Handle
List3.AddItem "cab:" & nPos & "-> " & MenuID '//MenuID
List4.AddItem "cab:" & nPos & "-> " & szbuff '//Nombre
End If
Next nID
Next nPos
'//DEMOSTRACIÓN'//
'/////////////////////////////////
'//Envía un mensaje a Notepad
'//para que ejecute el menú Ayuda
'/////////////////////////////////
AppActivate "Sin título: Bloc de notas" '//Activa el notepad
MenuID = 65& '//-<--Introduce el ID del menú en la variable
SendMessage HwndParent, WM_COMMAND, MenuID, 0& 'esto ejecuta el ID 65 (Acerca de bloc de notas)
End Sub
Private Sub Form_Load()
'Inicia notepad.exe
Dim X As Long, hw As Long
Dim WshShell As Object
Set WshShell = CreateObject("Wscript.Shell")
WshShell.Run "cmd.exe start /r notepad.exe", SW_HIDE, 0
End Sub
Puedes usar
GetMenuItemInfo par obtener información de menús, por ejemplo si están checkeados e igualmente los nombres, por ejemplo. Pero
hSubMenu siempre te devolverá 0 si no me equivoco.
Private Type MENUITEMINFO
cbSize As Long
fMask As Long
fType As Long
fState As Long
wID As Long
hSubMenu As Long
hbmpChecked As Long
hbmpUnchecked As Long
dwItemData As Long
dwTypeData As String
cch As Long
End Type
Private Declare Function GetMenuItemInfo Lib "user32" Alias "GetMenuItemInfoA" _
(ByVal hMenu As Long, ByVal un As Long, ByVal b As Long, lpMenuItemInfo As MENUITEMINFO) As Long
Muy bueno este código, este es para mi colección seguro que lo utilizaré.
Te he mandado un mensaje.
Lo que necesito hacer es que queden inaccesibles todos los menúes, y lo he conseguido así:
Private Sub Command1_Click()
'Dim Handle As Long
Dim hWnd As Long
Dim hMainMenu As Long
Dim hMenu As Long
Dim MenuID As Long
Dim menuFlag As Long
Dim szbuf As String * 128
Dim szBufM As String * 128
Dim i As Long, Z As Integer, x As Integer, j As Integer
1:
List1.Clear
List4.Clear
Z = 0 'Posición del menú
For i = 0 To 10
hWnd = FindWindow("SDPaintApp", vbNullString) 'handle Ventana aplicación
If hWnd = 0 Then Exit Sub
hMainMenu = getmenu(hWnd)
hMenu = GetSubMenu(hMainMenu, Z)
MenuID = GetMenuItemID(hMenu, i)
menuFlag = GetMenuState(hMenu, MenuID, MF_BYCOMMAND)
Handle = Handle
Call GetMenuString(hMenu, MenuID, szbuf, 128, MF_BYPOSITION & MF_POPUP)
If MenuID > 0 Then
List1.AddItem hMainMenu
List4.AddItem szbuf 'Nombre del menú
RemoveMenu hMainMenu, i, MF_BYPOSITION Or MF_DISABLED
'X = SendMessage(hWnd, WM_COMMAND, MenuID, 0&) esto ejecuta el MenuID
End If
Next
x = List1.ListCount
If x = 0 Then
Call SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, 1 Or 2) 'encima
Exit Sub
Else
GoTo 1
End If
End Sub
Seguramente tu tienes una solución mejor, pero esta funciona perfecto.
Un saludo.
Cita de: Fran1946 en 14 Febrero 2020, 19:53 PM
Muy bueno este código, este es para mi colección seguro que lo utilizaré.
Te he mandado un mensaje.
Lo que necesito hacer es que queden inaccesibles todos los menúes, y lo he conseguido así:
---
¿inaccesibles pero operativos o solo inaccesibles?
Puedes usar esta función la función API
RemoveMenu:
Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Public Function EliminarMenu(ByVal hwndAPP As Long)
Dim HWNDMenu As Long
Dim idpOS As Long
Dim i As Integer
Dim N As Long
Dim d As Long
'hwnd del menu del programa
HWNDMenu = GetMenu(hwndAPP)
If HWNDMenu Then
n_Menu = GetMenuItemCount(HWNDMenu)
If n_Menu Then
For i = 1 To n_Menu 'Recorre todos los menú y los elimina
Call RemoveMenu(HWNDMenu, 0, MF_BYPOSITION)
Next
Call DrawMenuBar(hwndAPP) 'Repinta la barra de menú
End If
End If
End Function
Call EliminarMenu(hwndAPP)
EJEMPLO:
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetMenu Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long
Private Const MF_BYPOSITION = &H400&
Dim hwndAPP As Long
Private Sub Form_Load()
Shell "notepad.exe", vbNormalFocus
Do While hwndAPP = 0
hwndAPP = FindWindow("Notepad", vbNullString)
DoEvents
Loop
End Sub
'//Oculgar menú
Private Sub Command1_Click()
Call EliminarMenu(hwndAPP)
End Sub
Public Function EliminarMenu(ByVal hwndAPP As Long)
Dim HWNDMenu As Long
Dim idpOS As Long
Dim i As Integer
Dim N As Long
Dim d As Long
'hwnd del menu del programa
HWNDMenu = GetMenu(hwndAPP)
If HWNDMenu Then
n_Menu = GetMenuItemCount(HWNDMenu)
If n_Menu Then
For i = 1 To n_Menu 'Recorre todos los menú y los elimina
Call RemoveMenu(HWNDMenu, 0, MF_BYPOSITION)
Next
Call DrawMenuBar(hwndAPP)
End If
End If
End Function
Si tienen que ser no accesibles, pero operativos para el programa
Yo no utilizo DrawMenuBar, quiero que desaparezcan
Cita de: Fran1946 en 14 Febrero 2020, 22:33 PM
Si tienen que ser no accesibles, pero operativos para el programa
No te preocupes siguen estando operativos
edito:
Pero debes obtener el MenuID que quieres usar, meterlos en memoria en un array por ejemplo, porque una vez borrado no se puede obtener el ID.
Mira prueba:
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetMenu Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function RemoveMenu Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
Private Declare Function DrawMenuBar Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Const MF_BYPOSITION = &H400&
Private Const WM_COMMAND = &H111
Dim hwndAPP As Long
Private Sub Form_Load()
Shell "notepad.exe", vbNormalFocus
Do While hwndAPP = 0
hwndAPP = FindWindow("Notepad", vbNullString)
DoEvents
Loop
Call EliminarMenu(hwndAPP)
End Sub
Private Sub Command1_Click()
Dim MenuID As Long
MenuID = 65&
AppActivate "Sin título: Bloc de notas"
SendMessage hwndAPP, WM_COMMAND, MenuID, 0&
End Sub
Public Function EliminarMenu(ByVal hwndAPP As Long)
Dim HWNDMenu As Long
Dim idpOS As Long
Dim i As Integer
Dim N As Long
Dim d As Long
'hwnd del menu del programa
HWNDMenu = GetMenu(hwndAPP)
If HWNDMenu Then
n_Menu = GetMenuItemCount(HWNDMenu)
If n_Menu Then
For i = 1 To n_Menu 'Recorre todos los menú y los elimina
Call RemoveMenu(HWNDMenu, 0, MF_BYPOSITION)
Next
Call DrawMenuBar(hwndAPP) 'Repinta la barra de menú
End If
End If
End Function
Perfecto...
Se queda así:
Public Function EliminarMenu(ByVal hwndAPP As Long)
Dim HWNDMenu As Long
Dim i As Integer, n_Menu As Long
'hwnd del menu del programa
HWNDMenu = GetMenu(hwndAPP)
SendMessage hwndAPP, WM_COMMAND, 57642, 0& 'esto ejecuta Crt+E Seleccionar todo
If HWNDMenu Then
n_Menu = GetMenuItemCount(HWNDMenu)
If n_Menu Then
For i = 1 To n_Menu 'Recorre todos los menú y los elimina
Call RemoveMenu(HWNDMenu, 0, MF_BYPOSITION)
Next
Call DrawMenuBar(hwndAPP) 'Repinta la barra de menú, actualiza la App
End If
End If
End Function
Se ejecuta Ctr+E para que el cursor del mouse no tenga el icono del lápiz, que podría pintar y arruinar el proceso.
Una vez mas, muchísimas gracias.
Cita de: Fran1946 en 15 Febrero 2020, 12:47 PM
Perfecto...
Se queda así:
Public Function EliminarMenu(ByVal hwndAPP As Long)
Dim HWNDMenu As Long
Dim i As Integer, n_Menu As Long
'hwnd del menu del programa
HWNDMenu = GetMenu(hwndAPP)
SendMessage hwndAPP, WM_COMMAND, 57642, 0& 'esto ejecuta Crt+E Seleccionar todo
If HWNDMenu Then
n_Menu = GetMenuItemCount(HWNDMenu)
If n_Menu Then
For i = 1 To n_Menu 'Recorre todos los menú y los elimina
Call RemoveMenu(HWNDMenu, 0, MF_BYPOSITION)
Next
Call DrawMenuBar(hwndAPP) 'Repinta la barra de menú, actualiza la App
End If
End If
End Function
Se ejecuta Ctr+E para que el cursor del mouse no tenga el icono del lápiz, que podría pintar y arruinar el proceso.
Una vez mas, muchísimas gracias.
al final te sirvío :)
VB todavía no está muerto, bien por el foro que permita esta sección. ;-)
Aunque la mayoría de preguntas sobre sql y base de datos, pero casi todas alguien las responde, aunque muchas con poca gana. También mucha gente se equivoca y hace preguntas sobre VB.NET, ya hay otra sección para eso. Ayudarte me ha servido para recordar como era esto de programar (pero venía rodado por ayudar a otro usuario antes que a tí que si no...) :xD