How to prevent an app from being pinned in Windows

2019-03-20 18:37发布

I am trying to prevent the user from pinning my .NET app to the taskbar. I've found some code on the Old New Thing that does just that. However, it is in C++.

#include <shellapi.h>
#include <propsys.h>
#include <propkey.h>

HRESULT MarkWindowAsUnpinnable(HWND hwnd)
{
 IPropertyStore *pps;
 HRESULT hr = SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(&pps));
 if (SUCCEEDED(hr)) {
  PROPVARIANT var;
  var.vt = VT_BOOL;
  var.boolVal = VARIANT_TRUE;
  hr = pps->SetValue(PKEY_AppUserModel_PreventPinning, var);
  pps->Release();
 }
 return hr;
}


BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
 MarkWindowAsUnpinnable(hwnd);
 return TRUE;
}

I am having very little luck converting it to c#. Can someone help?

3条回答
Deceive 欺骗
2楼-- · 2019-03-20 18:59

In the question, the Old New Thing post also talks about how you can set some registry settings on per application basis that will so prevent the pinning an application to the taskbar.

All you have to do is add the value of "NoStartPage" to a key for your application under the Root\Applications. The value can be blank and of any type, if Windows just sees it is there it will not show the ability to pin the app, when the user right clicks on it in the taskbar.

Here is the documentation from Microsoft on this feature: Use Registry to prevent pinning of an application

The one caveat to this is that in Windows 7, due to UAC, you have to run as administrator to update the registry. I did this via the app.manifest.

The code to find the right and update the correct registry keys is below (hopefully it is not too verbose):

public static void Main(string[] args)
    {
        // Get Root
        var root = Registry.ClassesRoot;

        // Get the Applications key
        var applicationsSubKey = root.OpenSubKey("Applications", true);

        if (applicationsSubKey != null)
        {
            bool updateNoStartPageKey = false;

            // Check to see if your application already has a key created in the Applications key
            var appNameSubKey = applicationsSubKey.OpenSubKey("MyAppName.exe", true);

            if (appNameSubKey != null)
            {
                // Check to see if the NoStartPage value has already been created
                if (!appNameSubKey.GetValueNames().Contains("NoStartPage"))
                {
                    updateNoStartPageKey = true;
                }
            }
            else
            {
                // create key for your application in the Applications key under Root
                appNameSubKey = applicationsSubKey.CreateSubKey("MyAppName.exe", RegistryKeyPermissionCheck.Default);

                if (appNameSubKey != null)
                {
                    updateNoStartPageKey = true;
                }
            }

            if (updateNoStartPageKey)
            {
                // Create/update the value for NoStartPage so Windows will prevent the app from being pinned.
                appNameSubKey.SetValue("NoStartPage", string.Empty, RegistryValueKind.String);                    
            }
        }
    }
查看更多
神经病院院长
3楼-- · 2019-03-20 19:07

You can download the Windows API Code Pack which has the necessary p/invoke calls you need to translate the code in your post to C#.

Either use the library in whole or find the specific calls and definitions you require (search it for SHGetPropertyStoreForWindow and then its other dependencies).

查看更多
SAY GOODBYE
4楼-- · 2019-03-20 19:16

Using the WindowsAPICodePack (via NuGet) you need code resembling:

// Ensure the handle is available
new WindowInteropHelper(window).EnsureHandle();

// Prevent the window from being pinned to the task bars
var preventPinningProperty = new PropertyKey(
        new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 9);
WindowProperties.SetWindowProperty(window, preventPinningProperty, "1");
查看更多
登录 后发表回答