|
Básicamente, todos sabemos lo que hace el teclado y el mouse, estos 2 dispositivos nos permiten comunicarnos con el computador, es lo que mas usamos para interactuar con el. El teclado nos sirve para “escribir”, y el mouse básicamente nos sirve para manipular objetos en la computadora de manera mas sencilla, ya que manipular dichos elementos con el teclado harian muy difícil la interacción entre el usuario y la computadora. ¿Cómo funciona básicamente estos dos dispositivos?. Empecemos con el teclado, en este dispositivo, debajo de las teclas que ustedes presionan, presenta dispositivos electrónicos, cada vez que presionan una tecla un “scan code” es generado, dicho “scan code”, lo recibe Windows, y ese codigo lo convierte en otro codigo llamado codigo virtual “virtual code”, ¿Por qué Windows hace eso?. Windows lo hace debido a que un “scan code” puede representar diferentes letras dependiendo de la configuración regional del teclado. ¿Cómo?. Veamos un ejemplo sencillo, ustedes pueden tener un teclado, cuyas teclas son del idioma “ingles”, esto significa que por ningun lado ven la tecla “ñ”, pero en Windows pueden configurar el teclado como “español”, en ese momento cuando ustedes presionen la tecla “;” de su teclado en ingles, en la pantalla ven la tecla “ñ” pero si configuran en Windows el teclado en ingles veran la “;”, lo que quiero decir, es que en ambos caso el “scan code” es el mismo, lo que cambia es el codigo virtual. Depues de esto, los programas pueden transforman dichos codigos en codigos del tipo Ascii y Unicode, por ejemplo en VB el evento “Keypress” muestra el codigo Ascii, pero el evento KeyDown y KeyUp muestran es el codigo virtual. Ya teniendo el codigo virtual generado por Windows, el sistema operativo envia un mensaje WM_KEYDOWN, que en VB sería el evento “KeyDown”, a la ventana activa del hilo de la aplicación que se este ejecutando en ese momento. Al soltar dicha tecla se genera WM_KEYUP, que en VB sería “KeyDown”. Hay otros mensajes relacionado con el teclado, pero básicamente así es como funciona la interacción del teclado con la computadora. El mouse, es un dispositivo mas sencillo, y no hay mucho que explicar, tan sencillamente hablamos de un puntero “hot spot”, el cual a medida que se mueve el mouse, dicho puntero se mueve, enviando mensajes constantemente al sistema operativo. TECLADO Y MOUSE Para este proyecto se necesita un formulario cuyo nombre sea “frmTeclado” y un modulo, dicho formulario tendra que contener los siguientes controles: 4 botones, 1 TextBox, 2 Label y un control Timer. En formulario colocan este codigo: Ver Codigo
Al correr el programa y presionar los botones veran cosas curiosas, con el boton “Keyboard event” veran como se escriben 2 letras en el textbox, sin presionar en el teclado. Con el boton “Mouse event”, notaran que el puntero del mouse se empieza a mover aleatoriamente en la pantalla, con el boton “Desaparecer cursor”, vemos como el puntero se esconde, y con el último botón capturamos el puntero del mouse en una ventana especifica. Para entender todo esto, vamonos a las funciones. keybd_event Api: Declare Sub keybd_event Lib "user32.dll" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long) Esta función es la que se encarga de simular la pulsación de una tecla. Como primer parámetro pasamos el “codigo virtual” de dicha tecla, como segundo parámetro podemos pasar el “scan code”, el parámetro “dwFlags”, puede tomar los siguientes valores: Private Const KEYEVENTF_EXTENDEDKEY = &H1 Private Const KEYEVENTF_KEYUP = &H2 : Indica que la tecla presionada se ha liberado. La primera constante, no entiendo su uso, ya que es usada cuando se le pasa un valor al parámetro “bScan”, y en realidad en los ejemplos no uso dicho parámetro. Pero en la documentación oficial en MSDN encontraran el uso de dicha constante. Como último parámetro se le pasa una información adicional de 32 Bits asociado a la tecla presionada. En nuestro ejempo lo usamos de la siguiente manera:
keybd_event VK_H, 0, 0, 0
keybd_event VK_H, 0, KEYEVENTF_KEYUP, 0
En la primera linea simulamos “keyDown”, es decir, que se esta presionando, en estos caso pasamos el codigo virtual, y la segunda linea hace lo mismo pero coloco la constante KEYEVENTF_KEYUP para indicarle al sistema que la tecla ha dejado de ser presionada. A continuación muestro la tabla de los codigos virtuales de la mayoria de las teclas, esta tabla fue extraida de la ayuda de MSDN de Microsoft. Symbolic constant name | Value (hexadecimal) | Mouse or keyboard equivalent |
|---|
VK_LBUTTON | 01 | Left mouse button | VK_RBUTTON | 02 | Right mouse button |
VK_CANCEL | 03 | Control-break processing | VK_MBUTTON | 04 | Middle mouse button (three-button mouse) | — | 05–07 | Undefined | VK_BACK | 08 | backspace key | VK_TAB | 09 | tab key | — | 0A–0B | Undefined | VK_CLEAR | 0C | clear key | VK_RETURN | 0D | enter key | — | 0E–0F | Undefined | VK_SHIFT | 10 | shift key | VK_CONTROL | 11 | ctrl key | VK_MENU | 12 | alt key | VK_PAUSE | 13 | pause key | VK_CAPITAL | 14 | caps lock key | — | 15–19 | Reserved for Kanji systems | — | 1A | Undefined | VK_ESCAPE | 1B | esc key | — | 1C–1F | Reserved for Kanji systems | VK_SPACE | 20 | spacebar | VK_PRIOR | 21 | page up key | VK_NEXT | 22 | page down key | VK_END | 23 | end key | VK_HOME | 24 | home key | VK_LEFT | 25 | left arrow key | VK_UP | 26 | up arrow key | VK_RIGHT | 27 | right arrow key | VK_DOWN | 28 | down arrow key | VK_SELECT | 29 | select key | — | 2A | Original equipment manufacturer (OEM) specific | VK_EXECUTE | 2B | execute key | VK_SNAPSHOT | 2C | print screen key | VK_INSERT | 2D | ins key | VK_DELETE | 2E | del key | VK_HELP | 2F | help key | VK_0 | 30 | 0 key | VK_1 | 31 | 1 key | VK_2 | 32 | 2 key | VK_3 | 33 | 3 key | VK_4 | 34 | 4 key | VK_5 | 35 | 5 key | VK_6 | 36 | 6 key | VK_7 | 37 | 7 key | VK_8 | 38 | 8 key | VK_9 | 39 | 9 key | — | 3A–40 | Undefined | VK_A | 41 | a key | VK_B | 42 | b key | VK_C | 43 | c key | VK_D | 44 | d key | VK_E | 45 | e key | VK_F | 46 | f key | VK_G | 47 | g key | VK_H | 48 | h key | VK_I | 49 | i key | VK_J | 4A | j key | VK_K | 4B | k key | VK_L | 4C | l key | VK_M | 4D | m key | VK_N | 4E | n key | VK_O | 4F | o key | VK_P | 50 | p key | VK_Q | 51 | q key | VK_R | 52 | r key | VK_S | 53 | s key | VK_T | 54 | t key | VK_U | 55 | u key | VK_V | 56 | v key | VK_W | 57 | w key | VK_X | 58 | x key | VK_Y | 59 | y key | VK_Z | 5A | z key | VK_LWIN | 5B | Left Windows key (Microsoft Natural Keyboard) | VK_RWIN | 5C | Right Windows key (Microsoft Natural Keyboard) | VK_APPS | 5D | Applications key (Microsoft Natural Keyboard) | — | 5E–5F | Undefined | VK_NUMPAD0 | 60 | Numeric keypad 0 key | VK_NUMPAD1 | 61 | Numeric keypad 1 key | VK_NUMPAD2 | 62 | Numeric keypad 2 key | VK_NUMPAD3 | 63 | Numeric keypad 3 key | VK_NUMPAD4 | 64 | Numeric keypad 4 key | VK_NUMPAD5 | 65 | Numeric keypad 5 key | VK_NUMPAD6 | 66 | Numeric keypad 6 key | VK_NUMPAD7 | 67 | Numeric keypad 7 key | VK_NUMPAD8 | 68 | Numeric keypad 8 key | VK_NUMPAD9 | 69 | Numeric keypad 9 key | VK_MULTIPLY | 6A | Multiply key | VK_ADD | 6B | Add key | VK_SEPARATOR | 6C | Separator key | VK_SUBTRACT | 6D | Subtract key | VK_DECIMAL | 6E | Decimal key | VK_DIVIDE | 6F | Divide key | VK_F1 | 70 | f1 key | VK_F2 | 71 | f2 key | VK_F3 | 72 | f3 key | VK_F4 | 73 | f4 key | VK_F5 | 74 | f5 key | VK_F6 | 75 | f6 key | VK_F7 | 76 | f7 key | VK_F8 | 77 | f8 key | VK_F9 | 78 | f9 key | VK_F10 | 79 | f10 key | VK_F11 | 7A | f11 key | VK_F12 | 7B | f12 key | VK_F13 | 7C | f13 key | VK_F14 | 7D | f14 key | VK_F15 | 7E | f15 key | VK_F16 | 7F | f16 key | VK_F17 | 80H | f17 key | VK_F18 | 81H | f18 key | VK_F19 | 82H | f19 key | VK_F20 | 83H | f20 key | VK_F21 | 84H | f21 key | VK_F22 | 85H | f22 key | VK_F23 | 86H | f23 key | VK_F24 | 87H | f24 key | — | 88–8F | Unassigned | VK_NUMLOCK | 90 | num lock key | VK_SCROLL | 91 | scroll lock key | — | 92–B9 | Unassigned | — | BA–C0 | OEM specific | — | C1–DA | Unassigned | — | DB–E4 | OEM specific | — | E5 | Unassigned | — | E6 | OEM specific | — | E7–E8 | Unassigned | — | E9–F5 | OEM specific | VK_ATTN | F6 | Attn key | VK_CRSEL | F7 | CrSel key | VK_EXSEL | F8 | ExSel key | VK_EREOF | F9 | Erase EOF key | VK_PLAY | FA | Play key | VK_ZOOM | FB | Zoom key | VK_NONAME | FC | Reserved for future use. | VK_PA1 | FD | PA1 key | VK_OEM_CLEAR | FE | Clear key |
Ustedes podrian decir, que los valores usados en el proyecto son distinto a los de la tabla, lo que sucede es que en el proyecto use valores “decimales”, y estos valores se encuentran especificado en “hexadecimal”. mouse_event Api: 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) Esta función es la encargada de simular algun evento del mouse, como primer parametro “dwFlags” especificamos que acción vamos a realizar, para ello dicho parametro puede tomar estas constantes: Public Const MOUSEEVENTF_LEFTDOWN = &H2 : Con este simulamos que el botón derecho del mouse fue presionado. Public Const MOUSEEVENTF_LEFTUP = &H4 : Con este simulamos que el botón derecho del mouse fue dejado de presionar. Public Const MOUSEEVENTF_MIDDLEDOWN = &H20 : Con este simulamos que el botón medio del mouse fue presionado. Public Const MOUSEEVENTF_MIDDLEUP = &H40 : Con este simulamos que el botón medio del mouse fue dejado de presionar. Public Const MOUSEEVENTF_MOVE = &H1 : Con esta constante indicamos que movemos el mouse. Public Const MOUSEEVENTF_ABSOLUTE = &H8000 : Especificamos “el como” se realiza el movimiento del mouse. Public Const MOUSEEVENTF_RIGHTDOWN = &H8 : Con este simulamos que el botón derecho del mouse fue presionado. Public Const MOUSEEVENTF_RIGHTUP = &H10 : Con este simulamos que el botón derecho del mouse fue dejado de presionar. Public Const MOUSEEVENTF_WHEEL = &H800 : Solo usado en NT, especifica que la rueda que poseen algunos mouse, ha sido movida, la cantidad del movimiento especificado en el parámetro “cButtons”. Como segundo y tercer parámetro especificamos las coordenadas del puntero del mouse, en donde se realizara la acción especificada arriba. El el cuarto parámetro especificamos la cantidad de movimiento de la rueda del mouse, si fue especificado en “dwFlags” la constante MOUSEEVENTF_WHEEL. Si el valor es positivo implica que la rueda fue movida hacia delante, si es negativo la rueda fue movida hacia atrás. Y como último parámetro pasamos una información extra, asociada al evento del mouse. Vamos a explicar la constante MOUSEEVENTF_ABSOLUTE, ya que en su explicación puse : (“el como” se realiza el movimiento del mouse”). Imaginemos que el puntero se encuentra en la coordenada (pixeles) 400x300, y llama la función mouse_event, con dx = 100 y dy = 50, si no especifico dicha constante, la nueva coordenada del mouse es 500x350, es decir, se desplaza, en cambio si uso dicha constante en la función, la nueva coordenada sería 100x50 En nuestro ejemplo usamos la constante, esa es la razón del por que el mouse cada 500 milisegundos cambia de posición: mouse_event MOUSEEVENTF_ABSOLUTE Or MOUSEEVENTF_MOVE, Int(Rnd() * Screen.Width * 15), Int(Rnd() * Screen.Height * 15), 0&, 0& Ustedes diran ¿Para que simular movimientos, clic, etc, del mouse, o simular las funciones del teclado?. Si ustedes desarrollaran por ejemplo un juego, sería perfecto, estas funciones, para hacer los “demos”, es decir, cuando ustedes estan jugando un juego, y en el menu del juego no hacen nada, algunas veces dicho juego, puede simular por ejemplo, un partido de futbol, dicha simulación puede estar simulando las teclas usadas para realizar dicha acción. Pero esto es un ejemplo, pueden haber muchos mas casos. RegisterHotKey Api: Declare Function RegisterHotKey Lib "user32" (ByVal hwnd As Long, ByVal id As Long, ByVal fsModifiers As Long, ByVal vk As Long) As Long Hot key en español sería algo como “tecla caliente”, como su traduccion no es tan bonita me referire a ella como hot Key. Esta función lo que hace es registrar un hot key. ¿Qué es un hot key?. Cuando una ventana registra un hot key, dicha ventana recibe el mensaje, aun si la ventana no esta seleccionada, es decir, si yo registro como hot key la tecla “a”, mi ventana cada ves que se presiona la tecla “a” recibe dicho mensaje, sin importar si la tecla “a” fue presionada en otra aplicación, esto es muy importante a la hora de quererle dar prioridad a su aplicación, si se presionan cierta combinación de teclas. Veamos los parámetros que tenemos: como primer parámetro le pasamos el “hwnd” de la ventana que recibira dicho mensajes, el segundo parámetro es un ID que identifica al mensaje, como tercer parámetro podemos pasarle las siguientes constantes: Public Const MOD_ALT = &H1 : Implica que la tecla a recibir es ALT-X, donde X es la tecla especificada en el cuarto parametro “vk”. Public Const MOD_CONTROL = &H2 : Implica que la tecla a recibir es CTRL-X, donde X es la tecla especificada en el cuarto parametro “vk”. Public Const MOD_SHIFT = &H4 : Implica que la tecla a recibir es SHIFT-X, donde X es la tecla especificada en el cuarto parametro “vk”. Y como último parámetro recibimos el codigo virtual, de la tecla o carácter que queremos registrar, veamos un ejemplo: RegisterHotKey Me.hwnd, ID_CURSOR, MOD_ALT, VK_E Aqui estoy registrando la combinacion de teclas ALT-E, es decir, no importa donde estes cuando presiones ALT-E, la ventana recibira dicho mensaje. Hay que dejar en claro que el parámetro ID tiene que ser unico para cada combinación. ¿Cómo recibimos el mensaje?. Estos mensajes requieren de un tratamiento especial, ya que cuando se presiona una combinación de teclas configuradas como “hot key”, Windows le envia a la ventana que lo registro el mensaje WM_HOTKEY. Que en nuestro modulo se encuentra especificado de esta manera:
Case WM_HOTKEY
Select Case wParam Case ID_MOUSE frmteclado.Timer1.Enabled = False frmteclado.Label1.Caption = vbNullString Case ID_CURSOR frmteclado.Label1.Caption = vbNullString ShowCursor True Case ID_CAPTURE frmteclado.Label1.Caption = vbNullString frmteclado.Label2.Caption = vbNullString ReleaseCapture End Select
El parámetro “wParam” contiene el ID del mensaje que se activo, y el parámetro “lParam” se divide en dos, la parte baja “loword” contiene la información acerca del valor colocado en el parámetro “fsModifiers”, y la parte alta “hiword” contiene la tecla virtual o codigo virtual de la tecla presionada. Ejemplo, corran el programa y presionen el botón “Desaparecer Cursor”, luego activen la ventana de VB u otra ventana, en este momento, la ventana de la aplicación desaparece, claro esta que todo es como incomodo por el puntero del mouse no esta, pero ahora presionen ALT-E, veran que el cursor aparece, y la ventana se activa, es decir, sin importar, que otra ventana estuviera activada, nuestra aplicación recibio el mensaje de la tecla hot key configurada. ¡impresionante!. Claro esta, que la activacion de nuestra ventana no es gracia al hot key. Si no es gracia a la función localizada en el mensaje WM_HOTKEY, que se explica a continuación: SetActiveWindow Api: Declare Function SetActiveWindow Lib "user32" (ByVal hwnd As Long) As Long Esta función se encarga de activar la ventana especificada en el “hwnd”. UnregisterHotKey Api Declare Function UnregisterHotKey Lib "user32" (ByVal hwnd As Long, ByVal id As Long) As Long Esta función se encarga de eliminar la tecla registrada por la función RegisterHotKey, como primer parámetro le pasamos el “hwnd” de la ventana que la registro y como segundo parametro le pasamos el ID que registramos. Pueden ver que la usamos en Form_Unload:
UnregisterHotKey Me.hwnd, ID_MOUSE
UnregisterHotKey Me.hwnd, ID_CURSOR
UnregisterHotKey Me.hwnd, ID_CAPTURE
ShowCursor Api: Declare Function ShowCursor Lib "user32" (ByVal bShow As Long) As Long Se encarga de mostrar u ocultar el cursor del mouse. Como unico parámetro se le pasa TRUE o FALSE, si es FALSE el cursor de esconde y en caso de ser TRUE el cursor se muestra. SetCapture Api: Declare Function SetCapture Lib "user32" (ByVal hwnd As Long) As Long Esta función lo que hace es que el “hwnd” especificado como unico parametro recibe o captura todos los mensajes del mouse, pero esto no es lo que ustedes imaginan, es decir, esto no implica que si uso dicha función y doy click en otra aplciacion, mi ventana recibira dicho clic, esto no funciona exactamente así. Si trabajaramos con ventanas creadas en el mismo hilo de aplicación en teoria la ventana si recibiria dicho mensajes, pero cuando se le da clic a una ventana perteneciente a otro hilo de aplicación dicha captura se elimina. ¿Para que es importante esto?. Imaginemos que realizamos un programa que dibuja un cuadro, pero resulta que cuando creamos el cuadro (arrastrando el mouse por la pantalla), si nuestro mouse sale de la ventana al soltarlo en otro lugar que no sea nuestro ventana la pregunta sería ¿Quién captura el mensaje MouseUp?. Nuestra aplicación o la aplicación en donde soltamos el mouse, si tienes capturado el mouse dicho mensaje lo recibe nuestra ventana, en caso contrario no lo recibe. Algunos que han trabajdo con esto podrían decir ¿Pero VB recibe el evento MouseUp, aun si el cursor no esta en nuestra ventana?. Eso quiere decir que el evento internamente sin que nosotros lo veamos esta capturando el mouse. Pero hagan este ejemplo, corran el programa y presionen el botón “Capturar cursor” y den un clic afuera de la ventana y veran que es nuestra ventana quien recibe dicho mensaje, pero solo la recibe la primera vez, en caso de volver a presionar afuera de nuestra ventana nuestra aplicación pierde la captura del mouse. ¿Por qué funciona una vez?. Esta respusta no la se, en caso de que una persona le sepa le agradeceria dicha respuesta y con gusto la colocare en el manual. Pero en teoria, o lo que dice la documentación oficial dice, es que dicha función captura los eventos del mouse en la ventana especificada como primer parámetro, tal vez, aunque no he realizado la prueba, dicho efecto, si vea mejor en apliacaciones que poseen varias ventanas hijas, pero esa prueba se las dejo a ustedes. ReleaseCapture Api: Declare Function ReleaseCapture Lib "user32" () As Long Esta función libera la captura del mouse, en la ventana especificada en la función SetCapture, este tambien se puede liberar si se activa otra ventana que pertenezca a otro hilo de aplicación. OTRAS FUNCIONES SOBRE TECLADO Y MOUSE SetFocus Api: Declare Function SetFocus Lib "user32" (ByVal hwnd As Long) As Long Función utilizada para darle el foco a una ventana que pertenezca al hilo de la aplicación, es decir, si tienen una ventana “A” que tiene controles, con esta función, si la usan dentro de dicha ventana “A” pueden darle el foco a los controles que ella posee, si otra aplicación “B” tiene controles y ustedes saben los “hwnd” de dicho controles, si usan esta función en la ventana “A” con los “hwnd” de la ventana “B”, dicha acción no funciona. Problema de esta función con VB. Resulta que en VB no se pueden usar esta función con este nombre. Ya que si en el formulario ponen: SetFocus hwnd El programa le genera un error, ya que da la casualidad que el formulario tiene una función con ese mismo nombre. Para ello usamos un alias, por ejemplo: Declare Function PonerFoco Lib "user32" Alias "SetFocus" (ByVal hwnd As Long) As Long Ahora si ponen en el formulario lo siguiente: PonerFoco hwnd Si! funciona, pueden ponerle cualquier nombre, siempre y cuando el “alias” posea el nombre original de la función. GetFocus Api: Declare Function GetFocus Lib "user32" () As Long Este función retorna el “hwnd” de la ventana que actualmente tienen el foco. GetActiveWindow Api: Declare Function GetActiveWindow Lib "user32" () As Long Función que retorna el “hwnd” de la ventana que esta activa. BlockInput Api: Declare Function BlockInput Lib "USER32.DLL" (ByVal fBlockIt As Long) As Long Función que bloquea todos los mensajes de entrada, es decir, del mouse y teclado. Dichos mensajes son bloqueados cuando le pasamos a la función TRUE y para desbloquear y recibir los mensajes pasamos FALSE. SwapMouseButton Api: Declare Function SwapMouseButton Lib "user32" (ByVal bSwap As Long) As Long Ustedes saben que windows, permite configurar los botones del mouse, que quiero decir, todos sabemos que el botón izquierdo, es el principal, es decir, es el botón con que nosotros activamos y hacemos las acciones principales, y el derecho es el botón secundario, ese orden puede ser invertido, y para ello usamos esta función. Si le pasamos TRUE cambiamos dicho orden, y si pasamos FALSE restauramos el orden original. SetDoubleClickTime Api: Declare Function SetDoubleClickTime Lib "user32" (ByVal wCount As Long) As Long Tambien sabemos que Windows permite configurar el “doble click”, es decir, con esta función configuramos el tiempo que debe de haber entre un click y otro click para activar el evento “Doble Clic”. Ese tiempo que lleva el parámetro “wCount” debe de estar en milisegundos. GetDoubleClickTime Api: Declare Function GetDoubleClickTime Lib "user32" () As Long Esta función retorna la cantidad de milisegundos configurados actualemente para detectar el doble click. CARET Imaginen que un control del tipo TextBox o Caja de texto, tiene el foco, lo primero que ven es una rayita titilando, es decir, como prendido y apagado, indicándonos en donde vamos a escribir, bueno esa rayita se llama “CARET”. Y tambien se han preguntado ¿Podre cambiar dicha rayita y poner otra cosa?. El proyecto que se muestra a continuación muestra como cambiar dicha rayita a cualquier cosa que nosotros queramos. Para este proyecto se necesita, 1 botón, 1 caja de texto o TextBox, y un control timer. En el lugar donde corren el proyecto coloquen la imagen “caret.bmp” que acompaña a este manual. Y por último en el formulario copien este codigo: Ver Codigo
Al arrancar dicha aplicación, denle el foco al textbox y se daran cuenta que tiene un “caret” diferente, a los 5 segundos el timer se activa y lo desaparece, para que se vuelva activar deben de presionar el botón y luego volver a darle el foco al control. Claro esta, como pueden ver no me esforcé en hacer un bonito “caret” pero estoy seguro que su creatividad sera mucho mejor que la mia. CreateCaret Api: Declare Function CreateCaret Lib "user32" (ByVal hwnd As Long, ByVal hBitmap As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long Esta función se utiliza para crear un nuevo caret y asignarselo a una ventana. Como primer parámetro tenemos a dicha ventana, como segundo parámetro le pasamos el bitmap que queremos mostrar, si dicho parámetro le pasamos NULL o 0, se establece un caret solido, en caso de ser 1 el caret es gris. En caso de especificar una imagen, los dos ultimos parámetros son ignorados. En caso contrario, los dos ultimos parámetros especifican el alto y ancho del caret, estas unidades son logicas. En nuestro ejemplo: bitmap = LoadImage(App.hInstance, App.Path & "\caret.bmp", IMAGE_BITMAP, ByVal 0&, ByVal 0&, LR_LOADFROMFILE) r = CreateCaret(Text1.hwnd, bitmap, 0, 0) ShowCaret Text1.hwnd En la primera linea, cargo la imagen, luego se la asigno a la ventana y por último muestro el caret. ShowCaret Api: Declare Function ShowCaret Lib "user32" (ByVal hwnd As Long) As Long Función encargada de mostrar el caret de la ventana especificada en su primer parametro. HideCaret Api: Declare Function HideCaret Lib "user32" (ByVal hwnd As Long) As Long Función encargada de ocultar el caret de la ventana especificada en su primer parametro. MULTIMEDIA Windows posee de una cantidad muy importante de funciones API’S para menejar los diferentes tipos de multimedias, como video, VCR, midi, wav, cd-audio, etc. Particularmente no voy a enfocar dicha seccion a explicar esas API’S, increiblemente Windows nos proporciona 2 funciones con las cuales podemos hacer praticamente TODO!!. Digo “practicamente” ya que tampoco abarca todo. Pero en mi opinion, podrian crear muy facil un programa parecido a Winamp con tan solo 1 función. Esas dos funciones reciben el nombre de mciSendCommandy mciSendString. Estas funciones hacen lo mismo, pero de diferente maneras ¿Qué significa esto?. La primera trabaja en base a puro comandos (constantes) y la segunda trabaja mediante cadenas de texto. Seguramente estan confundido como una función puede realizar tanto trabajo y ciertamente es sorprendente, pero todo lo que voy a explicar requiere de su concentración, por que tan poco es tan facilito entender dicho funcionamiento. ¿Qué significa mensajes en “cadena de texto”?. Esta función mciSendString es la que mas me gusta, ya que es muy parecido al lenguaje humano. Es decir, para hacer funcionar o darle play a un archivo .wav es necesario algo por el estilo. Cadena = “play xxxxx.wav from 0 to final”. E español sería algo como: “Ejecuta xxxx.wav desde el milisegundo 0 hasta ‘final’ (final = que es un valor) . En cambio mciSendCommand, funciona como funcionaria un robot, es decir, le das valores y la función hace algo. Cuando entremos de lleno, con dichas explicaciónes verán la diferencia. Así que empecemos con la primera, que es la mas sencilla, ya que si logran entender dicha función les sera mas facíl entender mciSendCommand. MCISENDSTRING mciSendString Api: Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Long, ByVal hwndCallback As Long) As Long Como primer parametro “lpstrCommand”, tenemos la cadena de texto, que especifica una acción, como segundo parametro “lpstrReturnString”, tenemos una cadena de texto que nos sirve cuando dicha acción, nos retorna un valor a tomar en cuenta, como tercer parametro “uReturnLength” tenemos la cantidad de caracteres que queremos agarrar en el parametro anterior, y como último parametro tenemos “hwndCallBack” aquí (ojo: no es obligatorio) podemos especificar un “hwnd” de una ventana cualquiera, esta ventana cuando es especificada y la acción tiene cierto parametro, el gestor de mensajes de dicha ventana recibira un mensaje especial, de todas manera eso lo veremos mas adelante. La pregunta de ustedes sería ¿Cómo formo la cadena para que haga algo util?. A partir de ahora voy a empezar a explicar palabras claves que necesitarán para formar su “oración” para así ejecutar lo que ustedes quieran. Antes que nada, hay que entender cierto “protocolo”, es decir, los pasos básicos a realizar para ejecutar alguna acción sobre un archivo. Windows puede tener cierto dispositivos “device” configurados, esos dispositivos pueden ser: cdaudio = utilizado para escuchar la musica de los CD. digitalvideo = video digital. overlay = video analogo. scanner = scanear imágenes. sequencer = MIDI vcr = para trabajar con video caseteras videodisc = para trabajar con aparatos de video, en donde insertas discos compactos. waveaudio = trabajar con archivo .WAV Nosotros en este apartado solo trabajaremos con los dispositivos “waveaudio”, “cdaudio” y “digitalvideo”. Lo que mencione arriba es que antes de trabajar con un dispositivo, hay que abrirlo, para ello es el mensaje: OPEN ¿Cómo es la sintaxis? Sería algo así: "open %s1 %s2 %s3" “%s” indica que ahi va algo, “ese algo” se explica continuación: %s1 = en nuestro caso aquí va el nombre del archivo. Que vamos abrir. %s2 = aquí van los llamados “flags”, ¿Qué es eso?. Los flags son como indicadores, que le informan a la función, de algunos detalles. Estos “flag” su uso dependera del dispositivo que este abierto, es decir, hay “flag” que solo se usan en dispositivos del tipo “waveaudio” que no sirven en “vcr”. A continuación menciono los tipos de flag para cada dispositivo: cdaudio | alias device_alias shareable | type device_type | digitalvideo | alias device_alias elementname nostatic parent hwnd shareable | style child style overlapped style popup style style_type type device_type | overlay | alias device_alias parent hwnd shareable style child | style overlapped style popup style style_type type device_type | sequencer | alias device_alias shareable | type device_type | vcr | alias device_alias shareable | type device_type | videodisc | alias device_alias shareable | type device_type | waveaudio | alias device_alias buffer buffer_size | shareable type device_type |
Mostrando dicha tabla, que fue tomada de la ayuda de MSDN de microsoft, aclaro, que no me voy a concentrar en explicar todos los “flag” explicare aquellos que considere mas importante, de todas maneras en la ayuda de MSDN encontraran la información completa. alias device_alias = especifica algún alias, que queramos usar. type device_type = aquí se específica el dispositivo el cual queremos cargar. shareable = Inicializa, el dispositivo o archivo de manera compartida, es decir, mas de un dispositivo puede abrirse al mismo tiempo. style child = abre una ventana con el estilo CHILD style overlapped = abre una ventana con el estilo OVERLAPPED style popup = abre la ventana con el estilo POPUP. %s3 = aquí podemos colocar las palabras “wait” , “notify”, o ambos, la explicación de que hacen dichas palabras se explicaran mas adelante. Ya visto para que sirve cada “sintaxis” hagamos un ejemplo, imaginen que queremos abrir el archivo “xxxx.wav”. El mensaje o la cadena de mensaje sería algo así:  Como pueden ver, se pueden activar mas de un “flag” a la vez, en nuestro caso usamos 2: type y alias. Cuando ya tenemos abierto un dispositivo, estamos listo para manipularlos, a continuación veremos algunos comandos o mensajes que permiten manipular dicho dispositivo abierto. CAPABILITY Sintaxis: "capability %s1 %s2 %s3" Con este comando podemos obtener información, o la capacidad de un dispositivo para realizar una acción. %s1 = Aquí colocamos al identificador del dispositivo, si usan “alias”, iria el nombre de dicho alias. %s2 = pueden ir los siguiente indicadores o “flag”: cdaudio | can eject can play can record can save compound device | device type has audio has video uses files | digitalvideo | can eject can freeze can lock can play can record can reverse can save can stretch can stretch input can test | compound device device type has audio has still has video maximum play rate minimum play rate uses files uses palettes windows | overlay | can eject can freeze can play can record can save can stretch | compound device device type has audio has video uses files windows | sequencer | can eject can play can record can save compound device | device type has audio has video uses files | vcr | can detect length can eject can freeze can monitor sources can play can preroll can preview can record can reverse can save can test | clock increment rate compound device device type has audio has clock has timecode has video number of marks seek accuracy uses files | videodisc | can eject can play can record can reverse can save CAV CLV compound device | device type fast play rate has audio has video normal play rate slow play rate uses files | waveaudio | can eject can play can record can save compound device device type | has audio has video inputs outputs uses files |
La mayoria de estos indicadores, retornan TRUE o FALSE. Por ejemplo: “capability nombrealias can eject” Si fuera “nombrealias” un dispositivo cdaudio , este comando nos retornaría TRUE o FALSE indicándonos que la unidad de CD-ROM puede ejecutar “eject”, es decir, sacar la bandeja donde va el CD. ¿Dónde se retorna dicho valor?. Se recuerdan del parámetro de la función mciSendString llamado “lpstrReturnString”, pues aquí es donde se almacena dicho valor. En particular creo que los flag, se explican por si solos, así que me evito entrar en detalles. %s3 = aquí podemos colocar las palabras “wait” , “notify”, o ambos STATUS Sintaxis: “status %s1 %s2 %s3" Nos sirve para retornar información acerca del estado de un dispositivo, y son muchos tipos de estado y lo veremos en las flag que usa dicho comando. %s1 = Aquí colocamos al identificador del dispositivo, si usan “alias”, iria el nombre de dicho alias. %s2 = pueden ir los siguiente indicadores o “flag”: cdaudio | cdaudio type track number current track length length track number media present mode | number of tracks position position track number ready start position time format | digitalvideo | audio audio alignment audio bitspersample audio breaks audio bytespersec audio input audio record audio source audio samplespersec audio stream bass bitsperpel brightness color contrast current track disk space drive file completion file format file mode forward frames skipped gamma input left volume length length track number media present mode monitor monitor method nominal nominal frame rate nominal record frame rate number of tracks | output palette handle pause mode play speed position position track number ready record frame rate reference frame reserved size right volume seek exactly sharpness smpte speed start position still file format time format tint treble unsaved video video key index video key color video record video source video source number video stream volume window handle window visible window minimized window maximized | overlay | media present mode number of tracks | ready stretch window handle | sequencer | current track division type length length track number master media present mode number of tracks offset | port position position track number ready slave start position tempo time format | vcr | assemble record audio monitor audio monitor number audio record audio record track number audio source audio source number channel channel tuner number clock clock id counter counter format counter resolution current track frame rate index index on length length track number media present media type mode number of audio tracks number of tracks number of video tracks | pause timeout play format position position start position track number postroll duration power on preroll duration ready record format speed time format time mode time type timecode present timecode record timecode type tuner number video monitor video monitor number video record video record track number video source video source number write protected | videodisc | current track disc size forward length length track number media present media type mode | number of tracks position position track number ready side speed start position time format | waveaudio | width="38%">alignment bitspersample bytespersec channels current track format tag input length length track number level | media present mode number of tracks output position position track number ready samplespersec start position time format |
Como pueden ver son muchos así que explicare los que considero mas importante: audio = retorna TRUE o FALSE, donde TRUE significa que las cornetas estan activadas. audio bytespersec = retorna el average de bytes por segundos usados para grabar. audio samplepersec = retorna el número de trazos o “muestra” por segundos. bass = retorna el actual nivel del audio-bass. channel = retorna un valor entero del canal activo. cannels = retorna 1 si los canales estan en mono y 2 si estan en stereo. left volume = retorna el volumen del canal izquierdo. right volume = retorna el volumen del canal derecho. lenght = retorna la longitud de un archivo media, esta longitud se retorna en el formato actual de tiempo, que quiero decir, un archivo .wav retornaría la cantidad de milisegundos que posee dicha canción o sonido. El formato en que lo regresa depende del formato de tiempo configurado, eso lo veremos cuando veamos el comando SET. position = retorna la posición actual. Esta posición depende del formato del tiempo. Colocando el mismo ejemplo del archivo .wav, este flag nos retornaría en que posición, en ese tiempo, se esta escuchando. power on = retorna TRUE si el VCR esta encendido. ready = retorna TRUE si el dispositivo esta listo para recibir otro comando. speed = retorna la velocidad del dispositivo. time format = retorna el tipo de format del tiempo. volume = retorna un promedio o average del volumen izuiqerdo y derecho. %s3 = aquí podemos colocar las palabras “wait” , “notify”, o ambos. La información que retorna dicho comando es colocado en la variable “lpstrReturnString” que se le pasa a la función. CLOSE Sintaxis: “close %s1 %s2" Este comando nos sirve para cerrar un dispositivo que este abierto. %s1 = Aquí colocamos al identificador del dispositivo, si usan “alias”, iria el nombre de dicho alias. %s2 = aquí podemos colocar las palabras “wait” , “notify”, o ambos. Ejm: “close nombrealias” PLAY Sintaxis: “play %s1 %s2 %s3” Este comando ejecuta el “play” de un dispositivo. %s1 = Aquí colocamos al identificador del dispositivo, si usan “alias”, iria el nombre de dicho alias. %s2 = pueden ir los siguiente indicadores o “flag”: cdaudio | from position | to position | digitalvideo | from position fullscreen repeat | reverse to position window | sequencer | from position | to position | vcr | at time from position reverse | scan to position | videodisc | fast from position reverse scan | slow speed integer to position | waveaudio | from position | to position |
from position = se especifica la posicion inicial donde se empieza a ejecutar el dispositovo. Por ejemplo, si un archivo .wav posee 5000 milisegundos de sonido, y hacemos esto “play nombrealias from 2500”, estamos empezando a escuchar el sonido en la mitad. to position = indica la posición final hasta donde se ejecuta dicho dispositivo. speed integer = con esto configuramos la velocidad en que se reproduce un videodisc. fast = se especifica que la ejecución se debe hacer lo mas rapido posible, esta velocidad viene determinado por el flag “speed”. fullscreen = especifica que la ejecución debería de hacerse a pantalla completa. repeat = este flag indica que cuando se finalice la ejecución del dispositivo, este vuelve a empezar desde el comienzo. reverse = la ejecución se hace en sentido contrario. %s3 = aquí podemos colocar las palabras “wait” , “notify”, o ambos. Ejm: “play nombrealias from 0” PAUSE Sintaxis: “pause %s1 %s2" Este comando nos sirve para poner en pausa un dispositivo que se este ejecutando. %s1 = Aquí colocamos al identificador del dispositivo, si usan “alias”, iria el nombre de dicho alias. %s2 = aquí podemos colocar las palabras “wait” , “notify”, o ambos. Ejm: “pause nombrealias” RESUME Sintaxis: “resume %s1 %s2" Este comando nos sirve para continuar un dispositivo que este en pausa. %s1 = Aquí colocamos al identificador del dispositivo, si usan “alias”, iria el nombre de dicho alias. %s2 = aquí podemos colocar las palabras “wait” , “notify”, o ambos. Ejm: “resume nombrealias” SET Sintaxis: “set %s1 %s2 %s3" Este comando nos sirve para configurar o cambiar la configuración de un dispositivo. %s1 = Aquí colocamos al identificador del dispositivo, si usan “alias”, iria el nombre de dicho alias. %s2 = pueden ir los siguiente indicadores o “flag”: cdaudio | audio all off audio all on audio left off audio left on audio right off audio right on | door closed door open time format milliseconds time format msf time format tmsf | digitalvideo | audio all off audio all on audio left off audio left on audio right off audio right on door closed door open | file format format seek exactly on seek exactly off speed factor still file format format time format frames time format milliseconds video off video on | overlay | audio all off audio all on audio left off audio left on audio right off | audio right on door closed door open video off video on | sequencer | audio all off audio all on audio left off audio left on audio right off audio right on door closed door open master MIDI master none master SMPTE offset time | port mapper port none port port_number slave file slave MIDI slave none slave SMPTE tempo tempo_value time format milliseconds time format SMPTE fps time format SMPTE 30 drop time format song pointer | vcr | assemble record on assemble record off audio all off audio all on audio left off audio left on audio right off audio right on clock time counter format counter value door closed door open index counter index date index time index timecode length duration pause timeout postroll duration - duration | power on power off preroll duration duration record format SP record format LP record format EP speed factor time format frames time format hms time format milliseconds time format msf time format SMPTE fps time format SMPTE 30 drop time format tmsf time mode counter time mode detect time mode timecode tracking plus tracking minus tracking reset | videodisc | audio all off audio all on audio left off audio left on audio right off audio right on door closed | door open time format frames time format hms time format milliseconds time format track video off video on | waveaudio | alignment integer any input any output audio all off audio all on audio left off audio left on audio right off audio right on bitspersample bit_count bytespersec byte_rate | channels channel_count door closed door open format tag pcm format tag tag input integer output integer samplespersec integer time format bytes time format milliseconds time format samples |
audio all on, audio all off = estos flag se encarga de desactivar o activar los cornetas o la salida de audio. audio left on, audio left off, audio right on, audio right off: se encargan de desactivar o activar la salida de sonido, de cada canal ya sea el canal derecho o izquierdo. door open = abre o expulsa, la bandeja donde se coloca el CD door close = cierra, la bandeja donde se coloca el CD input integer = especifica la cantidad canales de salida a utilizar. power on, power off = prende o apaga el dispositivo. time format bytes = Asigna el tiempo en formato de bytes, por ejemplo, si trabajamos con una archivo .wav, dicho formato retornaría el tamaño en bytes del archivo. time format frames = Asigna el tiempo en formato de “frames” o marcos, por ejemplo una película se puede especificar en este formato y saber por cual marco o frame se esta ejecutando. time format hms = Asigna el formato del tiempo en HH:MM:SS, donde HH = horas, MM = minutos y SS = segundos. time format milliseconds = Asigna el formato del tiempo en milisegundos. time format mfs = Asigna el formato del tiempo en MM:SS:FF, donde MM = minutos, SS = segundos y FF = frames o marcos. video on , video off = activa o desactiva la salida de video. %s3 = aquí podemos colocar las palabras “wait” , “notify”, o ambos. Ejm: “set nombrealias door open”, en caso de que “nombrealias” sea un dispositivo cdaudio este abriría la puerta del CD-ROM. STOP Sintaxis: “stop %s1 %s2 %s3" Este comando nos sirve para detener la ejecución de un dispositivo. %s1 = Aquí colocamos al identificador del dispositivo, si usan “alias”, iria el nombre de dicho alias. %s2 = aquí se utiliza un solo flag, que es “hold” dicho flag solo funciona para digitalvideo. %s3 = aquí podemos colocar las palabras “wait” , “notify”, o ambos. Ejm: “stop nombrealias” Estos son los comando básicos mas importantes a conocer, puede que a medida que salen diferentes versiones de Windows estos comandos y los flags de los comandos ya existentes se amplíen, por eso recomiendo revisar la documentación oficial de MSDN en internet para estar al actualizado. La explicación de dichos comando y flags fueron básicos, ya que eso es lo que voy a enseñar sobre la función mciSendString. Mas adelante veremos un ejemplo en VB que trabaja con dicho mensajes. Debi mencionar que en la documentación de MSDN tambien podran encontrar mensajes que solo sirven para ciertos dispositivos, es decir, hay mensajes solamente para digitalvideo. Estos mensajes se les llama “mensajes extendidos” (Extended Command). WAIT Y NOTIFY En todos los comando abran visto esta línea: “aquí podemos colocar las palabras “wait” , “notify”, o ambos.” ¿Qué significa poner wait?. Si ponemos este mensaje: “play dispositivo from 0 to 100 wait”, esto implica que el comando “play” ¡no! retornara el control a la aplicación hasta que se ejecute dicho “play”. ¿Qué significa poner notify?. Si ponemos este mensaje: “play dispositivo from 0 to 100 notify”, esto implica que al finalizar dicha ejecución o “play”, se le envia a la ventana de la aplicación el mensaje MM_MCINOTIFY, ¿Qué ventana recibe el mensaje?. Es la ventana que se especifica en el parámetro dwCallBack de la función. Cabe mencionar que para recibir dicho mensaje en VB tendría que usar Subclassing. Este mensaje les sirve para saber si cada comando se ejecuta de manera correcta. ERRORES ¿Qué sucede si hay un error, como lo capturamos?. Con el mensaje MM_MCINOTIFY podemos saber si la ejecución fue correcta aunque no es necesario capturar simpre dicho mensaje, pero como saber ¿Cuál es el error?. Para ello existe una una función llamada: mciGetErrorString Api: Declare Function mciGetErrorString Lib "winmm.dll" Alias "mciGetErrorStringA" (ByVal dwError As Long, ByVal lpstrBuffer As String, ByVal uLength As Long) As Long Con esta función retornamos una cadena de texto que identifica a dicho error. Como primer parámetro le pasamos el número de error, como segundo parámetro le pasamos la variable de tipo String que almacenara el texto que describe al error, y como tercer parámetro le pasamos la cantidad de espacio que queremos recuperar. ¿Cómo saber el número de error?. Cuando ejecutan la función mciSendString el valor que ella retorna es el “número de error”. Ejm: resultado = mciSendString(...,...,.....) Esta variable “resultado” es la que se coloca en el parámetro “dwError” de la función. SONIDO WAV (MCISENDSTRING) Ya visto la teoria, vamos al proyecto que usa dicha función. Primero dicho proyecto tendra que contener los siguientes componentes: Microsoft Common Dialog Control 6.0, Microsoft Windows Common Controls 6.0 (sp4). Con estos coponentes activados, procedemos a incluir los controles que presento a continuación: 4 Botones (Command). 2 Etiquetas (Label). 1 ProgressBar. 1 Slider 1 Caja de Texto (TextBox) 1 Timer Luego pegan este código en el formulario: Ver Codigo
Cuando arranquen el proyecto, aprietan el botón “Archivo WAV” y buscan en su computadora un archivo *.wav, después que lo seleccionen proceden a escucharlo, con los botones “PLAY”, “STOP” y “PAUSE”. ¿Cómo funciona todo esto?. El codigo lo voy explicar desde que se carga el archivo .wav, pero primero expliquemos 2 funciones claves:
Sub MandarMensaje(mensaje As String) cadena = Space(255) resultado = mciSendString(mensaje, cadena, Len(cadena), 0) BuscarError resultado End Sub Dicha función envia un mensaje con la función mciSendString, si el mensaje retorna un resultado, dicha información se almacena en “cadena”, y el codigo del error en “resultado”, pueden ver que en el cuarto parámetro no paso ningun “hwnd”, por lo que es facil deducir que no uso el flag “notify”. La variable “resultado” es pasada a otra función “BuscarError”, que se encarga de mostrar el mensaje de error.
Sub BuscarError(número As Long) error = Space(255) mciGetErrorString resultado, error, 255 Label1.Caption = error End Sub Pueden ver que capturo un máximo de 255 caracteres, y dicha “cadena” de error se almacena en la variable “error” que luego se le asigna al Caption del Label1. Ahora vamos a explicar pasa a paso lo que hacemos para que dicho programa funcione. Para ello empecemos cuando buscamos el archivo .wav en el evento Command1_Click(): Private Sub Command1_Click() . . . MandarMensaje "close archivowav" Cerramos cualquier dispositivo abierto que tenga el nombre del alias a usar. MandarMensaje "open " & Text1.Text & " type waveaudio alias archivowav" Abrimos el archivo .wav que se especifica en el Text del control Text1, pueden ver que especificamos el type y el alias en los flag. MandarMensaje "set archivowav time format milliseconds" Configuro el tiempo del archivo en formato de milisegundos. MandarMensaje "status archivowav length" Busco cuanto tiempo, posee dicho archivo en milisegundos. If Val(Trim(cadena)) <> 0 Then ‘ Si dicho tiempo es distinto de 0 ProgressBar1.Min = 1 ProgressBar1.Max = Val(cadena) ProgressBar1.Value = 1 Slider1.Min = 1 Slider1.Max = Val(cadena) Slider1.Value = 1 Configuro los controles. Label2.Caption = formatotiempo(Val(cadena)) Muestro en formato “MM:SS” el tiempo en milisegundo que posee la variable “cadena” End If End Sub Si presionan el botón “play” ejecutamos lo siguiente: Private Sub Command2_Click() Timer1.Enabled = True Activo el timer, el cual permite ir avanzando en los controles Progress1 y Slider1 MandarMensaje "play archivowav from 0" Ejecuto “play” del archivo cuyo alias es “archivowav” desde (from) la posición 0. End Sub Nos vamos ahora al Timer: Private Sub Timer1_Timer() MandarMensaje "status archivowav position" Solicito la información sobre la posicion actual que se esta ejecutando, es decir, por cual milisegundo esta actualmente. ProgressBar1.Value = Val(cadena) If Not slider Then Slider1.Value = Val(cadena) End If Le paso dicho valores a los controles, es por esa razon que se ve la barra moviendose. Label2.Caption = formatotiempo(ProgressBar1.Max - Val(cadena)) Actualizo el tiempo que falta. End Sub Si presionan “Stop” se ejecuta lo siguiente: Private Sub Command3_Click() MandarMensaje "stop archivowav" Paro la ejecución del archivo Timer1.Enabled = False Desactivo el Timer End Sub Si presionan “Pausa” se ejecuta lo siguiente: Private Sub Command4_Click() If Command4.Caption = "Pausa" Then Si el Caption es “Pausa” entoces MandarMensaje "pause archivowav" Mando el mensaje “pause” para parar la ejecución del archivo. Command4.Caption = "Continuar" Cambio el Caption del botón. Else Si es “continuar” MandarMensaje "resume archivowav" Mando el mensaje “resume” indicando que continue la ejecución del archivo. Command4.Caption = "Pausa" Y coloco ”Pausa” en el Caption. End If End Sub ¿Difícil?, no creo, pueden ver que al usar mciSendString el trabajo se hace muy natural, ya que los mensajes son intuitivos al momento de crearlos. Ahora vamos ver la función mciSendCommand y veremos el mismo proyecto con dicha función, y verán que la cosa se complica un poco. MCISENDCOMMAND mciSendCommand Api: Declare Function mciSendCommand Lib "winmm.dll" Alias "mciSendCommandA" (ByVal wDeviceID As Long, ByVal uMessage As Long, ByVal dwParam1 As Long, ByRef dwParam2 As Any) As Long Se podria decir que esta función es como mas “tecnica”, es decir, no tiene esa facilidad que posee mciSendString que consiste en usar una cadena de texto, en este función dicha cadena no existe, lo que existen son mensajes en forma de constante, y cuando queremos recuperar o asignar algun valor hay que hacerlo por medio de estructuras. Es decir, en pocas palabras esta función es mas complicada que la anterior. Dichas constantes no las voy a explicar todas al igual que las estructuras, inclusive en esta función mi explicación va ser mas basica, y me voy concentrar en que entiendan el como funciona la función y no para que es cada variable, ya que si saben como trabaja esta función, ya las constante es cuestion de leer un poquito y listo!. Como primer parámetro “wDeviceID”, se le pasa un valor que identifica a nuestro dispositivo, solamente cuando usamos el mensaje MCI_OPEN, en este parámetro ponemos 0, para cualquier otro mensaje dicho parámetro debe de tener un valor. Es casi lo equivalente al “alias” usado en mciSendString. Como segundo parámetro “uMessage”, le pasamos el mensaje que queremos ejecutar, aquí los mensajes no son cadenas de caracteres sino constantes, a continuación muestro un listado de los mensajes: Pueden ver que puse los mensajes con sus respectivo “string”, es decir, mientras en mciSendString usamos el comando o mensaje “play” su equivalente en mciSendCommand es la constante o mensaje MCI_PLAY. A continuación muestro los valores de dichas constantes: Private Const MCI_BREAK = &H811 Private Const MCI_SYSINFO = &H810 Private Const MCI_GETDEVCAPS = &H80B Private Const MCI_CLOSE = &H804 Private Const MCI_INFO = &H80A Private Const MCI_OPEN = &H803 Private Const MCI_STATUS = &H814 Private Const MCI_LOAD = &H850 Private Const MCI_PAUSE = &H809 Private Const MCI_PLAY = &H806 Private Const MCI_RECORD = &H80F Private Const MCI_RESUME = &H855 Private Const MCI_SAVE = &H813 Private Const MCI_SEEK = &H807 Private Const MCI_SET = &H80D Private Const MCI_STOP = &H808 Como tercer parametro “dwParam1” tenemos los flag o indicadores que acompañan al mensaje. Y como cuarto parámetro tenemos “dwParam2”, que es donde pasamos las estructuras que usamos ya sea para configurar o recuperar información. A simple vista pueden ver que es muy diferente a la función vista con anterioridad. Ahora vamos a ver como funciona cada mensaje. Voy a trabajar los mismos mensajes o comandos estudiados en mciSendString. MCI_OPEN Cuando usamos este mensaje los parámetros de la función mciSendCommand puede tomar los siguientes valores: wDeviceID = Particularmente cuando yo uso este mensaje pongo 0, ya que no hay dispositivo activado en ese momento. UMessage = MCI_OPEN. wParam1 = el uso de las flag puede ser un poco enredado pero presten atención, algunos de los valores que puede tomar son: Private Const MCI_OPEN_ALIAS = &H400& Private Const MCI_OPEN_SHAREABLE = &H100& Private Const MCI_OPEN_TYPE = &H2000& Private Const MCI_OPEN_TYPE_ID = &H1000& Private Const MCI_OPEN_ELEMENT = &H200& Private Const MCI_OPEN_ELEMENT_ID = &H800& Flags exclusivos para el dispositivo digitalvideo. Private Const MCI_DGV_OPEN_16BIT = &H80000& Private Const MCI_DGV_OPEN_32BIT = &H100000& Private Const MCI_DGV_OPEN_NOSTATIC = &H40000& Private Const MCI_DGV_OPEN_PARENT = &H20000& Private Const MCI_DGV_OPEN_WS = &H10000& Flags exclusivos para el dispositivo overlay. Private Const MCI_OVLY_OPEN_PARENT = &H20000 Private Const MCI_OVLY_OPEN_WS = &H10000 Flags exclusivos para el dispositivo waveaudio. Private Const MCI_WAVE_OPEN_BUFFER = &H10000 Los complicados de los flag, es ¿Como usarlos?. Pero antes de explicar como se usan vamos a ver que toma el otro parámetro. WParam2 = dicho parámetro toma una estructura del tipo MCI_OPEN_PARMS o una estructura de un dispositivo en especifico. Pero nosostros, en este mensaje trabajamos con MCI_OPEN_PARMS que posee la siguiente configuración: Private Type MCI_OPEN_PARMS dwCallback As Long ‘ Equivalente al hwdnCallback de mciSendString. wDeviceID As Long ‘ ID del dispositivo que en nuestro caso al inicio sera 0. lpstrDeviceType As String ‘ Nombre del dispositivo. lpstrElementName As String ‘ Nombre del elemento, usualmente es la dirección del archivo que se quiere abrir lpstrAlias As String ‘ Alias del dispositivo abierto. End Type ¿Como usamos todos esto? Eso depende si entienden el uso de los flag ¿Qué quiero decir? Algunos flag indican un estado pero otros indican que se esta pasando información a traves de la estructura del cuarto parámetro. Por ejemplo mciSendCommand(0, MCI_OPEN, MCI_OPEN_SHAREABLE or MCI_OPEN_ALIAS, openestructura). Suponiendo que “openestructura” es una variable del tipo MCI_OPEN_PARMS, lo que significa la linea de arriba es que la función espera que “lpstrAlias” tenga información ¿Por qué espera eso? La función espera dicha información por que se activa el flag “MCI_OPEN_ALIAS“ que debe de tomar en cuenta dicha variable de la estructura. Ejemplo mas claro: Openestructura.lpstrAlias = “nombre” mciSendCommand(0, MCI_OPEN, MCI_OPEN_SHAREABLE, openestructura). En este ejemplo la función no toma en cuenta el valor que posee “lpstrAlias” y el por que, se debe a que no fue indicado el flag para que tomara en cuenta dicha información, volviendo a poner la siguiente linea: Openestructura.lpstrAlias = “nombre” mciSendCommand(0, MCI_OPEN, MCI_OPEN_SHAREABLE or MCI_OPEN_ALIAS, openestructura). Arreglamos el problema. Otro ejemplo: Openestructura.lpstrAlias = “nombre” Openestructura.lpstrElementName = direccionarchivo mciSendCommand(0, MCI_OPEN, MCI_OPEN_SHAREABLE or MCI_OPEN_ALIAS, openestructura). De esta manera la función no toma el valor de “lpstrElementName” ya que no se ha especificado lo contrario, por lo que el dispositivo seguramente retornaría un error, el problema se soluciona de esta manera: Openestructura.lpstrAlias = “nombre” Openestructura.lpstrElementName = direccionarchivo mciSendCommand(0, MCI_OPEN, MCI_OPEN_SHAREABLE or MCI_OPEN_ALIAS or MCI_OPEN_ELEMENT, openestructura). La pregunta inmediata que deben de tener es ¿El flag MCI_OPEN_SHAREABLE tiene algo que ver con la estructura? La respuesta es no!, estos son flag indicativos o que se usan para configurar algo. Dicho flag hace lo mismo que el flag “shareable” de “open” de la función mciSendString. Segunda pregunta inmediata ¿Cómo saber que flag sirven para indicar algo nada mas, y cuales flag le indican a la función que debe de tomar en cuenta un valor de la estructura? Y es aquí donde tienen que saberse documentar, ya que en la ayuda de MSDN se especifica el uso de cada flag, y se darán cuenta de los flag que se usan para que la función tome en cuenta los valores de la estructura, a continuación muestro los flag que se necesitan para que la función tome en cuenta dicho valores: Private Type MCI_OPEN_PARMS dwCallback As Long ‘ Este valor es tomado en cuenta sin necesidad de algun flag. wDeviceID As Long ‘Este valor es tomado en cuenta sin necesidad de algun flag. lpstrDeviceType As String ‘ MCI_OPEN_TYPE o MCI_OPEN_TYPE_ID lpstrElementName As String ‘ MCI_OPEN_ELEMENT o MCI_OPEN_ELEMENT_ID lpstrAlias As String ‘ MCI_OPEN_ALIAS End Type Cuando se termina de ejecutar el mensaje MCI_OPEN, la variables “wDeviceID” de la estructura contiene el ID que vamos usar en todos los demas comandos que se encargan de manipular dicho dispositivo que fue abierto. ¿Donde ponemos el WAIT o NOTIFY? Ambos vienen especificados con las siguientes constantes: Private Const MCI_NOTIFY = &H1& Private Const MCI_WAIT = &H2& Y se colocan en “wParam1”. Cabe mencionar que el mensaje “notify” sera enviado a la gestor de mensajes de la ventana especificada en “dwCallBack” . Dichas constantes en TODOS los mensajes o comandos van en el parámetro “wParam1”. CAPABILITY Cuando usamos este mensaje los parámetros de la función mciSendCommand puede tomar los siguientes valores: wDeviceID = Aquí colocamos “wDeviceID” de la estructura MCI_OPEN_PARMS, después de ejecutar el comando MCI_OPEN uMessage = MCI_GETDEVCAPS. wParam1 = Voy a poner los flag, que sirven para cualquier dispositivo, les dejo a ustedes documentarse sobre los otros flag: Private Const MCI_GETDEVCAPS_DEVICE_TYPE = &H4& Private Const MCI_GETDEVCAPS_HAS_AUDIO = &H2& Private Const MCI_GETDEVCAPS_HAS_VIDEO = &H3& Private Const MCI_GETDEVCAPS_ITEM = &H100& Private Const MCI_GETDEVCAPS_CAN_EJECT = &H7&
Private Const MCI_GETDEVCAPS_CAN_PLAY = &H8&
Private Const MCI_GETDEVCAPS_CAN_RECORD = &H1&
Private Const MCI_GETDEVCAPS_CAN_SAVE = &H9&
WParam2 = Pasamos la estructura: Private Type MCI_GETDEVCAPS_PARMS dwCallback As Long ‘ Este parametro hace lo mismo que el de la estructura del mensaje MCI_OPEN dwReturn As Long dwItem As Long End Type ¿Como usamos los flag con la estructura? Sabemos que este mensaje MCI_GETDEVCAPS sirve para recuperar información, es intutivo pensar que la variable “dwReturn”, es quien contendra el resultado de dicha información, cuando explique el mensaje “capability” arriba, dije que los flag que acompañaban a dicho mensaje retornaban TRUE o FALSE, pues aquí sigue siendo igual, “dwReturn” en la mayoría de los casos retorna TRUE o FALSE, menciono mayoría ya que hay pequeñas excepciones. Aquí no hay flag, que funcionan como en MCI_OPEN, es decir, no hay flag que indiquen a la función que tome en cuenta el valor de la estructura. Es facil pensar que esto se debe a que este comando sirve para recibir información. Pero hay un hecho curioso con el uso de “dwIitem”, veamos un ejemplo: capestructura.dwItem = MCI_GETDEVCAPS_CAN_EJECT mciSendCommand(openestructura.wDeviceID , MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM, capestructura). Ustedes ven, que arriba hay unas constante en azul, esto significa que cuando la estructura en su parámetro “wParam1” posee MCI_GETDEVCAPS_ITEM esto implica que en el parámetro “dwItem” de la estructura va una de las constante que estan azul. Esto no es valido: mciSendCommand(openestructura.wDeviceID, MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM or MCI_GETDEVCAPS_CAN_EJECT, capestructura). Otro ejemplo: mciSendCommand(openestructura.wDeviceID , MCI_GETDEVCAPS, MCI_GETDEVCAPS_DEVICE_TYPE , capestructura). Pueden ver que a la estructura “capestructura” no se le configura nada, el valor que retorna se almacena en “dwReturn” y no es ni FALSE ni TRUE, estos son los valores que puede retornar: Private Const MCI_ALL_DEVICE_ID = - 1 Private Const MCI_DEVTYPE_ANIMATION = 519 Private Const MCI_DEVTYPE_CD_AUDIO = 516 Private Const MCI_DEVTYPE_DAT = 517 Private Const MCI_DEVTYPE_DIGITAL_VIDEO = 520 Private Const MCI_DEVTYPE_OTHER = 521 Private Const MCI_DEVTYPE_OVERLAY = 515 Private Const MCI_DEVTYPE_SCANNER = 518 Private Const MCI_DEVTYPE_SEQUENCER = 523 Private Const MCI_DEVTYPE_VCR = 513 Private Const MCI_DEVTYPE_VIDEODISC = 514 Private Const MCI_DEVTYPE_WAVEFORM_AUDIO = 522 Es decir, usamos este flag para saber que tipo de dispositivo es “openestructura.wDeviceID” STATUS wDeviceID = Aquí colocamos “wDeviceID” de la estructura MCI_OPEN_PARMS, después de ejecutar el comando MCI_OPEN uMessage = MCI_STATUS. wParam1 = Voy a poner los flag, que sirven para cualquier dispositivo, les dejo a ustedes documentarse sobre los otros flag: Private Const MCI_STATUS_ITEM = &H100& Private Const MCI_STATUS_CURRENT_TRACK = &H8&
Private Const MCI_STATUS_LENGTH = &H1&
Private Const MCI_STATUS_MODE = &H4&
Private Const MCI_STATUS_NUMBER_OF_TRACKS = &H3&
Private Const MCI_STATUS_POSITION = &H2&
Private Const MCI_STATUS_READY = &H7&
Private Const MCI_STATUS_TIME_FORMAT = &H6&
Private Const MCI_STATUS_START = &H200& wParam2 = Pasamos la estructura: Private Type MCI_STATUS_PARMS dwCallback As Long dwReturn As Long dwItem As Long dwTrack As Integer End Type Las constantes en azul funcionan exactamente igual que en el comando anterior. Y el valor que retorna “dwReturn” dependera de que mensaje se envie por ejemplo: Si usamos la constante MCI_STATUS_MODE, “dwReturn” puede retornar los siguientes valores: Private Const MCI_STRING_OFFSET = 512 Private Const MCI_MODE_NOT_READY = (MCI_STRING_OFFSET + 12) Private Const MCI_MODE_OPEN = (MCI_STRING_OFFSET + 18) Private Const MCI_MODE_PAUSE = (MCI_STRING_OFFSET + 17) Private Const MCI_MODE_PLAY = (MCI_STRING_OFFSET + 14) Private Const MCI_MODE_RECORD = (MCI_STRING_OFFSET + 15) Private Const MCI_MODE_SEEK = (MCI_STRING_OFFSET + 16) Private Const MCI_MODE_STOP = (MCI_STRING_OFFSET + 13) Si usamos la constante MCI_STATUS_TIME_FORMAT, “dwReturn” puede retornar los siguientes valores: Private Const MCI_FORMAT_BYTES = 8 Private Const MCI_FORMAT_FRAMES = 3 Private Const MCI_FORMAT_HMS = 1 Private Const MCI_FORMAT_MILLISECONDS = 0 Private Const MCI_FORMAT_MSF = 2 Private Const MCI_FORMAT_SAMPLES = 9 Private Const MCI_FORMAT_TMSF = 10 CLOSE wDeviceID = Aquí colocamos “wDeviceID” de la estructura MCI_OPEN_PARMS, después de ejecutar el comando MCI_OPEN uMessage = MCI_CLOSE. wParam1 = Cuando usamos MCI_CLOSE, lo unico que podemos poner aquí son las constante del mensaje “notify” o “wait”. wParam2 = en este parámetro pasamos la estructura: Private Type MCI_GENERIC_PARMS dwCallback As Long End Type Pueden ver que este mensaje es sencillo, esta estructura MCI_GENERIC_PARMS se usa en los mensajes o comandos sencillo, y lo único que se pasa es el HWDN de la ventana que capturara el mensaje “notify” en caso que se haya especificado dicha constante en “wParam1”. PLAY wDeviceID = Aquí colocamos “wDeviceID” de la estructura MCI_OPEN_PARMS, después de ejecutar el comando MCI_OPEN uMessage = MCI_PLAY. wParam1 = Voy a poner los flag, que sirven para cualquier dispositivo, les dejo a ustedes documentarse sobre los otros flag: Private Const MCI_FROM = &H4& Private Const MCI_TO = &H8& wParam2 = en este parámetro pasamos la estructura: Private Type MCI_PLAY_PARMS dwCallback As Long dwFrom As Long dwTo As Long End Type Es intituitivo pensar, con los conocimientos ya visto, que se queremos que tome en cuenta los valores “dwFrom” y “dwTo”, tendremos que especificar en el parámetro “wParam1” los constantes vistas arriba. PAUSE wDeviceID = Aquí colocamos “wDeviceID” de la estructura MCI_OPEN_PARMS, después de ejecutar el comando MCI_OPEN uMessage = MCI_PAUSE. wParam1 = Cuando usamos MCI_CLOSE, lo unico que podemos poner aquí son las constante del mensaje “notify” o “wait”. wParam2 = en este parámetro pasamos la estructura: Private Type MCI_GENERIC_PARMS dwCallback As Long End Type RESUME wDeviceID = Aquí colocamos “wDeviceID” de la estructura MCI_OPEN_PARMS, después de ejecutar el comando MCI_OPEN uMessage = MCI_RESUME. wParam1 = Cuando usamos MCI_CLOSE, lo unico que podemos poner aquí son las constante del mensaje “notify” o “wait”. wParam2 = en este parámetro pasamos la estructura: Private Type MCI_GENERIC_PARMS dwCallback As Long End Type STOP wDeviceID = Aquí colocamos “wDeviceID” de la estructura MCI_OPEN_PARMS, después de ejecutar el comando MCI_OPEN uMessage = MCI_STOP. wParam1 = Cuando usamos MCI_CLOSE, lo único que podemos poner aquí son las constante del mensaje “notify” o “wait”. wParam2 = en este parámetro pasamos la estructura: Private Type MCI_GENERIC_PARMS dwCallback As Long End Type SET wDeviceID = Aquí colocamos “wDeviceID” de la estructura MCI_OPEN_PARMS, después de ejecutar el comando MCI_OPEN uMessage = MCI_SET. wParam1 = Voy a poner los flag, que sirven para cualquier dispositivo, les dejo a ustedes documentarse sobre los otros flag: Private Const MCI_SET_AUDIO = &H800& Private Const MCI_SET_AUDIO_ALL = &H4001&
Private Const MCI_SET_AUDIO_LEFT = &H4002&
Private Const MCI_SET_AUDIO_RIGHT = &H4003&
Private Const MCI_SET_DOOR_CLOSED = &H200& Private Const MCI_SET_DOOR_OPEN = &H100& Private Const MCI_SET_OFF = &H4000& Private Const MCI_SET_ON = &H2000& Private Const MCI_SET_TIME_FORMAT = &H400& Private Const MCI_FORMAT_BYTES = 8
Private Const MCI_FORMAT_FRAMES = 3
Private Const MCI_FORMAT_HMS = 1
Private Const MCI_FORMAT_MILLISECONDS = 0
Private Const MCI_FORMAT_MSF = 2
Private Const MCI_FORMAT_SAMPLES = 9
Private Const MCI_FORMAT_TMSF = 10
Private Const MCI_SET_VIDEO = &H1000& wParam2 = Pasamos la estructura: Private Type MCI_SET_PARMS dwCallback As Long dwTimeFormat As Long dwAudio As Long End Type Vamos a explicar mediante ejemplo como funciona las constantes marcadas en azul: setestructura.dwAudio = MCI_SET_AUDIO_ALL mciSendCommand(openestructura.wDeviceID , MCI_SET, MCI_SET_AUDIO or MCI_SET_ON, setestructura) En el caso del tiempo, es parecido: setestructura.dwTimeFormat = MCI_FORMAT_MILLISECONDS mciSendCommand(openestructura.wDeviceID , MCI_SET, Private Const MCI_SET_TIME_FORMAT = &H400& , setestructura) Con esto cubri los mensajes todos los mensajes que explique en mciSendString, se daran cuenta que en estos mensajes o constantes, no me preocupe por explicar que hacia cada constante, mi enfoque era que entendieran en como usar dichas constante ya que eso es lo mas difícil de entender, algunas constante cumplen la misma definición que los flag que usa mciSendString. Al igual que mciSendString, la función mciSendCommand lo que retorna es el valor que se usa en la función mciGetErrorString. SONIDO WAV (MCISENDCOMMAND) Ya visto la teoria, vamos al proyecto que usa dicha función. Primero dicho proyecto tendra que contener los siguientes componentes: Microsoft Common Dialog Control 6.0, Microsoft Windows Common Controls 6.0 (sp4). Con esto coponentes activados, procedemos a incluir los controles que presento a continuación: 4 Botones (Command). 2 Etiquetas (Label). 1 ProgressBar. 1 Slider 1 Caja de Texto (TextBox) 1 Timer Luego pegan este codigo en el formulario: Ver Codigo
Pueden ver que hace exactamente lo mismo, con la diferencia que use mciSendCommand, ahora vamos a ir explicando pasa a paso lo que se hizo:
Private Sub Command1_Click() . . . mciopen.wDeviceID = 0 mciopen.lpstrAlias = "archivowav1" mciopen.lpstrDeviceType = "waveaudio" mciopen.lpstrElementName = Text1.Text Preparo la estructura con la información basica. resultado = mciSendCommand(0, MCI_OPEN, MCI_OPEN_ALIAS Or MCI_OPEN_TYPE Or MCI_OPEN_ELEMENT, mciopen) Especifico las constantes necesarias en “wParam1”, para que la función tome en cuenta los valores de la estructura. BuscarError resultado mciset.dwTimeFormat = MCI_FORMAT_MILLISECONDS resultado = mciSendCommand(mciopen.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, 0) BuscarError resultado Configuro el formato del tiempo, para que sea en milisegundos- mcistatus.dwItem = MCI_STATUS_LENGTH resultado = mciSendCommand(mciopen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, mcistatus) Recupero la longitud, en el formato configurado arriba, es decir, recupero la cantidad de milisegundos que posee el archivo. BuscarError resultado If mcistatus.dwReturn <> 0 Then ProgressBar1.Min = 1 ProgressBar1.Max = mcistatus.dwReturn ProgressBar1.Value = 1 Slider1.Min = 1 Slider1.Max = mcistatus.dwReturn Slider1.Value = 1 Label2.Caption = formatotiempo(mcistatus.dwReturn) End If End Sub Botón “play”: Timer1.Enabled = True Activo el timer. mciplay.dwFrom = 0 Especifico que empiece desde el milisegundo 0. resultado = mciSendCommand(mciopen.wDeviceID, MCI_PLAY, MCI_FROM, mciplay) Vean que especifico MCI_FROM para que tome en cuenta el valor que le paso en la estructura. BuscarError resultado Botón “Stop”: resultado = mciSendCommand(mciopen.wDeviceID, MCI_STOP, 0, 0) Detengo la ejecucion. BuscarError resultado Timer1.Enabled = False Botón “Pause”: If Command4.Caption = "Pausa" Then resultado = mciSendCommand(mciopen.wDeviceID, MCI_PAUSE, 0, 0) Coloco en “pausa” la ejecución BuscarError resultado Command4.Caption = "Continuar" Else resultado = mciSendCommand(mciopen.wDeviceID, MCI_RESUME, 0, 0) Continuo la ejecución de archivo BuscarError resultado Command4.Caption = "Pausa" End If En el Timer: mcistatus.dwItem = MCI_STATUS_POSITION resultado = mciSendCommand(mciopen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, mcistatus) Busco la posicion actual en “milisegundo” que se esta ejecutando BuscarError resultado . . . ¿mciSendString o mciSendCommand? Ya vimos como funciona cada función, la decisión ahora esta en como saber cual usar, y yo les digo usen con la que ustedes se sientan mas comodo, particularmente yo prefiero mciSendString aunque en teoria mciSendCommand debería de ser mas rapida, y esto se debe a que la cadena de string donde pasamos el mensaje, internamente la función la convierte en comandos, es decir, internamente trabaja como la función mciSendCommand, pero es obvio ver el ahorro del codigo y la facilidad de usar la cadena de mensajes en ves de las constantes y estructuras de la función mciSendCommand. VIDEO AVI (MCISENDSTRING) Ya visto la teoria, vamos al proyecto que usa dicha función. Primero dicho proyecto tendra que contener los siguientes componentes: Microsoft Common Dialog Control 6.0, Microsoft Windows Common Controls 6.0 (sp4). Con esto coponentes activados, procedemos a incluir los controles que presento a continuación: 4 Botones (Command). 2 Etiquetas (Label). 1 ProgressBar. 1 Slider 1 Caja de Texto (TextBox) 1 Timer 1 Picture Luego pegan este codigo en el formulario: Ver Codigo
CD AUDIO (MCISENDSTRING) Ya visto la teoria, vamos al proyecto que usa dicha función. Primero dicho proyecto tendra que contener los siguientes componentes: Microsoft Common Dialog Control 6.0, Microsoft Windows Common Controls 6.0 (sp4). Con esto coponentes activados, procedemos a incluir los controles que presento a continuación: 5 Botones (Command). 2 Etiquetas (Label). 1 ProgressBar. 1 Slider 1 Caja de Texto (TextBox) 1 Timer Luego pegan este codigo en el formulario: Ver Codigo
VOLUMEN Sabemos ahora como ejecutar archivos multimedia, pero como manipular el volumen de cada dispositivo de salida, si abren “Volumen Control” veran varias columnas en donde pueden manipular los volúmenes de cada dispositivo. ¿Cómo hacer un programa que haga eso?. Para este proyecto son necesarios los siguientes controles: 3 Hscroll o Scroll Horizontales 4 Label o etiquetas. 1 listbox Necesitan tener el archivo “TLBINF32.DLL” en el Windows/System, en caso de no tenerlo, en el zip que contiene este manual, ahí esta. Luego pegen este codigo: Ver Codigo
Cuando arranquen verán un listbox, que debera de contener todos los dispositivos de salida que poseen, al darle clic a cada dispositivo se configuran los Scroll dependiendo del volumen que tengan en ese momento, si alteran los Scroll con una música activada verán que altera el volumen. Antes de explicar las funciones que intervienen en ello, vamos a dejar en claro, para Windows no existe un volumen MASTER, es decir, el Hscroll3 que representa un volumen global, dicho volumen Windows no lo maneja de esa manera, para Windows existe 2 volumenes derecho “right” e izquierdo “left” el control hScroll3 se programa de tal manera que altere ambos volúmenes. Ya veremos eso con mas detalle. La primera función a estudiar sera la que no spermite saber cuantos dispositivos de salida tenemos. auxGetNumDevs Api: Declare Function auxGetNumDevs Lib "winmm.dll" () As Long Esta función se encarga de retornar la cantidad de dispositivos que posee configurado Windows. Dicha cantidad se encuentra en el valor que la función devuelve. auxGetDevCaps Api: Declare Function auxGetDevCaps Lib "winmm.dll" Alias "auxGetDevCapsA" (ByVal uDeviceID As Long, lpCaps As AUXCAPS, ByVal uSize As Long) As Long Esta función toma información, de un dispositivo de audio, dicha información se almacena en la estructura AUXCAPS. Como primer parámetro pasamos el ID del dispositivo a consultar, como segundo parámetro “lpCaps” le pasamos la estructura que almacenara la información, y como último parámetro le pasamos el tamaño de la estructura. Estructura: Private Type AUXCAPS wMid As Integer ‘ Identificador del fabricante wPid As Integer ‘ Identificador del producto vDriverVersion As Long ‘ version del driver szPname As String * MAXPNAMELEN ‘ Nombre del dispositivo wTechnology As Integer ‘ Tipo de salida. dwSupport As Long ‘ Establece si soporta ambos volumenes Izquierdo y derecho. End Type Particularmente solo vamos a usar “szPname”. auxGetVolume Api: Declare Function auxGetVolume Lib "winmm.dll" (ByVal uDeviceID As Long, ByRef lpdwVolume As Long) As Long Con esta función tomamos el valor del volumen de cierto dispositivo, el dispositivo es indicado en el primer parametro “uDeviceID”, en el segundo parametro le pasamos una variable de tipo “long” donde se alamacena el volumen. Dicho volumen tiene algo peculiar, ya que mencione que el volumen se divide en 2 partes derecha y parte izquierda. La parte alta de la variable “lpdwVolume” posee el volumen de la salida izquierda y la parte baja posee el volumen de la parte derecha. Esto significa que si la variable “lpdwVolume” es de 32 bits, cada volumen es de 16 Bits, con esto deducimos que el volumen de cada salida va desde 0 hasta 65535. auxSetVolume Api: Declare Function auxSetVolume Lib "winmm.dll" (ByVal uDeviceID As Long, ByVal dwVolume As Long) As Long Esta función le asigna un nuevo volumen a un dispositivo de salida, dicho dispositivo se especifica en el primer parametro, y en el segundo parametro se especifica el nuevo volumen. ¿Pero el volumen no se divide en dos izquierda-derecha? Cierto, la parte alta de “dwVolume” contendra el nuevo volumen izquierdo y y la parte baja tendra el volumen derecho. Seguramente creen que es sencillo manejar esto, ciertamente si estuviéramos en C o C++ sería facil, pero en VB hay que usar truquitos para hacer funcionar esto. Por ejemplo: como poner el volumen izquierdo en la parte alta y como poner el volumen derecho en la parte baja. Todo eso vamos a verlo directo con las líneas del código. Empecemos en el LOAD: Dim ac As AUXCAPS For Cnt = 0 To auxGetNumDevs – 1 ‘ Por cada dispositivo que existe tomamos su información. auxGetDevCaps Cnt, ac, Len(ac) ‘ List1.AddItem Left(ac.szPname, InStr(ac.szPname, vbNullChar) - 1) Next List1_Click: auxGetVolume List1.ListIndex, Vol Obtengo el volumen del dispositivo seleccionado leftV = hiword(Abs(Vol)) rightV = loword(Abs(Vol)) Separamos los volumenes izquierdo y derechos. valorleft = (leftV * 100) \ 65535 valorright = (rightV * 100) \ 65535 Lo llevamos a una escala de 100. If valorleft > valorright Then HScroll3.Value = valorleft HScroll1.Value = 100 HScroll2.Value = valorright End If If valorright > valorleft Then HScroll3.Value = valorright HScroll1.Value = valorleft HScroll2.Value = 100 End If If valorright = valorleft Then HScroll3.Value = valorright HScroll1.Value = 100 HScroll2.Value = 100 End If Configuramos cada scroll con su valor correspondiente. Función “CalculoVolumen”: Dim v As Vol Creo una variable del tipo “Vol”, “Vol” es una estructura que posee 2 variables integer, dicha estructura la vamos a usar para hacer un truco. v.vleft = (HScroll2.Value * HScroll3.Value) / 100 v.vright = (HScroll1.Value * HScroll3.Value) / 100 Dependiendo del volumen “general”, configuro los volumenes para cada lado, recuerden que ustedes pueden alterar el volumen de ambos al mismo tiempo por el Hscroll3, dichos cambios se reflejan con estos calculos. vleft = (v.vleft * 65535) / 100 vright = (v.vright * 65535) / 100 Los calculos que estan en una escala de 100 los convierto a una escala desde 0 hasta 65535. Estas variables vleft y vright pueden llegar hasta 65535 ya que son del tipo LONG. If vright > 32767 Then v.vright = vright - 65536 Else v.vright = vright End If If vleft > 32767 Then v.vleft = vleft - 65536 Else v.vleft = vleft End If Llevo el volumen a un formato que puede entender la función. Vean que los valores negativos se valen, ya que las función sabe interpretarlos. CopyMemory vTotal, v.vleft, Len(v) CopyMemory, es casi idéntico a la función visto en el capitulo de “menu” que se llamaba MoveMemory. Con esto lo que hacemos es poner de manera correcta la información en la variable vTotal. Es decir, la parte alta de Vtotal tendra el volumen izquierdo y la parte baja tendra el volumen derecho, por esa razón la estructura es así:
Private Type Vol vleft As Integer vright As Integer End Type auxSetVolume List1.ListIndex, vTotal Configuramos el nuevo volumen. End Sub Con esto finalizamos la parte de multimedia, existen muchas funciones que manipulan los diferentes dispositivos multimedia, pero creo que cubri las mas importantes.
|