It is currently Thu Jun 07, 2018 6:48 pm

All times are UTC - 8 hours [ DST ]




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Wed Aug 03, 2016 7:35 am 
Offline

Joined: Wed Aug 03, 2016 7:27 am
Posts: 5
As mentionned in this article, it is possible to make the taskbar's background fully transparent with Classic Shell.

However, I feel that installing Classic Shell for this only feature overkill.

I'd like to know how Classic Shell does this, so I can write a tiny program dedicated to do that (and maybe add some features, such as having the taskbar transparent only when you're on the desktop)

I tried searching in the old source code, but the feature wasn't introduced yet.

If possible, I'd also appreciated having code snippets.


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 03, 2016 7:45 am 
Offline
Site Admin
User avatar

Joined: Wed Jan 02, 2013 11:38 pm
Posts: 5331
On Windows 10 this is done by using the undocumented function SetWindowCompositionAttribute. You can control the glass color and opacity of any window.
On older versions it is achieved by replacing the painting of the taskbar window with custom code.


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 03, 2016 8:15 am 
Offline

Joined: Wed Aug 03, 2016 7:27 am
Posts: 5
Thanks! Will check that out.


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 03, 2016 11:35 am 
Offline

Joined: Wed Aug 03, 2016 7:27 am
Posts: 5
Ivo wrote:
On Windows 10 this is done by using the undocumented function SetWindowCompositionAttribute. You can control the glass color and opacity of any window.



As soon as the Windows 10 start menu is opened, the effect reverts back to normal. Do you know the way to prevent that?


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 03, 2016 1:47 pm 
Offline
Site Admin
User avatar

Joined: Wed Jan 02, 2013 11:38 pm
Posts: 5331
When Classic Shell does it, or when you do it?


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 03, 2016 5:10 pm 
Offline

Joined: Wed Aug 03, 2016 7:27 am
Posts: 5
Ivo wrote:
When Classic Shell does it, or when you do it?



When I do it.



For reference, here's my (quickly written) code:

Code:
using System;
using System.Runtime.InteropServices;

public class TransparentTaskbar {
static class Interop {
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll")]
internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);

[StructLayout(LayoutKind.Sequential)]
internal struct WindowCompositionAttributeData {
public WindowCompositionAttribute Attribute;
public IntPtr Data;
public int SizeOfData;
}

[StructLayout(LayoutKind.Sequential)]
internal struct AccentPolicy {
public AccentState AccentState;
public AccentFlags AccentFlags;
public uint GradientColor;
public int AnimationId;
}

[Flags]
internal enum AccentFlags {
// ...
DrawLeftBorder = 0x20,
DrawTopBorder = 0x40,
DrawRightBorder = 0x80,
DrawBottomBorder = 0x100,
DrawAllBorders = (DrawLeftBorder | DrawTopBorder | DrawRightBorder | DrawBottomBorder)
// ...
}

internal enum WindowCompositionAttribute {
// ...
WCA_ACCENT_POLICY = 19
// ...
}

internal enum AccentState {
ACCENT_DISABLED = 0,
ACCENT_ENABLE_GRADIENT = 1,
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
ACCENT_ENABLE_BLURBEHIND = 3,
ACCENT_INVALID_STATE = 4
}
}

public static void Main(string[] CommandLine) {
var accent = new Interop.AccentPolicy();
accent.AccentState = Interop.AccentState.ACCENT_ENABLE_BLURBEHIND;

var accentPtr = Marshal.AllocHGlobal(Marshal.SizeOf(accent));
Marshal.StructureToPtr(accent, accentPtr, false);

var data = new Interop.WindowCompositionAttributeData();
data.Attribute = Interop.WindowCompositionAttribute.WCA_ACCENT_POLICY;
data.SizeOfData = Marshal.SizeOf(accent);
data.Data = accentPtr;

Interop.SetWindowCompositionAttribute(Interop.FindWindow("Shell_TrayWnd", null), ref data);
}
}


Top
 Profile  
Reply with quote  
PostPosted: Thu Aug 04, 2016 7:00 am 
Offline
Site Admin
User avatar

Joined: Wed Jan 02, 2013 11:38 pm
Posts: 5331
I am doing this when the taskbar gets WM_PAINT message. And in few other cases to prevent flickering.


Top
 Profile  
Reply with quote  
PostPosted: Wed Sep 07, 2016 5:37 pm 
Offline

Joined: Wed Aug 03, 2016 7:27 am
Posts: 5
I found an even better way!

Code:
#include <windows.h>
#include "stdafx.h"

TCHAR szClassName[] = TEXT("Blur");

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch (msg)
   {
   case WM_NCHITTEST:
      wParam = DefWindowProc(hWnd, msg, wParam, lParam);
      if (wParam == HTCLIENT)
         return HTCAPTION;
      else
         return wParam;
   case WM_DESTROY:
      PostQuitMessage(0);
      break;
   default:
      return DefWindowProc(hWnd, msg, wParam, lParam);
   }
   return 0;
}

void SetWindowBlur(HWND hWnd)
{
   const HINSTANCE hModule = LoadLibrary(TEXT("user32.dll"));
   if (hModule)
   {
      struct ACCENTPOLICY
      {
         int nAccentState;
         int nFlags;
         int nColor;
         int nAnimationId;
      };
      struct WINCOMPATTRDATA
      {
         int nAttribute;
         PVOID pData;
         ULONG ulDataSize;
      };
      typedef BOOL(WINAPI*pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*);
      const pSetWindowCompositionAttribute SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hModule, "SetWindowCompositionAttribute");
      if (SetWindowCompositionAttribute)
      {
         ACCENTPOLICY policy = { 3, 0, 0, 0 };
         WINCOMPATTRDATA data = { 19, &policy, sizeof(ACCENTPOLICY) };
         SetWindowCompositionAttribute(hWnd, &data);
      }
      FreeLibrary(hModule);
   }
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR pCmdLine, int nCmdShow)
{
   MSG msg;
   WNDCLASS wndclass = {
      0,
      WndProc,
      0,
      0,
      hInstance,
      0,
      LoadCursor(0, IDC_ARROW),
      (HBRUSH)GetStockObject(BLACK_BRUSH),
      0,
      szClassName
   };
   RegisterClass(&wndclass);
   RECT taskpos;
   HWND taskbar = FindWindow(L"Shell_TrayWnd", NULL);
   GetWindowRect(taskbar, &taskpos);
   HWND hWnd = CreateWindowEx(
      WS_EX_TOOLWINDOW | WS_EX_TOPMOST ,
      szClassName,
      TEXT("Blur"),
      WS_POPUP,
      taskpos.left,
      taskpos.top,
      taskpos.right - taskpos.left,
      taskpos.bottom - taskpos.top,
      0,
      0,
      hInstance,
      0
   );
   SetParent(taskbar, hWnd);
   SetWindowBlur(hWnd);
   ShowWindow(hWnd, SW_SHOW);
   // i wanna add some darkening effect later on, draw a half-transparent black rectangle on the whole window
   while (GetMessage(&msg, 0, 0, 0))
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }
   return msg.wParam;
}


Just create a window with the same size and position as the taskbar and then set the taskbar as the child of this window. This gives you total control over the taskbar's background (you can draw anything in the window, and it will be the taskbar's background.)

Sorry if the code is a bit messy, that's a prototype.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC - 8 hours [ DST ]


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group, Almsamim WYSIWYG Classic Shell © 2010-2016, Ivo Beltchev.
All right reserved.