Are there any tutorials on creating onscreen displays? So far I have working code that lowers and raises the sound volume when a certain hotkey combinations are pressed but I would like a status indicator as well. How would I actually go about creating the status indicator and not have it interfere with other things on the screen?
I have some code that manipulates the windows volume controls, but I'm not sure it's what you're after. Can you define what you want any better?
Ehtyar.
I already have code that raises, lowers and mutes the sound volume. Thanks for the offer. You know when you press the volume buttons on a TV remote and it displays a volume status indicator on the screen? That's what I would like to be able to do. A friend of mine has Media Center 2005 and it has that functionality and I thought it would be "cool" to do that.
I haven't touched (until recently) assembly language for about 10 years or so and picked it up again just to have something to pass idle time.
Could you not catch the vscroll/hscroll message from the scrollbar (which you would already need to do to adjust the sound itself) and increase the step of a progress bar to match? I can probably code you an example of some kind if you're really hard pressed to work it out.
Hope this helps, Ehtyar.
I think you're probably after some GDI code. There are a number of examples in the MASM32 package - possibly BARCHART is one that may interest you. You can probably extend your search for examples coded in C also, since this stuff is mostly API calls. You can either draw directly onto the screen, though this could stuff things up beneath it unless you're careful, or you can create a little window to draw on and hide it when it's not needed. There's plenty of examples to work from.
Cheers,
Zooba :U
What he's talking about is essentially a screen overlay - which is handled by the media centre itself, rather than the cpu - it draws a volume indicator 'in front' of the screen.
One way to achieve this is to create an "on-top" popup window, which will appear in-front of the other windows (you could make it semi-transparent) for a short time to indicate the volume change/current level. It would, however, be clickable and possibly moveable without a little extra code to handle this. It could also still be hidden behind other on-top windows.
The other alternative, which is a little more difficult is to write directly to video memory after everything else has been drawn, so it appears on top. Newer video cards do support this (this is how the mouse pointer is usually drawn) but windows won't allow you direct access to it.
I'd go with the 'window' method, unless it's totally unsatisfactory (most of the time it won't be a problem.)
Quote from: Tedd on November 30, 2006, 01:02:24 PM
The other alternative, which is a little more difficult is to write directly to video memory after everything else has been drawn, so it appears on top.
You can draw to the desktop window and get the same effect, though you do run the risk of corrupting other windows if they don't fully redraw themselves. GetDC(0) will give the device context of the entire screen. This is what I was suggesting, rather than direct to video memory :bg
a) have a Scroll bar on a pop-up window
b) filter the WM_INITDIALOG where: you read the current Volume level and update the Scroll bar accordingly
c) in the WndProc you handle any Scroll bar changes, too:
.ELSEIF eax == WM_HSCROLL
mov eax,wParam
invoke WndProcScroll
return 0
d) to update the Scroll bar:
align
WndProcScroll PROC USES edx
mov edx,eax
and eax,0FFFFh
.if eax == TB_THUMBTRACK or TB_THUMBPOSITION
shr edx,16
invoke SetMstrVolume,edx ;Set the new volume control value
.elseif eax == TB_LINEUP || eax == TB_LINEDOWN || eax == TB_PAGEUP || eax == TB_PAGEDOWN || eax == TB_TOP || eax == TB_BOTTOM
invoke SendDlgItemMessage,hWnd,scVolume,TBM_GETPOS,0,0
invoke SetMstrVolume,eax
.endif
ret
WndProcScroll ENDP
These fragments belong to code I used once.
To read and set the Volume I used some pretty code written by William F. Cravener (year 2003)
hope it helps
Ok, I have code. I did this in C and it works. I assemble and link the code below and it causes DEP errors on XP SP2. :( Can someone please take a look and tell me where the problem is?
.486
.model flat, stdcall
option casemap:none
include windows.inc
include kernel32.inc
include shell32.inc
include user32.inc
include gdi32.inc
include winmm.inc
includelib kernel32.lib
includelib shell32.lib
includelib user32.lib
includelib gdi32.lib
includelib winmm.lib
chr$ MACRO any_text:VARARG
LOCAL txtname
.data
txtname db any_text,0
.code
EXITM <OFFSET txtname>
ENDM
RegisterWindowMessage proto :DWORD
DeregisterShellHookWindow proto :DWORD
RegisterShellHookWindow proto :DWORD
.const
MIXER_ERROR equ 0FFFFFFFFh
DST_FIRST equ 0
DST_UNDEFINED equ 0
DST_DIGITAL equ 1
DST_LINE equ 2
DST_MONITOR equ 3
DST_HEADPHONES equ 5
DST_TELEPHONE equ 6
DST_WAVEIN equ 7
DST_VOICEIN equ 8
DST_LAST equ 8
DST_SPEAKERS equ 4 ; master volume
SRC_FIRST equ 1000h
SRC_UNDEFINED equ 1000h + 0
SRC_DIGITAL equ 1000h + 1 ; spdif vol
SRC_LINE equ 1000h + 2 ; linein2 vol
SRC_MICROPHONE equ 1000h + 3
SRC_SYNTHESIZER equ 1000h + 4 ; midi vol
SRC_COMPACTDISC equ 1000h + 5
SRC_TELEPHONE equ 1000h + 6
SRC_PCSPEAKER equ 1000h + 7
SRC_WAVEOUT equ 1000h + 8 ; wav vol
SRC_AUXILIARY equ 1000h + 9
SRC_ANALOG equ 1000h + 10 ;aux2 vol
SRC_LAST equ 1000h + 10
_NOERROR equ 0
_ERROR equ 1
_BADDEVICEID equ 2
_NOTENABLED equ 3
_ALLOCATED equ 4
_INVALHANDLE equ 5
_NODRIVER equ 6
_NOMEM equ 7
_NOTSUPPORTED equ 8
_BADERRNUM equ 9
_INVALFLAG equ 10
_INVALPARAM equ 11
_HANDLEBUSY equ 12
_INVALIDALIAS equ 13
_LASTERROR equ 13
.data
mxc MIXERCONTROL <?>
mxcd MIXERCONTROLDETAILS <?>
mxcdu MIXERCONTROLDETAILS_UNSIGNED <?>
mxcdb MIXERCONTROLDETAILS_BOOLEAN <?>
mxlc MIXERLINECONTROLS <?>
mxl MIXERLINE <?>
MixerHandle DWORD ?
VolumeControlId DWORD ?
MuteControlId DWORD ?
.code
OpenMixer proc
local temp:DWORD
invoke mixerOpen, addr temp, 0, 0, 0, 0
.if eax != MMSYSERR_NOERROR
mov temp, -1
.endif
mov eax, temp
ret
OpenMixer endp
GetVolumeControlId proc cType:DWORD
mov mxl.cbStruct, sizeof MIXERLINE
mov eax, cType
mov mxl.dwComponentType, eax
invoke mixerGetLineInfo, MixerHandle, addr mxl, MIXER_GETLINEINFOF_COMPONENTTYPE
mov eax, mxl.dwLineID
mov mxlc.dwLineID, eax
mov mxlc.cbStruct, sizeof mxlc
mov mxlc.dwControlType, MIXERCONTROL_CONTROLTYPE_VOLUME
mov mxlc.cControls, 1
mov mxlc.cbmxctrl, sizeof MIXERCONTROL
mov mxlc.pamxctrl, offset mxc
invoke mixerGetLineControls, MixerHandle, addr mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE
mov eax, mxc.dwControlID
ret
GetVolumeControlId endp
GetMuteControlId proc cType:DWORD
mov mxl.cbStruct, sizeof MIXERLINE
mov eax, cType
mov mxl.dwComponentType, eax
invoke mixerGetLineInfo, MixerHandle, addr mxl, MIXER_GETLINEINFOF_COMPONENTTYPE
mov eax, mxl.dwLineID
mov mxlc.dwLineID, eax
mov mxlc.cbStruct, sizeof mxlc
mov mxlc.dwControlType, MIXERCONTROL_CONTROLTYPE_MUTE
mov mxlc.cControls, 1
mov mxlc.cbmxctrl, sizeof MIXERCONTROL
mov mxlc.pamxctrl, offset mxc
invoke mixerGetLineControls, MixerHandle, addr mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE
mov eax, mxc.dwControlID
ret
GetMuteControlId endp
GetMixerVolume proc uses esi cType:DWORD
mov edi, offset mxcd
xor eax, eax
mov ecx, sizeof MIXERCONTROLDETAILS
rep stosd
mov mxcd.cbStruct, size MIXERCONTROLDETAILS
mov mxcd.hwndOwner, 0
mov mxcd.cChannels, 1
mov mxcd.cbDetails, size MIXERCONTROLDETAILS_UNSIGNED
invoke GetVolumeControlId, cType
mov mxcd.dwControlID, eax
mov mxcd.paDetails, offset mxcdu
invoke mixerGetControlDetails, MixerHandle, addr mxcd, MIXER_SETCONTROLDETAILSF_VALUE
mov ecx, mxcdu.dwValue
mov eax, 903847ebh
mul ecx
mov eax, ecx
sub eax, edx
shr eax, 1
add eax, edx
shr eax, 9
ret
GetMixerVolume endp
GetMixerMute proc uses edi cType:DWORD
mov edi, offset mxcd
xor eax, eax
mov ecx, sizeof MIXERCONTROLDETAILS
rep stosd
mov mxcd.cbStruct, sizeof MIXERCONTROLDETAILS
mov mxcd.hwndOwner, 0
mov mxcd.cChannels, 1
mov mxcd.cbDetails, sizeof MIXERCONTROLDETAILS_BOOLEAN
invoke GetMuteControlId, cType
mov mxcd.dwControlID, eax
mov mxcd.paDetails, offset mxcdb
invoke mixerGetControlDetails, MixerHandle, addr mxcd, MIXER_SETCONTROLDETAILSF_VALUE
mov eax, mxcdb.fValue
ret
GetMixerMute endp
CloseMixer proc
invoke mixerClose, addr MixerHandle
ret
CloseMixer endp
.const
WM_SHELLNOTIFY equ WM_APP + 1
IDM_VOLUMEDOWN equ WM_APP + 2
IDM_VOLUMEUP equ WM_APP + 3
IDM_VOLUMEMUTE equ WM_APP + 4
ID_TRAY equ 1000
ID_ABOUT equ 1001
ID_EXIT equ 1002
.data
OSDWindow DWORD ?
hInstance DWORD ?
WM_SHELLHOOK DWORD 0ffffffffh
WM_TASKBARCREATED DWORD 0ffffffffh
hPopupMenu HMENU ?
hFont HFONT ?
nid NOTIFYICONDATA <?>
brBrush HBRUSH 2 dup(?)
hIcon HICON 2 dup(?)
dwCurrentVolume DWORD ?
hdc HDC ?
bMuted BOOL ?
.code
VolumeDisplayProc proc uses ebx esi edi, hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
local pt:POINT
local rct:RECT
local ps:PAINTSTRUCT
local buff[6]:BYTE
mov eax, WM_SHELLHOOK
cmp eax, -1
je $$is_taskbar_msg
cmp uMsg, eax
jne $$is_taskbar_msg
cmp wParam, HSHELL_APPCOMMAND
jne $$is_taskbar_msg
mov eax, lParam
shr eax, 16
and eax, 0fffh
cmp eax, APPCOMMAND_VOLUME_UP
mov ecx, IDM_VOLUMEUP
je $$acvu
cmp eax, APPCOMMAND_VOLUME_DOWN
mov ecx, IDM_VOLUMEDOWN
je $$acvd
cmp eax, APPCOMMAND_VOLUME_MUTE
mov ecx, IDM_VOLUMEMUTE
je $$acvm
jmp $$is_taskbar_msg
$$acvu:
$$acvd:
$$acvm:
invoke PostMessage, hWnd, WM_COMMAND, ecx, 0
jmp $$default
$$is_taskbar_msg:
mov eax, uMsg
cmp eax, WM_TASKBARCREATED
jne $$fall_thru
mov nid.cbSize, sizeof NOTIFYICONDATA
push hWnd
pop nid.hwnd
mov nid.uID, ID_TRAY
mov nid.uFlags, NIF_ICON or NIF_MESSAGE or NIF_TIP
mov nid.uCallbackMessage, WM_SHELLNOTIFY
mov eax, bMuted
mov ecx, hIcon[eax*4]
mov nid.hIcon, ecx
invoke lstrcpy, addr nid.szTip, chr$("OnScreen Volume Display")
invoke Shell_NotifyIcon, NIM_ADD, addr nid
jmp $$default
$$fall_thru:
cmp eax, WM_CREATE
je $$wm_create
cmp eax, WM_PAINT
je $$wm_paint
cmp eax, WM_TIMER
je $$wm_timer
cmp eax, WM_COMMAND
je $$wm_command
cmp eax, WM_CLOSE
je $$wm_close
cmp eax, WM_DESTROY
je $$wm_destroy
cmp eax, MM_MIXM_CONTROL_CHANGE
je $$control_change
cmp eax, WM_SHELLNOTIFY
je $$wm_shellnotify
jmp $$default
$$wm_create:
invoke OpenMixer
mov MixerHandle, eax
invoke GetMixerVolume, DST_SPEAKERS
mov dwCurrentVolume, eax
invoke GetMixerMute, DST_SPEAKERS
mov bMuted, eax
invoke CreateFont, 20, 0, 0, 0, FW_THIN, 0, 0, 0, 0, 0, ANTIALIASED_QUALITY, 0, 0, chr$("Arial")
mov hFont, eax
invoke CreateSolidBrush, Green - 150
mov brBrush[0], eax
invoke CreateSolidBrush, Green
mov brBrush[4], eax
invoke LoadIcon, hInstance, 1
mov hIcon[0], eax
invoke LoadIcon, hInstance, 2
mov hIcon[4], eax
mov nid.cbSize, sizeof NOTIFYICONDATA
push hWnd
pop nid.hwnd
mov nid.uID, ID_TRAY
mov nid.uFlags, NIF_ICON or NIF_MESSAGE or NIF_TIP
mov nid.uCallbackMessage, WM_SHELLNOTIFY
mov eax, bMuted
mov ecx, hIcon[eax*4]
mov nid.hIcon, ecx
invoke lstrcpy, addr nid.szTip, chr$("OnScreen Volume Display")
invoke Shell_NotifyIcon, NIM_ADD, addr nid
invoke CreatePopupMenu
mov hPopupMenu, eax
invoke AppendMenu, hPopupMenu, MF_STRING, ID_ABOUT, chr$("About")
invoke AppendMenu, hPopupMenu, MF_STRING, ID_EXIT, chr$("Quit")
invoke RegisterShellHookWindow, hWnd
invoke GetCurrentProcess
invoke SetProcessWorkingSetSize, eax, -1, -1
mov eax, 0
ret
$$wm_paint:
invoke BeginPaint, hWnd, addr ps
mov hdc, eax
push esi
push edi
xor esi, esi
xor edi, edi
@@:
invoke SetRect, addr rct, esi, 62, addr [esi+2], 76
cmp edi, dwCurrentVolume
sbb eax, eax
neg eax
mov ecx, brBrush[eax*4]
invoke FillRect, hdc, addr rct, ecx
add esi, 6
inc edi
cmp esi, 600
jb @B
pop edi
pop esi
invoke SetRect, addr rct, 0, 59, 598, 60
invoke FillRect, hdc, addr rct, brBrush[0]
invoke SetRect, addr rct, 0, 78, 598, 79
invoke FillRect, hdc, addr rct, brBrush[4]
invoke SelectObject, hdc, hFont
invoke SetTextColor, hdc, 005B7B8Ch
invoke SetRect, addr rct, 0, 38, 598, 58
invoke DrawTextEx, hdc, chr$("MASTER VOLUME"), -1, addr rct, DT_LEFT, 0
invoke wsprintf, addr buff, chr$("%d %%"), dwCurrentVolume
invoke DrawTextEx, hdc, addr buff, -1, addr rct, DT_CENTER, 0
cmp bMuted, 1
jne @F
invoke SetTextColor, hdc, Red
invoke DrawTextEx, hdc, chr$("MUTE"), -1, addr rct, DT_RIGHT, 0
@@:
invoke EndPaint, hWnd, addr ps
mov eax, 0
ret
$$wm_timer:
invoke KillTimer, hWnd, 1
invoke GetCurrentProcess
invoke SetProcessWorkingSetSize, eax, -1, -1
invoke ShowWindow, hWnd, FALSE
mov eax, 0
ret
$$wm_shellnotify:
cmp wParam, ID_TRAY
jne @F
cmp lParam, WM_RBUTTONUP
jne @F
invoke GetCursorPos, addr pt
invoke SetForegroundWindow, hWnd
invoke TrackPopupMenu, hPopupMenu, TPM_RIGHTALIGN or TPM_RIGHTBUTTON, pt.x, pt.y, 0, hWnd, 0
@@:
mov eax, 0
ret
$$control_change:
invoke GetMixerVolume, DST_SPEAKERS
mov dwCurrentVolume, eax
invoke GetMixerMute, DST_SPEAKERS
mov bMuted, eax
mov eax, 0
ret
$$wm_close:
invoke Shell_NotifyIcon, NIM_DELETE, addr nid
invoke CloseMixer
invoke DestroyMenu, hPopupMenu
invoke DeleteObject, brBrush[0]
invoke DeleteObject, brBrush[4]
invoke DeleteObject, hIcon[0]
invoke DeleteObject, hIcon[4]
invoke DeleteObject, hFont
invoke DeleteObject, hWnd
jmp $$default
$$wm_destroy:
invoke PostQuitMessage, 0
invoke DeregisterShellHookWindow, hWnd
or WM_SHELLHOOK, 0ffffffffh
jmp $$default
$$wm_command:
cmp lParam, 0
jne $$nope
movzx eax, word ptr wParam
cmp eax, ID_ABOUT
je $$about
cmp eax, ID_EXIT
je $$exit
cmp eax, IDM_VOLUMEUP
je $$vup
cmp eax, IDM_VOLUMEDOWN
je $$vdn
cmp eax, IDM_VOLUMEMUTE
je $$vmt
$$nope:
mov eax, 0
ret
$$about:
invoke EnableMenuItem, hPopupMenu, 0, MF_DISABLED or MF_GRAYED or MF_BYPOSITION
invoke MessageBox, 0, \
chr$("OnScreen Volume Display",13,10,"Version .01",13,10,13,10,"-= More to come =-"), \
chr$("OnScreen Volume Display"), MB_OK
invoke EnableMenuItem, hPopupMenu, 0, MF_ENABLED or MF_BYPOSITION
invoke GetCurrentProcess
invoke SetProcessWorkingSetSize, eax, -1, -1
mov eax, 0
ret
$$exit:
invoke SendMessage, hWnd, WM_CLOSE, 0, 0
mov eax, 0
ret
$$vup:
$$vdn:
invoke GetMixerVolume, DST_SPEAKERS
mov dwCurrentVolume, eax
@@:
invoke InvalidateRect, hWnd, 0, 1
invoke ShowWindow, OSDWindow, TRUE
invoke SetTimer, OSDWindow, 1, 2000, 0
mov eax, 0
ret
$$vmt:
invoke GetMixerMute, DST_SPEAKERS
mov bMuted, eax
mov ecx, hIcon[eax*4]
mov nid.hIcon, ecx
invoke Shell_NotifyIcon, NIM_MODIFY, addr nid
jmp @B
$$default:
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
VolumeDisplayProc endp
WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, lpCmdLine:LPSTR, nCmdShow:DWORD
local hMutex:HANDLE
local wc:WNDCLASSEX
local msg:MSG
local dwWidth:DWORD
local dwHeight:DWORD
invoke CreateMutex, 0, 0, chr$("OSD.01")
mov hMutex, eax
invoke GetLastError
cmp eax, ERROR_ALREADY_EXISTS
jne $0
invoke MessageBox, 0, chr$("Program is already running."), chr$("OnScreen Volume Display"), MB_OK
cmp hMutex, 0
jz $1
invoke CloseHandle, hMutex
$1:
mov eax, 0
ret
$0:
lea edi, wc
xor eax, eax
mov ecx, sizeof wc
rep stosd
mov wc.cbSize, sizeof WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
push hInst
pop wc.hInstance
mov wc.lpfnWndProc, offset VolumeDisplayProc
invoke LoadCursor, 0, IDC_ARROW
mov wc.hCursor, eax
invoke GetStockObject, WHITE_BRUSH
mov wc.hbrBackground, eax
mov wc.lpszClassName, chr$("**OSD**")
invoke RegisterClassEx, addr wc
invoke RegisterWindowMessage, chr$("SHELLHOOK")
mov WM_SHELLHOOK, eax
invoke RegisterWindowMessage, chr$("TaskbarCreated")
mov WM_TASKBARCREATED, eax
invoke GetSystemMetrics, SM_CXSCREEN
sub eax, 600
cdq
sub eax, edx
sar eax, 1
mov dwWidth, eax
invoke GetSystemMetrics, SM_CYSCREEN
cdq
sar eax, 1
mov dwHeight, eax
invoke CreateWindowEx, WS_EX_LAYERED or WS_EX_TOOLWINDOW or WS_EX_TOPMOST or WS_EX_TRANSPARENT, \
chr$("**OSD**"), 0, WS_POPUP, dwWidth, dwHeight, 600, 90, 0, 0, hInst, 0
mov OSDWindow, eax
invoke SetLayeredWindowAttributes, OSDWindow, 0fffffffh, 0, LWA_COLORKEY
@@:
Invoke GetMessage,ADDR msg,NULL,0,0
cmp eax, 0
jz @F
invoke TranslateMessage, addr msg
invoke DispatchMessage, addr msg
jmp @B
@@:
.if hMutex
invoke CloseHandle, hMutex
.endif
mov eax, 0
ret
WinMain endp
StartupCode:
invoke GetModuleHandle, 0
mov hInstance, eax
invoke GetCommandLine
invoke WinMain, hInstance, 0, eax, SW_SHOWDEFAULT
invoke ExitProcess, eax
end StartupCode
[attachment deleted by admin]
I don't know how this might help with this topic, but it is an Interesting program that controls volume with the middle scroll wheel on the mouse. No source code, but a program I use all the time. it is a free program, and quite useful. You might like to check this one out.
http://www.nirsoft.net/utils/volumouse.html
Anunitu
Cobra,
I took a look at your code. I think I see one problem in WinMain.
$0:
lea edi, wc
xor eax, eax
mov ecx, sizeof wc
rep stosd
Shouldn't the rep stosd be rep stosb?
After changing that, the program runs with no errors. There is an icon in the system tray with a context menu, but I don't see anything else on the screen. I'll look at it more when I get some time. BTW, I'm running XP Pro SP2.
Ahhh, right you are Greg. I feel so stupid. The rep stosd is correct but I forgot to divide the size of the structures by 4. There are 2 other locations in the mixer code that had incorrect structure sizes set as well. It's kinda funny that you sometimes can't see what's in front of your face. Everything works now. Time to do some major code cleanup and organize it better (the code is crap ATM).
If you have a keyboard that has multimedia keys (volume up, volume down and mute) those control on onscreen volume meter.
Cobra,
Quote from: CobraIt's kinda funny that you sometimes can't see what's in front of your face.
I've been there many times.
where are the "DeregisterShellHookWindow proto :DWORD
RegisterShellHookWindow proto :DWORD
"?
They are in the user32.lib from the Platform SDK. They aren't defined in the MASM package.
Hi to all:
Mr Cobra:
It seems to me that, you can here obtain something.
http://website.masm32.com/files/td_win32asm_all.zip
Excuses if I am mistaken.
Bye('_').