Skip to content

Commit 6fec1bb

Browse files
committed
Initial commit
1 parent 301338c commit 6fec1bb

10 files changed

Lines changed: 314 additions & 0 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
################################################################################
44

55
/TaskbarHook/bin/Debug
6+
/TaskbarHook/obj
7+
/.vs/TaskbarHook/v15/Server/sqlite3

.vs/TaskbarHook/v15/.suo

27.5 KB
Binary file not shown.

TaskbarHook.sln

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.28010.2016
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TaskbarHook", "TaskbarHook\TaskbarHook.csproj", "{854641A8-D4F1-4230-9C1A-03F881DD3FF7}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{854641A8-D4F1-4230-9C1A-03F881DD3FF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{854641A8-D4F1-4230-9C1A-03F881DD3FF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{854641A8-D4F1-4230-9C1A-03F881DD3FF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{854641A8-D4F1-4230-9C1A-03F881DD3FF7}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {3C2751D8-0EEF-4EA8-88FB-C98F423AB579}
24+
EndGlobalSection
25+
EndGlobal
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// Allgemeine Informationen über eine Assembly werden über die folgenden
6+
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
7+
// die einer Assembly zugeordnet sind.
8+
[assembly: AssemblyTitle("TaskbarHook")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("TaskbarHook")]
13+
[assembly: AssemblyCopyright("Copyright © 2018")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
18+
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
19+
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
20+
[assembly: ComVisible(false)]
21+
22+
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
23+
[assembly: Guid("854641a8-d4f1-4230-9c1a-03f881dd3ff7")]
24+
25+
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
26+
//
27+
// Hauptversion
28+
// Nebenversion
29+
// Buildnummer
30+
// Revision
31+
//
32+
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
33+
// indem Sie "*" wie unten gezeigt eingeben:
34+
// [assembly: AssemblyVersion("1.0.*")]
35+
[assembly: AssemblyVersion("1.0.0.0")]
36+
[assembly: AssemblyFileVersion("1.0.0.0")]

TaskbarHook/Rectangle.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.Runtime.InteropServices;
2+
3+
namespace TaskbarHook
4+
{
5+
[StructLayout(LayoutKind.Sequential)]
6+
public struct Rectangle
7+
{
8+
public int Left; // x position of upper-left corner
9+
public int Top; // y position of upper-left corner
10+
public int Right; // x position of lower-right corner
11+
public int Bottom; // y position of lower-right corner
12+
}
13+
}

TaskbarHook/TaskBarFactory.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
3+
namespace TaskbarHook
4+
{
5+
public static class TaskBarFactory
6+
{
7+
private const string SHELLTRAY = "Shell_traywnd";
8+
private const string REBAR = "ReBarWindow32";
9+
10+
public static IntPtr ShellTrayHandle => User32.GetWindow(SHELLTRAY);
11+
12+
public static IntPtr ReBarWindowHandle => User32.GetWindow(ShellTrayHandle, REBAR);
13+
14+
public static IntPtr TaskBarHandle => User32.GetFirstWindowChild(User32.GetFirstWindowChild(ReBarWindowHandle));
15+
16+
/// <summary>
17+
/// Tries to get the taskbar of the running windows system.
18+
/// (MSTaskListWClass)
19+
/// </summary>
20+
/// <returns>A Taskbar representing object for manipulation.</returns>
21+
/// <exception cref="PlatformNotSupportedException">No TaskBar could be obtained.</exception>
22+
public static Taskbar GetTaskbar()
23+
{
24+
IntPtr taskbarHandle = TaskBarHandle;
25+
26+
if (taskbarHandle == IntPtr.Zero)
27+
throw new PlatformNotSupportedException($"The TaskBar cound't be obtained.");
28+
29+
return new Taskbar(taskbarHandle);
30+
}
31+
}
32+
}

TaskbarHook/Taskbar.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Threading.Tasks;
4+
5+
namespace TaskbarHook
6+
{
7+
public class Taskbar
8+
{
9+
public Taskbar(IntPtr handle)
10+
{
11+
Handle = handle;
12+
13+
Initialize();
14+
}
15+
16+
private void Initialize()
17+
{
18+
Rectangle = User32.GetWindowRectangle(Handle);
19+
}
20+
21+
public IntPtr Handle { get; private set; }
22+
23+
public Rectangle Rectangle { get; private set; }
24+
25+
public async Task<TaskbarElement> AddToTaskbar() => await AddToTaskbar(Process.GetCurrentProcess());
26+
27+
public async Task<TaskbarElement> AddToTaskbar(Process process)
28+
{
29+
while (process.MainWindowHandle == IntPtr.Zero)
30+
await Task.Delay(6); //ToDo: Add timeout
31+
32+
TaskbarElement taskbarElement = new TaskbarElement(process.MainWindowHandle);
33+
taskbarElement.SetParent(Handle);
34+
35+
return taskbarElement;
36+
}
37+
}
38+
}

TaskbarHook/TaskbarElement.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
3+
namespace TaskbarHook
4+
{
5+
public class TaskbarElement
6+
{
7+
public TaskbarElement(IntPtr handle)
8+
{
9+
Handle = handle;
10+
}
11+
12+
public IntPtr Handle { get; private set; }
13+
14+
public IntPtr Parent { get; private set; } = IntPtr.Zero;
15+
16+
public IntPtr OriginalParent { get; private set; } = IntPtr.Zero;
17+
18+
public bool CanResetParent => OriginalParent != IntPtr.Zero;
19+
20+
public bool Show() => User32.ShowWindow(Handle);
21+
22+
public bool Hide() => User32.HideWindow(Handle);
23+
24+
/// <summary>
25+
/// Sets the position of the process.
26+
/// (0, 0) indicates the top left corner of the taskbar.
27+
/// </summary>
28+
/// <param name="x">The X coordinate, relative to its parent.</param>
29+
/// <param name="y">The y coordinate, relative to its parent.</param>
30+
/// <param name="width">The width of the process.</param>
31+
/// <param name="height">The height of the process.</param>
32+
/// <returns><c>true</c> if the position adjustment was successfull, <c>false</c> otherwise.</returns>
33+
public bool SetPosition(int x, int y) => User32.SetWindowPosition(Handle, x, y);
34+
35+
internal bool SetParent(IntPtr handle)
36+
{
37+
Parent = handle;
38+
OriginalParent = User32.SetWindowParent(handle, Handle);
39+
return OriginalParent != IntPtr.Zero;
40+
}
41+
42+
public bool ResetParent()
43+
{
44+
if (!CanResetParent)
45+
throw new ApplicationException($"Could not reset the parent. No parent known!");
46+
47+
var parentBackup = OriginalParent;
48+
var returnValue = SetParent(OriginalParent);
49+
OriginalParent = parentBackup;
50+
return returnValue;
51+
}
52+
}
53+
}

TaskbarHook/TaskbarHook.csproj

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{854641A8-D4F1-4230-9C1A-03F881DD3FF7}</ProjectGuid>
8+
<OutputType>Library</OutputType>
9+
<AppDesignerFolder>Properties</AppDesignerFolder>
10+
<RootNamespace>TaskbarHook</RootNamespace>
11+
<AssemblyName>TaskbarHook</AssemblyName>
12+
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
13+
<FileAlignment>512</FileAlignment>
14+
<Deterministic>true</Deterministic>
15+
</PropertyGroup>
16+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
17+
<DebugSymbols>true</DebugSymbols>
18+
<DebugType>full</DebugType>
19+
<Optimize>false</Optimize>
20+
<OutputPath>bin\Debug\</OutputPath>
21+
<DefineConstants>DEBUG;TRACE</DefineConstants>
22+
<ErrorReport>prompt</ErrorReport>
23+
<WarningLevel>4</WarningLevel>
24+
</PropertyGroup>
25+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26+
<DebugType>pdbonly</DebugType>
27+
<Optimize>true</Optimize>
28+
<OutputPath>bin\Release\</OutputPath>
29+
<DefineConstants>TRACE</DefineConstants>
30+
<ErrorReport>prompt</ErrorReport>
31+
<WarningLevel>4</WarningLevel>
32+
</PropertyGroup>
33+
<ItemGroup>
34+
<Reference Include="System" />
35+
<Reference Include="System.Core" />
36+
<Reference Include="System.Xml.Linq" />
37+
<Reference Include="System.Data.DataSetExtensions" />
38+
<Reference Include="Microsoft.CSharp" />
39+
<Reference Include="System.Data" />
40+
<Reference Include="System.Net.Http" />
41+
<Reference Include="System.Xml" />
42+
<Reference Include="UIAutomationClient" />
43+
<Reference Include="WindowsBase" />
44+
</ItemGroup>
45+
<ItemGroup>
46+
<Compile Include="TaskbarElement.cs" />
47+
<Compile Include="TaskBarFactory.cs" />
48+
<Compile Include="Properties\AssemblyInfo.cs" />
49+
<Compile Include="Rectangle.cs" />
50+
<Compile Include="Taskbar.cs" />
51+
<Compile Include="User32.cs" />
52+
</ItemGroup>
53+
<ItemGroup>
54+
<PackageReference Include="TestStack.White">
55+
<Version>0.13.3</Version>
56+
</PackageReference>
57+
</ItemGroup>
58+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
59+
</Project>

TaskbarHook/User32.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace TaskbarHook
5+
{
6+
internal static class User32
7+
{
8+
#region DLLImports
9+
[DllImport("user32.dll", SetLastError = true)]
10+
private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
11+
12+
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
13+
private static extern IntPtr GetParent(IntPtr hWnd);
14+
15+
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
16+
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
17+
18+
[DllImport("user32.dll", SetLastError = true)]
19+
private static extern bool GetWindowRect(IntPtr hwnd, out Rectangle lpRect);
20+
21+
[DllImport("user32.dll", SetLastError = true)]
22+
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
23+
24+
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
25+
private static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, int wFlags);
26+
27+
[DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
28+
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
29+
#endregion
30+
31+
internal static bool SetWindowPosition(IntPtr handle, int x, int y) => SetWindowPos(handle, 0, x, y, 0, 0, 0x0001) != IntPtr.Zero;
32+
33+
internal static IntPtr SetWindowParent(IntPtr parent, IntPtr child) => SetParent(child, parent);
34+
35+
internal static bool HideWindow(IntPtr handle) => SetVisibilityState(handle, 0);
36+
37+
internal static bool ShowWindow(IntPtr handle) => SetVisibilityState(handle, 5);
38+
39+
internal static bool SetVisibilityState(IntPtr handle, int state) => ShowWindow(handle, state);
40+
41+
internal static IntPtr GetWindowParent(IntPtr handle) => GetParent(handle);
42+
43+
internal static IntPtr GetWindow(string className) => GetWindow(IntPtr.Zero, className);
44+
45+
internal static IntPtr GetWindow(IntPtr parentHandle, string className) => FindWindowEx(parentHandle, IntPtr.Zero, className, string.Empty);
46+
47+
internal static IntPtr GetFirstWindowChild(IntPtr parentHandle) => GetWindow(parentHandle, 5);
48+
49+
internal static Rectangle GetWindowRectangle(IntPtr handle)
50+
{
51+
Rectangle rectangle = new Rectangle();
52+
GetWindowRect(handle, out rectangle);
53+
return rectangle;
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)