From: Perl R. <pe...@co...> - 2008-12-08 04:46:58
|
Well, I figured it out. Hopefully this will help someone else. It turns out that editing the registry is not necessary. I simply had to send the WM_COMMAND message (which means a command was selected from a menu) and a specific message number (which, for locking/unlocking the taskbar, happens to be 424). Here's the code in its entirety-just 3 lines. I decided to use SendMessageTimeout() in case the taskbar doesn't respond: use Win32::GUI qw(WM_COMMAND); my $taskbar = Win32::GUI::FindWindow("Shell_TrayWnd", ""); Win32::GUI::SendMessageTimeout($taskbar, WM_COMMAND, 424, 0, 0, 1000); By the way, I found a list of message numbers in the 3rd post here (although I'm still not sure where these message numbers are actually defined): http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/eb0b17d6- 66de-4ce6-bb3a-0c174a17991e -Rob _____ From: Perl Rob [mailto:pe...@co...] Sent: Sunday, December 07, 2008 8:18 PM To: 'per...@li...' Subject: Refresh the taskbar Hi all, I've been banging my head against this one for the last several hours, so I'll buy a beer for the man or woman who helps me figure it out! :-) Quite simply, all I'm trying to do is programmatically toggle the "Lock the Taskbar" setting. However, I can't get the taskbar to refresh itself after I toggle the setting (I have to hover my mouse over the taskbar and press F5). I thought I could do it in two steps: 1. Set the pertinent registry value to 1 (not locked) or 0 (locked). 2. Then send the HWND_BROADCAST message to all windows using the SendMessageTimeout() function. Here's the code: use Win32::TieRegistry( Delimiter=>"/" ); $Registry->{"CUser/Software/Microsoft/Windows/CurrentVersion/Explorer/Advanc ed//TaskbarSizeMove"} = [ pack("L",1), "REG_DWORD" ]; use Win32::API; use constant HWND_BROADCAST => 65535; use constant WM_SETTINGCHANGE => 26; my $SendMessageTimeout = new Win32::API('user32', 'SendMessageTimeout', 'NNNNNNN', 'N'); $SendMessageTimeout->Call(HWND_BROADCAST, WM_SETTINGCHANGE, 0, "Windows", SMTO_BLOCK, 1000, undef); This code almost works. The setting is toggled in the registry and the desktop refreshes itself...but the taskbar stays the same unless I manually refresh it. Since broadcasting the message didn't work, I decided to get the taskbar handle and send the message only to it: use Win32::GUI(); my $taskbar = Win32::GUI::FindWindow("Shell_TrayWnd", ""); Win32::GUI::SendMessage($taskbar, WM_SETTINGCHANGE, undef, "HKEY_CURRENT_USER"); This doesn't work either, so I decided to call invalidateRect() on the taskbar: Win32::GUI::InvalidateRect($taskbar, 0, 0, Win32::GUI::Width($taskbar), Win32::GUI::Height($taskbar), 1); Still nothing, so I tried calling Hide() and Show() on the taskbar Win32::GUI::Hide($taskbar); sleep(1); # To make sure it's hiding Win32::GUI::Show($taskbar); It hides and shows, but the setting still isn't taking effect! I get the feeling I'm going about this all wrong, but I'm running out of ideas (and I've searched all over MSDN). Any ideas? Thanks, Rob |
From: Robert M. <ro...@th...> - 2008-12-08 10:50:00
|
2008/12/8 Perl Rob <pe...@co...>: > It turns out that editing the registry is not necessary. I simply had to > send the WM_COMMAND message (which means a command was selected from a menu) > and a specific message number (which, for locking/unlocking the taskbar, > happens to be 424). Here's the code in its entirety—just 3 lines. I decided > to use SendMessageTimeout() in case the taskbar doesn't respond: > > use Win32::GUI qw(WM_COMMAND); > > my $taskbar = Win32::GUI::FindWindow("Shell_TrayWnd", ""); > > Win32::GUI::SendMessageTimeout($taskbar, WM_COMMAND, 424, 0, 0, 1000); > > By the way, I found a list of message numbers in the 3rd post here (although > I'm still not sure where these message numbers are actually defined): > > http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/eb0b17d6-66de-4ce6-bb3a-0c174a17991e They are not officially defined, and you'll get no guarantee that they remain the same between different releases of the windows OS. The 'official' way to do this is to call the SHAppBarMessage() function: http://msdn.microsoft.com/en-us/library/bb762108.aspx using it to send the ABM_SETSTATE message: http://msdn.microsoft.com/en-us/library/bb787961(VS.85).aspx (If you just want to toggle the auto-hide bit (leaving the always-on-top state unchanged), then you need to call the function with the ABM_GETSTATE message type first, and then flit the auto-hide bit). Something like this: #!perl -w use strict; use warnings; # Toggle auto-hide state of windows taskbar use Win32::API qw(); # Import the ShAppBarMessage() API call Win32::API->Import("shell32","SHAppBarMessage","LP","L") or die $^E; # Constants that we will use sub ABM_SETSTATE() {0x0000000A} # Set State message sub ABM_GETSTATE() {0x00000004} # Get State message sub ABS_AUTOHIDE() {0x00000001} # Auto-hide flag my $state = get_taskbar_state(); $state ^= ABS_AUTOHIDE; # toggle state bit set_taskbar_state($state); exit(0); sub get_taskbar_state { return SHAppBarMessage(ABM_GETSTATE, pack("LLIIiiiiL", 32, 0, 0, 0, 0, 0, 0, 0, 0 )); } sub set_taskbar_state { my $state = shift; SHAppBarMessage(ABM_SETSTATE, pack("LLIIiiiiL", 36, 0, 0, 0, 0, 0, 0, 0, $state )); return; } __END__ Regards, Rob. |
From: Robert M. <ro...@th...> - 2008-12-08 11:21:50
|
Ignore me. I mis-read the question, which was about the 'lock the taskbar' functionality, not about auto-hiding the taskbar. I have no better approach than that already found by Rob for this. I still maintain that the WM_COMMAND values for this will not be guaranteed between OS releases (but you might get lucky). Rob. 2008/12/8 Robert May <ro...@th...>: > 2008/12/8 Perl Rob <pe...@co...>: >> It turns out that editing the registry is not necessary. I simply had to >> send the WM_COMMAND message (which means a command was selected from a menu) >> and a specific message number (which, for locking/unlocking the taskbar, >> happens to be 424). Here's the code in its entirety—just 3 lines. I decided >> to use SendMessageTimeout() in case the taskbar doesn't respond: >> >> use Win32::GUI qw(WM_COMMAND); >> >> my $taskbar = Win32::GUI::FindWindow("Shell_TrayWnd", ""); >> >> Win32::GUI::SendMessageTimeout($taskbar, WM_COMMAND, 424, 0, 0, 1000); >> >> By the way, I found a list of message numbers in the 3rd post here (although >> I'm still not sure where these message numbers are actually defined): >> >> http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/eb0b17d6-66de-4ce6-bb3a-0c174a17991e > > They are not officially defined, and you'll get no guarantee that they > remain the same between different releases of the windows OS. > > The 'official' way to do this is to call the SHAppBarMessage() function: > http://msdn.microsoft.com/en-us/library/bb762108.aspx > > using it to send the ABM_SETSTATE message: > http://msdn.microsoft.com/en-us/library/bb787961(VS.85).aspx > > (If you just want to toggle the auto-hide bit (leaving the > always-on-top state unchanged), then you need to call the function > with the ABM_GETSTATE message type first, and then flit the auto-hide > bit). > > Something like this: > > #!perl -w > use strict; > use warnings; > > # Toggle auto-hide state of windows taskbar > > use Win32::API qw(); > > # Import the ShAppBarMessage() API call > Win32::API->Import("shell32","SHAppBarMessage","LP","L") or die $^E; > > # Constants that we will use > sub ABM_SETSTATE() {0x0000000A} # Set State message > sub ABM_GETSTATE() {0x00000004} # Get State message > sub ABS_AUTOHIDE() {0x00000001} # Auto-hide flag > > > my $state = get_taskbar_state(); > $state ^= ABS_AUTOHIDE; # toggle state bit > set_taskbar_state($state); > exit(0); > > sub get_taskbar_state { > return SHAppBarMessage(ABM_GETSTATE, > pack("LLIIiiiiL", 32, 0, 0, 0, 0, 0, 0, 0, 0 )); > } > > sub set_taskbar_state { > my $state = shift; > SHAppBarMessage(ABM_SETSTATE, > pack("LLIIiiiiL", 36, 0, 0, 0, 0, 0, 0, 0, $state )); > return; > } > __END__ > > Regards, > Rob. > |