Setting another Application to Be Always On Top

When creating an application, if we want our own application to be the topmost window, many UI APIs have a call or setting that we can alter to ensure that is how our window displays. For a client, we were asked to make a third-party application that always appeared on top of other windows. Contacting the application vendor, we found that there was no way to do this within the range of settings that we have access to. Nor was there likely to be a method available on our timelines. This isn’t a serious problem though; we can use some Win32 APIs to alter the window settings ourselves.

This is something that is only to be done as a last resort. Manipulating the internal settings of another application can come with risks. When doing something like this, it should be done with a significant amount of testing. To accomplish this task, we only need to get a handle of the window that we wish to affect and call SetWindowPos with the argument HWND_TOPMOST. That’s the easy part. The less obvious part is how does get their hands on the handle of another window. The FindWindows API can be used to get the handle of a Window based either on the window title or the window class name. For the Notepad application on Windows 10, the name of the window class is simply Notepad. We could also get access to a Notepad window if we use the text string that shows up in its title bar. For flexibility, put this functionality into an application or have it use FindWindow up to 2 times so that I can attempt to find the window by the class name or the title. The value to be used here is passed as a command line parameter. In C++, we end up with an application that has the following source code. The application calls these Windows API in a loop. This allows it to have an effect if the target application hasn’t presented a window or if the application closes and reopens.

// AlwaysOnTop.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <Windows.h>

void ShowInstructions()
{
    std::wcout << L"Usage:\rn"
        L"AlwaysOnTop.exe[window - name]\r\n"
        L"[window - name] should be either the\r\n"
        L"window or the name of the window class. " << std::endl;
}

int wmain(int argc, wchar_t** argv)
{
    HWND windowHandle = nullptr;
    std::wstring windowName ;
    if (argc < 2) {
        ShowInstructions();
        return -1;
    }

    windowName = std::wstring(argv[1]);

    while (true)
    {
        windowHandle = NULL;
        while (windowHandle == NULL)
        {
            windowHandle = FindWindow(windowName.c_str(), nullptr);
            if (windowHandle == nullptr)
            {
                windowHandle = FindWindow(nullptr, windowName.c_str());
            }
            if (windowHandle == nullptr)
            {
                Sleep(3500);
            }
        }
        std::wcout << "Window handle found for " <<windowName << " }. \r\nSetting to top most window";
        while (true) {

            SetWindowPos(windowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
            SetForegroundWindow(windowHandle);
            Sleep(7500);
        }
    }
}


I’ve found that native executables tend to set off alarms for a security application that we use. The security application isn’t as sensitive to .Net executables. I have the source code in .Net also. It calls the same Windows APIs in the same order.

using System.Runtime.InteropServices;

namespace AlwaysOnTop.Net
{
    internal class Program
    {
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);


        [DllImport("user32.dll")]
        static extern IntPtr SetFocus(IntPtr hWnd);

        [DllImport("User32.dll")]
        static extern int SetForegroundWindow(IntPtr hWnd);

        // Constants for nCmdShow
        const int SW_HIDE = 0;
        const int SW_SHOW = 5;
        const uint SWP_NOSIZE = 0x0001;
        const uint SWP_NOZORDER = 0x0004;
        const uint SWP_NOMOVE = 0x002;
        const int HWND_TOPMOST = -1;
        static readonly IntPtr HWND_TOP = IntPtr.Zero;



        static void ShowInstructions()
        {
            Console.WriteLine(
@"Usage:

AlwaysOnTop.Net.exe [window-name]

[window-name] should be either the 
window name or window class.
"
            );
        }

        static void Main(string[] args)
        {
            if(args.Length < 1)
            {
                ShowInstructions();
                return;
            }            
            string windowName = args[0];



            IntPtr windowHandle = IntPtr.Zero;

            while(true)
            {
                while (windowHandle == IntPtr.Zero)
                {
                    windowHandle = FindWindow(windowName, null);
                    if (windowHandle == IntPtr.Zero)
                    {
                        windowHandle = FindWindow(null, windowName);
                    }
                    if(windowHandle == null)
                    {
                        Thread.Sleep(3500);
                    }
                }
                Console.WriteLine($"Window handle found for {windowName}. \r\nSetting to top most window");
                while(true){

                    SetWindowPos(windowHandle,  HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
                    SetForegroundWindow(windowHandle);
                    Thread.Sleep(7500);
                }
            }
        }
    }
}

For applications where the class of the top-most window is not known, what do we do? I threw together one other application to get that information. With this other application, I would start the application whose information I want to acquire, then run my command line utility, saving the CSV text that it outputs. The name of the application is ListAllWindows.exe (descriptive!). The Win32 function EnumWindows enumerates all top-level windows and passes a handle to them to a callback function. In the callback, I save the window handle. With a window handle, I can call GetWindowClass() function to get the class name as a WCHAR array. This gets packaged as a std::wstring (those are safer).

// ListAllWindows.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <Windows.h>
#include <vector>
#include <algorithm>
#include <tlhelp32.h>
#include <psapi.h>
#include <iomanip>
#include <sstream>


struct HANDLECloser
{
    void operator()(HANDLE handle) const
    {
        if (handle != INVALID_HANDLE_VALUE && handle != 0)
        {
            CloseHandle(handle);
        }
    }
};


struct WindowInformation {
    HWND handle;
    std::wstring className;
    std::wstring processName;
};

std::vector<WindowInformation> windowList;

BOOL CALLBACK WindowFound(HWND hWnd, LPARAM lParam)
{
    windowList.push_back(WindowInformation{hWnd, L"",L""});
    return TRUE;
}

int wmain()
{    
    EnumWindows(WindowFound, 0);
    std::wcout << "Number of top level Windows found :" << windowList.size() << std::endl << std::endl;

    std::for_each(windowList.begin(), windowList.end(), [](WindowInformation& info) 
    {
            std::vector<WCHAR> buffer(1024);
            size_t stringLength;
            DWORD processID = 0;
            if (SUCCEEDED(stringLength=GetClassName(info.handle, buffer.data(), buffer.size())))
            {
                info.className = std::wstring(buffer.data(), stringLength);
            }

            DWORD threadID = GetWindowThreadProcessId(info.handle, &processID);
            if (threadID != 0)
            {
                auto processHandleTemp = OpenProcess(PROCESS_ALL_ACCESS, TRUE, processID);
                if (processHandleTemp != 0)
                {

                    auto processHandle = std::unique_ptr<void, HANDLECloser>(processHandleTemp);


                    std::vector<WCHAR> processName(1024);
                    auto processNameLength = GetModuleFileNameEx(processHandle.get(), NULL, processName.data(), processName.size());
                    info.processName = std::wstring(processName.data(), processNameLength);
                }
                else
                {
                    auto lastError = GetLastError();
                    std::wcerr << "Get Process failed " << lastError << std::endl;
                    info.processName = L"unknown";
                }                
            }
    });


    std::wcout <<  "Window Handle, Class Name, Process Executable" << std::endl;
    std::for_each(windowList.begin(), windowList.end(), [](WindowInformation& info)
        {
            std::wcout << info.handle << L", " << info.className << L", " << info.processName << std::endl;
        }
    );

    return 0;
}

Sample output from this program follows. I’ve not provided the full output since that would be more than 800 windows.

Number of top level Windows found :868
0000000000030072, .NET-BroadcastEventWindow.21af1a5.0, C:\Program Files\WindowsApps\Microsoft.YourPhone_1.25022.70.0_x64__8wekyb3d8bbwe\PhoneExperienceHost.exe
00000000000716DA, PersonalizationThemeChangeListener, C:\Windows\ImmersiveControlPanel\SystemSettings.exe
00000000008514E4, Windows.UI.Core.CoreWindow, C:\Windows\ImmersiveControlPanel\SystemSettings.exe
0000000000950E12, WorkerW, C:\Windows\ImmersiveControlPanel\SystemSettings.exe
00000000003E16C2, ApplicationFrameWindow, C:\Windows\System32\ApplicationFrameHost.exe
00000000001B1660, ComboLBox, C:\Windows\System32\mstsc.exe
000000000065157E, TscShellContainerClass, C:\Windows\System32\mstsc.exe
00000000006014C4, WorkerW, C:\Windows\explorer.exe
00000000001E0D7E, WindowsForms10.Window.20808.app.0.224edbf_r3_ad1, C:\Program Files\paint.net\paintdotnet.exe
0000000000190E8A, WindowsForms10.tooltips_class32.app.0.224edbf_r3_ad1, C:\Program Files\paint.net\paintdotnet.exe
00000000000D10A0, WindowsForms10.Window.0.app.0.224edbf_r3_ad1, C:\Program Files\paint.net\paintdotnet.exe
0000000000061732, WindowsForms10.Window.20808.app.0.224edbf_r3_ad1, C:\Program Files\paint.net\paintdotnet.exe
00000000000C1778, WindowsForms10.tooltips_class32.app.0.224edbf_r3_ad1, C:\Program Files\paint.net\paintdotnet.exe
000000000027125C, WindowsForms10.Window.20808.app.0.224edbf_r3_ad1, C:\Program Files\paint.net\paintdotnet.exe
00000000002516D2, WindowsForms10.tooltips_class32.app.0.224edbf_r3_ad1, C:\Program Files\paint.net\paintdotnet.exe

In the second column of this CSV, the names of the Window classes show along with the path to the executable that they belong to. Oftentimes, an application may have more than one top-level window. Figuring out which don’t to use comes down to experimentation. Be prepared to start the program several times.


Posts may contain products with affiliate links. When you make purchases using these links, we receive a small commission at no extra cost to you. Thank you for your support.

Mastodon: @j2inet@masto.ai
Instagram: @j2inet
Facebook: @j2inet
YouTube: @j2inet
Telegram: j2inet
Bluesky: @j2i.net

Building Clang on Window

While I’ve generally used Visual Studio for C/C++ projects, I’m introducing Clang to my C-related build chain. Clang is a front end for C languages (C, C++, Objective-C, OpenCL, CUDA). There is some other code that compiles with Clang. Building the compiler yourself also allows you to get access to the lates-and-greatest features. If you are only seeking the pre-built binaries, you can find them here. The Visual Studio installer also has support for installing a build of Clang that is older. Before trying to build Clang yourself, consider if one of these other options is right for you.

I like for setup processes to be easily repeatable and automated. For building Clang, I’ve made a batch file to perform most of the steps for me. For building this C/C++ compiler, I need to use a C/C++ compiler. I used Visual Studio 2022 Community Edition for this. I have successfully completed a set of scripts for building Clang and have made them available on Github. Instead of putting them in their own repository, I’ve made a single repository for such scripts. Since Github doesn’t appear to have a way to organize repositories in folders, I’m trying to minimize the number of new ones I make.

You can find the script at https://github.com/j2inet/DevSetup/tree/main/Clang

What does “C Front End” mean?

Understanding what this means is probably aided by knowing what LLVM is. LLVM (low-level virtual machine) originally referred to a set of technologies that targeted a language-independent machine specification. The project has grown beyond targeting a virtual machine specification. It provides tools that could help someone create a compiler for their own programming language or a compiler for some specific machine architecture. LLVM-based compilers are available for a wide range of programming languages. I’m installing Clang because some other code library that I wish to use compiles with Clang.

Customize the Installation Settings

Before running the script, some customizations should be considered. The script assumes you wish to build and install Clang on your C: drive. I’ve set a default installation path for c:\shares\clang. Variables for this and other settings are set in the script named ClangDefineEnvironmentVariables.cmd. I’ve also included the URLs to a version of CMake, Ninja, and Python. You may already have these tools installed and in your path. If you don’t want the script to attempt to install these tools, you can comment out the variables InstallCmake and InstallPython. If these are not defined, the script will skip its attempt to install them.

@ECHO OFF
setlocal Enabledelayedexpansion 
ECHO Defining environment variables
SET InstallPython=true
SET InstallCmake=false
SET InstallDrive=c:
SET InstallRoot=%InstallDrive%\shares\clang
SET TempFolder=%InstallRoot%\temp
SET MSBUILD_FULL_PATH=C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\amd64\MSBuild.exe
SET CMAKE_SOURCE_URL=https://github.com/Kitware/CMake/releases/download/v4.0.0-rc3/cmake-4.0.0-rc3-windows-x86_64.msi
SET CMAKE_FILE_NAME=cmake-4.0.0-rc3-windows-x86_64.msi
SET PYTHON_URL=https://www.python.org/ftp/python/3.13.2/python-3.13.2-amd64.exe

Run Part1.cmd

Once these are defined, there are two scripts to run. Run the script titled Part1.cmd. The body of this script only has a few of lines.

@ECHO OFF
Copy CLangDefineEnvironmentVariables.cmd + 0-InstallDependencies.cmd Combined.bat
call Combined.bat
del Combined.bat

I combine the environment variables script with the script to install dependencies. I then run that resultant script. If I were to execute these scripts separately, I wouldn’t get the same result. The environment variables in the script CLangDefineEnvironmentVariables.cmd get cleared when the script is finished running. They don’t carry over to the next script. This script will require user interaction. It will download and invoke the installers for Cmake and Python. You’ll need to be at the computer to approve the installation. It will also invoke the Visual Studio installer and automatically select Visual Studio components to add. You will need to approve those, too. Since the script cannot know when these installers have completed their job, it will wait for you to press a key at points before continuing. Once these installations are complete, you’ve completed most of the steps that require user interaction. Close the terminal window and open a new one. This new terminal window will have a different path environment that includes CMake and Python.

Run Part2.cmd

This next script could take a few hours to run. Once invoked, your attention isn’t needed any further. This will be a great time to go out to lunch or go to bed. If all goes well, when you return after this script runs, you will have a working Clang installation.

To run Part2.cmd, open a new terminal window to ensure that the environment variables created by the installations are applicable. Like Part1.cmd, this script combines two scripts and then runs the results. The file that contains the actions performed is 1-BuildClang.cmd.

@echo off
call CLangDefineEnvironmentVariables.cmd
mkdir %InstallRoot%
cd %InstallRoot%
%InstallDrive%
git clone https://github.com/llvm/llvm-project.git
cd llvm-project
git config core.autocrlf false
mkdir build
pushd build
cmake -DLLVM_ENABLE_PROJECTS=clang -G "Visual Studio 17 2022" -A x64 -Thost=x64 ..\llvm
"%MSBUILD_FULL_PATH%" ALL_BUILD.vcxproj /p:Configuration=Release
"%MSBUILD_FULL_PATH%" tools\clang\tools\driver\clang.vcxproj /p:Configuration=Release
mkdir %InstallRoot%\bin
robocopy \build\Debug\bin %InstallRoot%\bin /MIR
"%MSBUILD_FULL_PATH%" clang.vcxproj

Environment Variables

After the build has been run, the executables are there, but they are not added to your path. If you want to add it to your path, run the script CLangDefineEnvironmentVariables.cmd. It will show a variety of folder paths. The path of interest to you is InstallRoot. Within that folder is a subfolder named bin into which all of the executables have been copied. Add that to your path. You will also want to add the linker from Microsoft Visual Studio to your path. The exact location that this is at could vary. But the specific location for your installation can be found in a file that was created by CLangDefineEnvironmentVariables.cmd.

After both of these have been added, if you would like to test out the setup, I’ve got a HelloWorld.cpp with the scripts. In the subfolder, HelloWorld there is a script named build.cmd. Running that will let you know if you’ve successfully set things up.

Terminal Background

In Windows Terminal, I customize the background so that I can quickly recognize which terminal I’m using. For the terminal that I’m using in Clang, I’ve used an LLVM logo. The image that is included in the repository for this script is the same image. Those who customize their Windows Terminals may be interested in using it.


Posts may contain products with affiliate links. When you make purchases using these links, we receive a small commission at no extra cost to you. Thank you for your support.

Mastodon: @j2inet@masto.ai
Instagram: @j2inet
Facebook: @j2inet
YouTube: @j2inet
Telegram: j2inet
Bluesky: @j2i.net

Converting between .Net DateTime and JavaScript Date Ticks

Representations of time can differ significantly between programming languages. I recently mixed some .Net code and JavaScript code and had to make some conversions between time representations. This code is generally useful and is being placed here for those who find themselves looking for a quick conversion. Let’s jump into the code.

const long DOTNET_JAVASCRIPT_EPOCH_DIFFERENCE = 621_355_968_000_000_000;
static long DotNetDateToJavaScriptTicks(DateTime d)
{
    return (d.Ticks - DOTNET_JAVASCRIPT_EPOCH_DIFFERENCE) / 10_000;
}

static DateTime JavaScriptTicksToDotNetDate(long ticks)
{
    long dticks = ticks * 10_000 + DOTNET_JAVASCRIPT_EPOCH_DIFFERENCE;
    var retVal = new DateTime(dticks );
    return retVal;
}

To test that it was working, I converted from a .Net time to JavaScript ticks and then back to .Net time If all went well, then I should end up with the same time that I started with.

var originalDotNetTime = DateTime.Now.Date.AddHours(15).AddHours(4).AddMinutes(0);
var javaScriptTicks = DotNetDateToJavaScriptTicks(originalDotNetTime) ;
var convertedDotNetTime = JavaScriptTicksToDotNetDate(javaScriptTicks);

if(originalDotNetTime == convertedDotNetTime)
{
    Console.WriteLine("Time Conversion Successful!");
}
else
{
    Console.WriteLine("The conversion was unsuccessful");
}

I ran the code, and it worked! Honestly, it didn’t work the first time because I left a 0 off of 10,000. Adding the underscores (_) to the numbers makes discovering such mistakes easier. Were you to use this code in AWS, note that some values in AWS, such as a TTL field on a DynamoDB table, expect values to be in seconds, not milliseconds. The JavaScript ticks value would have to be divided by 1000 when converted from a .Net time or multiplied by 1000 when being converted back to a .Net time.


Posts may contain products with affiliate links. When you make purchases using these links, we receive a small commission at no extra cost to you. Thank you for your support.

Mastodon: @j2inet@masto.ai
Instagram: @j2inet
Facebook: @j2inet
YouTube: @j2inet
Telegram: j2inet
Bluesky: @j2i.net