I am using PackageManager class to list the installed metro style applications in the system.
PackageId.Name does not return the actual name of the package, Neither is Package.DisplayName. Package.DisplayName returns empty string. It does return display name only for Package.Current.
When I tried to use AppxManifest.xml, I could not get the display name from
Package->Properties->Displayname too.
<Properties>
<DisplayName>ms-resource:///Resources/AppStoreName</DisplayName>
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
<Logo>Assets\WindowsIcons\StoreLogo.png</Logo>
</Properties>
Where can I get the exact display name of metro style applications ?
If you already have a reference to a Package instance, you can get the Display Name using an interop method and the registry. Here's a complete example:
using Microsoft.Win32;
using System;
using System.Runtime.InteropServices;
using System.Text;
using Windows.ApplicationModel;
public class PackageUtil
{
[DllImport("shlwapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode,
ExactSpelling = true, SetLastError = false, ThrowOnUnmappableChar = true)]
private static extern int SHLoadIndirectString(string pszSource,
StringBuilder pszOutBuf, int cchOutBuf, IntPtr ppvReserved);
private static string GetPackageDisplayName(Package package)
{
using (var key = Registry.ClassesRoot.OpenSubKey(
#"Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel" +
$#"\Repository\Packages\{package.Id.FullName}\App\Capabilities"))
{
var sb = new StringBuilder(256);
Shlwapi.SHLoadIndirectString((string)key.GetValue("ApplicationName"),
sb, sb.Capacity, IntPtr.Zero);
return sb.ToString();
}
}
}
Related
I want to open a registry key that is a symbolic link.
According to Microsoft I need to use REG_OPTION_OPEN_LINK to open it.
I searched for an option to add it to the OpenSubKey function but I didn't find an option. There are only fiver overload functions but none of them allow to add an optional parameter:
Microsoft.Win32.Registry.CurrentUser.OpenSubKey(string name)
Microsoft.Win32.Registry.CurrentUser.OpenSubKey(string name, bool writable)
Microsoft.Win32.Registry.CurrentUser.OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck)
Microsoft.Win32.Registry.CurrentUser.OpenSubKey(string name, RegistryRights rights)
Microsoft.Win32.Registry.CurrentUser.OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)
The only way I can think of is to use p\invoke but maybe I am missing it and there is an option in C# classes.
You can't do this with the normal RegistryKey functions. Having checked in the source code, it seems that the ulOptions parameter is always passed as 0.
The only way is to call RegOpenKeyEx yourself, and pass the resulting SafeRegistryHandle to RegistryKey.FromHandle
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.ComponentModel;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
static extern int RegOpenKeyExW(SafeRegistryHandle hKey, String lpSubKey,
int ulOptions, int samDesired, out SafeRegistryHandle hkResult);
public static RegistryKey OpenSubKeySymLink(this RegistryKey key, string name, RegistryRights rights = RegistryRights.ReadKey, RegistryView view = 0)
{
const int REG_OPTION_OPEN_LINK = 0x0008;
var error = RegOpenKeyExW(key.Handle, name, REG_OPTION_OPEN_LINK, ((int)rights) | ((int)view), out var subKey);
if (error != 0)
{
subKey.Dispose();
throw new Win32Exception(error);
}
return RegistryKey.FromHandle(subKey); // RegistryKey will dispose subKey
}
It is an extension function, so you can call it on either an existing sub-key, or on one of the main keys, such as Registry.CurrentUser. Don't forget to put a using on the returned RegistryKey:
using (var key = Registry.CurrentUser.OpenSubKeySymLink(#"SOFTWARE\Microsoft\myKey", RegistryRights.ReadKey))
{
// do stuff with key
}
I have the following C# code to extract an icon with a specific index from a specific DLL:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
public class ExtractIcon
{
public static Icon Extract(string file, int number, bool largeIcon)
{
IntPtr large;
IntPtr small;
ExtractIconEx(file, number, out large, out small, 1);
try
{
return Icon.FromHandle(largeIcon ? large : small);
}
catch
{
return null;
}
}
[DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);
}
This works fine. Sort of. Because it doesn't handle transparency.
Take a look:
How can I fix this?
EDIT
Credits to #rbmm
The problem was not the code above but rather the code I was using to convert from Icon to Bitmap. I was using Bitmap.FromHIcon, which apparently discards the transparency. I now use a custom method to convert between these two and it works flawlessly.
I wanna detect every keyboard layout change with C#. It doesn't matter whether it is switched by win + space or alt + shift or with mouse...
I wrote a code that works considerably well (see below) for desktop apps. But it doesn't work for UWP apps. If I switch layout while within the UWP app, it is not detected, if I switch to desktop app the change is detected right away... How can I do it to detect any change in the layout? Is there any other way how to find out what layout is active at any given moment no matter what window is active?
My code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Globalization;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string lastLang = "";
while (true)
{
string langSuffix = GetKeyboardLayoutIdAtTime();
if (!langSuffix.Equals(lastLang))
{
// do something
Console.WriteLine(getCurrentTimeStamp() + ": Changing '" + lastLang + "' to '" + langSuffix + "'.");
lastLang = langSuffix;
}
System.Threading.Thread.Sleep(1000);
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern int GetWindowThreadProcessId(IntPtr handleWindow, out int lpdwProcessID);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetKeyboardLayout(int WindowsThreadProcessID);
public static string GetKeyboardLayoutIdAtTime()
{
IntPtr hWnd = GetForegroundWindow();
int lpdwProcessId;
InputLanguageCollection installedInputLanguages = InputLanguage.InstalledInputLanguages;
CultureInfo currentInputLanguage = null;
int WinThreadProcId = GetWindowThreadProcessId(hWnd, out lpdwProcessId);
IntPtr KeybLayout = GetKeyboardLayout(WinThreadProcId);
// this remain unchanged when I switch layouts in UWP
Console.WriteLine("KL IntPtr: " + KeybLayout);
for (int i = 0; i < installedInputLanguages.Count; i++)
{
if (KeybLayout == installedInputLanguages[i].Handle) currentInputLanguage = installedInputLanguages[i].Culture;
}
if(currentInputLanguage == null)
{
Console.WriteLine(getCurrentTimeStamp() + "current input language is null...");
}
return currentInputLanguage.TwoLetterISOLanguageName;
}
private static string getCurrentTimeStamp()
{
return DateTime.Now.ToString("yyyyMMddHHmmssffff");
}
}
}
In Desktop, we use the Input Method Manager to communicate with an input method editor (IME), which runs as a service. In UWP, we should be able to use the Text Services Framework. There is a document about Alternatives to Windows APIs in Universal Windows Platform (UWP) apps.
So we should be able to use the Windows.UI.Text.Core namespace, it provides types for accessing the Windows core text APIs and the text input server. Windows core text is a client-server system that centralizes the processing of keyboard input into a single server.
We can find the InputLanguageChanged event in the CoreTextServicesManager class. It occurs when the current input language has changed. When we switched the input method by win + space or alt + shift or with mouse, the InputLanguageChanged will be fired.
For example:
public MainPage()
{
this.InitializeComponent();
CoreTextServicesManager textServiceManager = CoreTextServicesManager.GetForCurrentView();
textServiceManager.InputLanguageChanged += TextServiceManager_InputLanguageChanged;
}
private void TextServiceManager_InputLanguageChanged(CoreTextServicesManager sender, object args)
{
Debug.WriteLine("Keyboard layout is changed!");
}
I am scrapping content from another Windows application.
The application has a Listbox and two TRichEdit controls (and other controls without interest).
When using SendKeys.SendWait("{DOWN}") to the Listbox, the content in the two TRichEdit boxes changes. Thats where I want to scrap the content. That works.
RichEdit1 : No problem - I get the content using SendMessageW()
RichEdit2: Big problem. It changes Windows Handle each time I use SendKeys.SendWait on the LIstBox, so I can't access it.
The solution is to find the new Windows Handle for RichEdit2. I think that I can get a list of Handles for RichEdit control and select the one with Handle different from RichEdit1.
Question:
How can I get a list of Handles of a specific class (RichEdit) from a different windows forms application?
Or
Does anyone has a better solution?
A code snippet in C# will be appreciated.
Thanks in advance.
For the question on how to get the RichEdit window handles:
You can PInvoke FindWindowEx setting the child window parameter to NULL to check all child windows and the class name set to the class names of RichEdit control from here:
v1.0 = RICHEDIT
v2.0 & v3.0 = RichEdit20A or RichEdit20W
v4.1 = RICHEDIT50W
v5.0 = RichEdit50W
v6.0 = RichEdit60W
Still, MSDN states that:
The function searches among windows that are child windows of the desktop.
So basically you get a search depth of one. If your controls are nested deeper, then you may need to combine this with EnumChildWindows to perfrom a full depth search.
EDIT
This is a snippet on how to enumerate the windows and find matching windows for a given class using the described method, hope you can fine tune it.
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace UIAutomation
{
class Program
{
public delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
public static bool EnumChildWindowsCallback(IntPtr hWnd, IntPtr lParam)
{
StringBuilder className = new StringBuilder(256);
GetClassName(hWnd, className, className.Capacity);
var windowInformation = new WindowInformation(hWnd, lParam, className.ToString());
_windowLookupMap[hWnd] = windowInformation;
if (lParam != IntPtr.Zero)
{
_windowLookupMap[lParam]._children.Add(windowInformation);
}
EnumChildWindows(hWnd, EnumChildWindowsCallback, hWnd);
return true;
}
class WindowInformation
{
public IntPtr _parent;
public IntPtr _hWnd;
public string _className;
public List<WindowInformation> _children = new List<WindowInformation>();
public WindowInformation(IntPtr hWnd, IntPtr parent, string className)
{
_hWnd = hWnd;
_parent = parent;
_className = className;
}
}
static Dictionary<IntPtr, WindowInformation> _windowLookupMap = new Dictionary<IntPtr, WindowInformation>();
static void FindWindowsByClass(string className, WindowInformation root, ref List<WindowInformation> matchingWindows)
{
if (root._className == className)
{
matchingWindows.Add(root);
}
foreach (var child in root._children)
{
FindWindowsByClass(className, child, ref matchingWindows);
}
}
static void Main(string[] args)
{
var processes = Process.GetProcessesByName("notepad");
StringBuilder className = new StringBuilder(256);
GetClassName(processes[0].MainWindowHandle, className, className.Capacity);
_windowLookupMap[processes[0].MainWindowHandle] = new WindowInformation(processes[0].MainWindowHandle, IntPtr.Zero, className.ToString());
EnumChildWindows(processes[0].MainWindowHandle, EnumChildWindowsCallback, processes[0].MainWindowHandle);
List<WindowInformation> matchingWindows = new List<WindowInformation>();
FindWindowsByClass("Edit", _windowLookupMap.Single(window => window.Value._parent == IntPtr.Zero).Value, ref matchingWindows);
Console.WriteLine("Found {0} matching window handles", matchingWindows.Count);
}
}
}
Thanks for the answer above. It's very detailed. I ended up using a more simple approach:
private IntPtr FindHandle()
{
while (true)
{
IntPtr handle = FindWindowEx(this.ApplicationHandle,IntPtr.Zero,"TRichEdit", null);
if (handle == null)
{
throw new Exception("No handle found");
}
if (handle != this.Handle_01)
{
return handle;
}
}
}
I have the following c sharp file compiled as an executable.
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
using System.Threading;
namespace Foreground {
class GetForegroundWindowTest {
[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
public static void Main(string[] args){
while (true){
IntPtr fg = GetForegroundWindow(); //use fg for some purpose
var bufferSize = 1000;
var sb = new StringBuilder(bufferSize);
GetWindowText(fg, sb, bufferSize);
using (StreamWriter sw = File.AppendText("C:\\Office Viewer\\OV_Log.txt"))
{
sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss,") + sb.ToString());
}
Thread.Sleep(5000);
}
}
}
}
When I run this executable on a local machine it yields both the date and the name of the current window.
when I run this executable from a remote machine using wmi it yields date and the name of the current window is blank, which I assume means that it returns null. Does anyone have a fix for this?
The program which runs the wmi executable is written in python, and is of the form:
import wmi
IP = '192.168.165.x'
USERNAME = 'username'
PASSWORD = 'password'
REMOTE_DIR = 'c:\ ... \'
remote_pc = wmi.WMI (IP, user = USERNAME, password = PASSWORD)
exe_remote_path = join (['\\\\', IP, '\\', REMOTE_DIR, filename)
remote_pc.Win32_Process.Create (CommandLine = exe_remote_path)
This may be the issue.....
For security reasons the Win32_Process.Create method cannot be used to start an interactive process remotely.
from msdn