Tag: winapi

Entries for tag "winapi", ordered from most recent. Entry count: 21.

Warning! Some information on this page is older than 6 years now. I keep it for reference, but it probably doesn't reflect my current knowledge and beliefs.

Pages: 1 2 3 >

# How to programmatically check graphics driver version

Sat
16
Dec 2023

This article is for you if you are a graphics programmer who develops for Windows using Direct3D 11, 12, or Vulkan, and you want to fetch the version of the graphics driver currently installed in your user's system programmatically. If you are in a hurry, you can jump straight to the recommended solution in section "DXGI way" below. However, because this topic is non-trivial, I invite you to read the entire article, where I explain it comprehensively.

 

 

 

Comments | #rendering #directx #vulkan #windows #winapi Share

# Ways to Print and Capture Text Output of a Process

Sun
02
Jul 2023

In my previous blog post “Launching process programmatically: system vs CreateProcess vs ShellExecute”, I investigated various ways of launching a new process when programming in C++ using Windows, with the focus on different ways to specify a path to the executable file. Today, I want to describe a related topic: we will investigate ways that a process can print some text messages (standard output, standard error, WriteConsole function, DebugOutputString function), how we can observe this output and, finally, how we can capture it programmatically when launching a subprocess using CreateProcess function.

Visual Studio / C++ project accompanying this article: github.com/sawickiap/TextOutputTest

 

 

 

Comments | #windows #winapi Share

# Launching process programmatically: system vs CreateProcess vs ShellExecute

Sat
15
Apr 2023

Today I went on a quest to investigate various ways in which we can launch a process (an EXE file) programmatically, while programming in C++ using Windows. I tested 3 different functions: system, CreateProcess, ShellExecute. I focused on ways to specify a path to the executable file – not on passing parameters and not on capturing standard input/output of the subprocess (which I plan to investigate next and I did). All examples below launch a subprocess and wait until it completes before continuing. They all make the subprocess inheriting the console, so if both main process and the subprocess are console programs, their output will go to the single console of the main process.

But first things first: To understand this article, please recall that in operating systems we commonly use, no matter if Windows or Linux, every executable file launched as a process has several parameters:

Paths in the file system can be absolute (in case of Windows it usually means they start with drive letter, like “C:\Dir1\Text.exe”) or relative.

Startup directory is often the same as the directory where the executable file is located, but it doesn’t need to be. Many methods of process launching offer an explicit parameter for it. We won’t use it in the code samples below, but you can also achieve this manually from system console. For example, following console command uses a relative path to launch an executable located in “C:\Dir2\Test.exe”, while current directory of the process will be the same as current directory of the console: “C:\Dir1”:

C:\Dir1>..\Dir2\Test.exe

Method 1: Function system from standard C library (required header: <stdlib.h> or <cstdlib> in C++) is the simplest, most primitive one. It just takes a single string as parameter. An advantage of it is that you can launch any console command with it, also built-in commands (like “echo”), not only EXE files. It is also portable between different operating systems.

#include <cstdlib>

int main()
{
    char path[MAX_PATH];
    strcpy_s(path, "Test.exe");

    system(path);
}

Waiting for the command to finish is the default behavior of this function and so is inheriting the console, so that messages printed to the standard output by “Test.exe” will go to the same console as our host application.

path can always be absolute or relative. For each of the 4 methods described in this article, I found answers to following questions:

  1. Does it work with file name alone without an extension, like "Test"? In case of this function: Yes, it does.
  2. When only file name (relative path) is specified, like "Test.exe", where is the function able to locate the executable file?
    1. In the same directory where host EXE is located? No.
    2. In the current directory? Yes.
    3. In one of the directories passed though PATH environmental variable? Yes.
  3. When the path contains spaces, like "C:\My Program\Test.exe", how to escape it properly?
    1. Does it work as-is without any escaping, like strcpy_s(path, "C:\\My Program\\Test.exe");? No. (Note the double backslash \\ is for escaping in C++, so that string will actually contain single backslashes. You can also use forward slashes / in Windows – they work with all methods described in this article and they don’t need to be escaped in C++ code.)
    2. Does it work when entire path is enclosed with quotes, like strcpy_s(path, "\"C:\\My Program\\Test.exe\"");? Yes.
    3. Does it work when spaces are escaped with character ^, like strcpy_s(path, "C:\\My^ Program\\Test.exe");? Yes! (However strange it looks, this is the character used as an escape sequence in Windows shell!)

Method 2: Function CreateProcess from WinAPI (required header: <Windows.h>) is likely the most native and most feature-rich option. Numerous parameters passed to the function and accompanying structures allow to control the new subprocess in various ways, including getting and using its process handle or capturing its standard input/output. Here, for simplicity, I replicate the behavior of system function from method 1 – I make it inherit the console by passing parameter bInheritHandles = TRUE and wait until it completes by calling WaitForSingleObject on the process handle. Process handle and main thread handle also need to closed to avoid resource leak.

STARTUPINFO startupInfo = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION processInfo = {};
BOOL success = CreateProcess(
  path, // lpApplicationName
  NULL, // lpCommandLine
  NULL, // lpProcessAttributes
  NULL, // lpThreadAttributes
  TRUE, // bInheritHandles
  0, // dwCreationFlags
  NULL, // lpEnvironment
  NULL, // lpCurrentDirectory
  &startupInfo,
  &processInfo);
assert(success);
WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hThread);
CloseHandle(processInfo.hProcess);

There are actually 2 ways to pass executable file path to CreateProcess. Code above shows the first way – using lpApplicationName parameter, which is intended for just application name, while command line parameters are passed via next argument. Note this is different from system function, which accepts one string with everything. Using the method shown above:

  1. Does it work with file name alone without an extension, like "Test"? No.
  2. When only file name is specified, like "Test.exe", where is the function able to locate the executable file?
    1. In the same directory where host EXE is located? No.
    2. In the current directory? Yes.
    3. In one of the directories passed though PATH environmental variable? No!
  3. When the path contains spaces, how to escape it properly?
    1. Does it work as-is without any escaping, like "C:\\My Program\\Test.exe"? Yes – likely because this parameter is intended exclusively for executable file path.
    2. Does it work when entire path is enclosed with quotes, like "\"C:\\My Program\\Test.exe\""? No.
    3. Does it work when spaces are escaped with character ^, like "C:\\My^ Program\\Test.exe"? No.

Method 3: Function CreateProcess, but this time passing executable file path as lpCommandLine parameter, while leaving lpApplicationName set to NULL. This is also a valid use case and it behaves differently – more like launching a console command than starting a specific EXE file.

STARTUPINFO startupInfo = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION processInfo = {};
BOOL success = CreateProcess(
  NULL, // lpApplicationName <- !!!
  path, // lpCommandLine <- !!!
  NULL, // lpProcessAttributes
  NULL, // lpThreadAttributes
  TRUE, // bInheritHandles
  0, // dwCreationFlags
  NULL, // lpEnvironment
  NULL, // lpCurrentDirectory
  &startupInfo,
  &processInfo);
assert(success);
WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hThread);
CloseHandle(processInfo.hProcess);
  1. Does it work with file name alone without an extension, like "Test"? Yes!
  2. When only file name is specified, like "Test.exe", where is the function able to locate the executable file?
    1. In the same directory where host EXE is located? Yes!
    2. In the current directory? Yes.
    3. In one of the directories passed though PATH environmental variable? Yes!
  3. When the path contains spaces, how to escape it properly?
    1. Does it work as-is without any escaping, like "C:\\My Program\\Test.exe"? No!
    2. Does it work when entire path is enclosed with quotes, like "\"C:\\My Program\\Test.exe\""? Yes.
    3. Does it work when spaces are escaped with character ^, like "C:\\My^ Program\\Test.exe"? No!

Method 4: Function ShellExecuteEx (or legacy ShellExecute) which is also part of WinAPI, but coming from header <shellapi.h>. It requires COM to be initialized with CoInitializeEx. It can be used not only to start processes from EXE files, but also to open any types of files (TXT or DOCX documents, JPEG images etc.) with their associated programs, as if the user double-clicked on such file or right-clicked and selected one of the available “verbs”, like “Edit” or “Print”. But for this article, let’s focus on launching executable files. To replicate the same behavior as in previous methods, I pass SEE_MASK_NO_CONSOLE to inherit console and SEE_MASK_NOCLOSEPROCESS to retrieve process handle to be able to wait for it.

CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
SHELLEXECUTEINFO shellExecuteInfo = {
  .cbSize = sizeof(SHELLEXECUTEINFO),
  .fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE,
  .lpFile = path,
  .nShow = SW_SHOWNORMAL
};
BOOL success = ShellExecuteEx(&shellExecuteInfo);
assert(success);
WaitForSingleObject(shellExecuteInfo.hProcess, INFINITE);
CloseHandle(shellExecuteInfo.hProcess);

This method behaves in the following way:

  1. Does it work with file name alone without an extension, like "Test"? Yes.
  2. When only file name is specified, like "Test.exe", where is the function able to locate the executable file?
    1. In the same directory where host EXE is located? No!
    2. In the current directory? Yes.
    3. In one of the directories passed though PATH environmental variable? Yes.
  3. When the path contains spaces, how to escape it properly?
    1. Does it work as-is without any escaping, like "C:\\My Program\\Test.exe"? Yes.
    2. Does it work when entire path is enclosed with quotes, like "\"C:\\My Program\\Test.exe\""? Yes.
    3. Does it work when spaces are escaped with character ^, like "C:\\My^ Program\\Test.exe"? No.

To summarize, let’s see all the results in a table:

  system() CreateProcess()
lpApplicationName
CreateProcess()
lpCommandLine
ShellExecuteEx()
Works without extension? "Test" YesNoYesYes
Searching dir of the host app? NoNoYesNo
Searching current dir? YesYesYesYes
Searching PATH env var? YesNoYesYes
Path with spaces unescaped: My Program\Test.exe NoYesNoYes
Path with spaces enclosed with quotes: "My Program\Test.exe" YesNoYesYes
Spaces escaped with ^: My^ Program\Test.exe YesNoNoNo

I did my tests using Windows 10, Version 22H2 (OS Build 19045.2846) and Visual Studio 2022 17.5.3. Although unlikely, it is not impossible that these results may change on another version of the operating system or C++ compiler and standard library implementation.

Comments | #windows #c++ #winapi Share

# When QueryPerformanceCounter call takes long time

Sun
03
Dec 2017

QueryPerformanceCounter function is all about measuring time and profiling performance, so I wasn't able to formulate right Google query to find a solution to the problem I had - call to QueryPerformanceCounter function itself taking too much time. Below I describe what I eventually found out.

It all started from hardware failure. My motherboard stopped working, so I needed to buy a new one (ASRock X370 Killer SLI). I know that normally changing motherboard requires reinstalling Windows, but I tried not to do it. The system didn't want to boot, so I booted the PC using pendrive with Windows installer and launched the repair function. It helped - after that Windows was able to start and everything seemed to work... until I launched the program that I develop on that machine. It was running painfully slow.

I tried different things to find out what is happening. Input/output to hard drive or network was not an issue. GPU performance was also OK. It seemed that the app is just doing its calculations slowly, like the CPU was very slow. I double-checked actual CPU and RAM frequency, but it was OK. Finally I launched sampling profiler (the one embedded in Visual Studio - command: Analyze > Performance Profiler). This way I found that most of the time is spent in function QueryPerformanceCounter.

This WinAPI function is the recommended way to obtain a timestamp in Windows. It's very precise, monotonic, safe to use on multiple cores and threads, it has stable frequency independent of CPU power management or Turbo Boost... It's just great, but in order to meet all these requirements, Windows may use different methods to implement it, as described in article Acquiring high-resolution time stamps. Some of them are fast (just reading TSC register), others are slow (require system call - transition to kernel mode).

I wrote a simple C++ program that tests how long it takes to execute QueryPerformanceCounter function. You can see the code here: QueryPerformanceCounterTest.cpp and download 64-bit binary here: QueryPerformanceCounterTest.zip. Running this test on two different machines gave following results:

CPU: Intel Core i7-6700K, Motherboard: GIGABYTE Z170-HD3-CF:

> QueryPerformanceCounterTest.exe 1000000000
Executing QueryPerformanceCounter x 1000000000...
According to GetTickCount64 it took 0:00:11.312 (11.312 ns per call)
According to QueryPerformanceCounter it took 0:00:11.314 (11.314 ns per call)

CPU: AMD Ryzen 7 1700X, Motherboard: ASRock X370 Killer SLI (changed from different model without system reinstall):

> QueryPerformanceCounterTest.exe 10000000
Executing QueryPerformanceCounter x 10000000...
According to GetTickCount64 it took 0:00:24.906 (2490.6 ns per call)
According to QueryPerformanceCounter it took 0:00:24.911 (2491.1 ns per call)

As you can see, the function takes 11 nanoseconds on first platform and 2.49 microsenonds (220 times more!) on the second one. This was the cause of slowness of my program. The program calls this function many times.

I tried to fix it and somehow convince Windows to use the fast implementation. I uninstalled and reinstalled motherboard drivers - the latest ones downloaded from manufacturer website. I upgraded and downgraded BIOS to different versions. I booted the system from Windows installation media and "repaired" it again. I restored default settings in UEFI/BIOS and tried to change "ACPI HPET Table" option there to Disabled/Enabled/Auto. Nothing worked. Finally I restored Windows to factory settings (Settings > Update & Security > Recovery > Reset this PC). This solved my problem, but unfortunately it's like reinstalling Windows from scratch - now I need to install and configure all the apps again. After that the function takes 22 ns on this machine.

My conclusions from this "adventure" are twofold:

  1. It is valid for function QueryPerformanceCounter to execute slowly on some platforms, like for 2.5 microseconds. If you call it just once per rendering frame then it doesn't matter, but you shouldn't profile every small portion of your code with it, calling it millions of times.
  2. Windows 10 still requires reinstallation when changing motherboard. Otherwise, even if it seems to work, you may experience strange issues like this one.

Update 2017-12-11: A colleague told me that enabling/disabling HPET using "bcdedit" system command could possibly help for that issue.

Update 2018-12-17: Blog post "Ryzen Threadripper for Game Development – optimising UE4 build times" on GPUOpen.com, section "HPET timer woes", seems to be related to this topic.

Comments | #windows #optimization #hardware #winapi Share

# Lost clicks and key presses on low FPS

Sun
22
Oct 2017

There is a problem with handling input from mouse and keyboard in games and other interactive applications that I just solved. I would like to share my code for the solution. When your app uses a loop that constantly calculates and renders frames, like games usually do, it may seem natural to just read current state of every mouse and keyboard key (whether it's down or up) on each frame. You may then caculate derived information, like whether a button has just been pressed on released, by comparing new state to the state from previous frame. This is how Dear ImGui library works. So first solution could look like this:

void UpdateFrame()
{
    // Fill ImGui::GetIO().DeltaTime, KeyCtrl, KeyShift, KeyAlt etc.
    ImGui::GetIO().MouseDown[0] = (GetKeyState(VK_LBUTTON) & 0x8000) != 0;
    ImGui::GetIO().MouseDown[1] = (GetKeyState(VK_RBUTTON) & 0x8000) != 0;
    ImGui::GetIO().MouseDown[2] = (GetKeyState(VK_MBUTTON) & 0x8000) != 0;
    for(uint32_t i = 0; i < 512; ++i)
        ImGui::GetIO().KeysDown[i] = (GetKeyState(i) & 0x8000) != 0;
    
    ImGui::NewFrame();
    
    if(ImGui::IsKeyPressed('A'))
        // Do something...
}

There is one problem with this approach. If user presses and releases a key for a very short time, so that both press and release happens between two frame, it will go unnoticed. This is very annoying. It happens especially when:

First step towards solving this is to react to "real" events that are sent by the operating system:

 

 

 

Comments | #gui #winapi #windows Share

# Handling Multiple Mice with Raw Input

Thu
21
Mar 2013

When you connect second USB mouse to your computer, you don't have second cursor to move on the screen and click on things. Instead you can move and click the single cursor with both mice. What if you want to distinguish messages from multiple mice in your program? I found the solution here. I downloaded and looked at the source code of MouseParty.zip linked from this page.

Handling multiple mice is possible using part of WinAPI called Raw Input. If you have <Windows.h> included, have your WinAPI window and message loop, you only need to initialize Raw Input like this:

RAWINPUTDEVICE device;
device.usUsagePage = 0x01;
device.usUsage = 0x02;
device.dwFlags = 0;
device.hwndTarget = 0;
RegisterRawInputDevices(&device, 1, sizeof device);

You then start to receive WM_INPUT message, which should be handled this way:

case WM_INPUT:
  OnRawInput(
    GET_RAWINPUT_CODE_WPARAM(wParam) == RIM_INPUT,
    (HRAWINPUT)lParam);
  // Must call DefWindowProc!
  break;

 

 

 

Comments | #winapi Share

# Easiest Way to Generate a Bitmap

Wed
19
Oct 2011

I wanted to visualize results of some mathematical computations so I wondered what is the easiest way to generate and then show or save a bitmap? I considered Scilab, PHP with GD library, C++ with WinAPI GDI, C++ with some library that have image file formats support like FreeImage... Finally I've came up with the following solution, using only C++ and WinAPI to fill appropriate data structures and save the image as 24-bit BMP file.

// Width and height of the bitmap
unsigned size_x = 1280, size_y = 720;
// Rows top-down,
// for each row pixels from left to right,
// for each pixel components B, G, R = 0..255.
unsigned data_size = size_x * size_y * 3;
unsigned char *data = new unsigned char[data_size];

// Here fill the data, for example:
for (unsigned y = 0, i = 0; y < size_y; ++y) {
  for (unsigned x = 0; x < size_x; ++x) {
    data[i++] = 255; // G
    data[i++] = 255; // B
    data[i++] = 255; // R
  }
}

// Prepare data structures
DWORD data_offset = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
DWORD file_size = data_offset + data_size;
BITMAPFILEHEADER file_header = {
  0x4D42, // bfType = "BM"
  file_size, // bfSize
  0, 0, // bfReserved1, bfReserved2
  data_offset, // bfOffBits
};
BITMAPINFOHEADER info_header = {
  sizeof(BITMAPINFOHEADER), // biSize
  (LONG)size_x, -(LONG)size_y, // biWidth, biHeight
  1, // biPlanes
  24, // biBitCount
  BI_RGB, // biCompression
  0, // biSizeImage
  72, 72, // biXPelsPerMeter, biYPelsPerMeter
  0, 0, // biClrUsed, biClrImportant
};

// Save file
FILE *file = fopen("file_name.bmp", "wb");
fwrite(&file_header, sizeof(file_header), 1, file);
fwrite(&info_header, sizeof(info_header), 1, file);
fwrite(&data[0], 1, data_size, file);
fclose(file);

// Finalize
delete [] data;

Comments | #rendering #winapi #c++ Share

# Handling Ctrl+C in Windows Console Application

Wed
28
Sep 2011

Just a small code snippet: Let's say you write a console application in native C++ for Windows. Closing the console by pressing Ctrl+C, Ctrl+Break or clicking on close window button [X] kills the process. Is there any way to handle such event and close the program gracefully? The answer is calling SetConsoleCtrlHandler() WinAPI function and implementing your own HandlerRoutine callback function. The template looks like this:

// Handler function will be called on separate thread!
static BOOL WINAPI console_ctrl_handler(DWORD dwCtrlType)
{
  switch (dwCtrlType)
  {
  case CTRL_C_EVENT: // Ctrl+C
    break;
  case CTRL_BREAK_EVENT: // Ctrl+Break
    break;
  case CTRL_CLOSE_EVENT: // Closing the console window
    break;
  case CTRL_LOGOFF_EVENT: // User logs off. Passed only to services!
    break;
  case CTRL_SHUTDOWN_EVENT: // System is shutting down. Passed only to services!
    break;
  }

  // Return TRUE if handled this message, further handler functions won't be called.
  // Return FALSE to pass this message to further handlers until default handler calls ExitProcess().
  return FALSE;
}

int main(int argc, char **argv)
{
  SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
  ...
}

If your program performs some loop and you want the user to be able to break it by closing the console or pressing Ctrl+C, you can solve it this way:

static volatile bool g_exit = false;

static BOOL WINAPI console_ctrl_handler(DWORD dwCtrlType)
{
  g_exit = true;
  return TRUE;
}

int main(int argc, char **argv)
{
  SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
  initialize();
  while (!g_exit)
    do_a_piece_of_work();
  finalize();
}

Comments | #windows #winapi #c++ Share

Pages: 1 2 3 >

[Download] [Dropbox] [pub] [Mirror] [Privacy policy]
Copyright © 2004-2024