<-- Capítulo VI

Regresar a la página principal

Capítulo VIII -->

Capítulo VII

Teclado, Mouse y Multimedia

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.

<-- Capítulo VI

Regresar arriba

Regresar a la página principal

Capítulo VIII -->

Desarrollado por Eduardo Roa. Copyright 2002-2003 Todos los derechos reservados