Entries for tag "windows", ordered from most recent. Entry count: 52.
# 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:
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.)strcpy_s(path, "\"C:\\My Program\\Test.exe\"");
? Yes.^
, 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:
"C:\\My Program\\Test.exe"
? Yes – likely because this parameter is intended exclusively for executable file path."\"C:\\My Program\\Test.exe\""
? No.^
, 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);
"C:\\My Program\\Test.exe"
? No!"\"C:\\My Program\\Test.exe\""
? Yes.^
, 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:
"C:\\My Program\\Test.exe"
? Yes."\"C:\\My Program\\Test.exe\""
? Yes.^
, 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" |
Yes | No | Yes | Yes |
Searching dir of the host app? | No | No | Yes | No |
Searching current dir? | Yes | Yes | Yes | Yes |
Searching PATH env var? | Yes | No | Yes | Yes |
Path with spaces unescaped: My Program\Test.exe |
No | Yes | No | Yes |
Path with spaces enclosed with quotes: "My Program\Test.exe" |
Yes | No | Yes | Yes |
Spaces escaped with ^ : My^ Program\Test.exe |
Yes | No | No | No |
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
# Why I Catch Exceptions in Main Function in C++
Sun
22
Jan 2023
Exception handling in C++ is a controversial topic. On one hand, it can be a good means of reporting and handling errors if done correctly. For it to be free from memory leaks, all memory allocations should be wrapped in smart pointers and other acquired resources (opened files and other handles) wrapped in similar RAII objects. On the other hand, it has been proven many times that the exception mechanism in C++ works very slow. Disabling exception handling in C++ compiler options can speed up the program significantly. No wonder that game developers dislike and disable them completely.
Let’s talk about a command-line C++ program that doesn’t need to disable exception handling in compiler options. Even if it doesn’t use exceptions explicitly, some exceptions may occur, thrown by C++ standard library or some third-party libraries. When a C++ exception is thrown and uncaught, program terminates and process exit code is some large negative number. On my system it is -1073740791 = 0xC0000409.
It would be good if the program printed some error message in such case and returned some custom, clearly defined exit code. Therefore, when developing a command-line C++ program, I like to catch and handle exceptions in the main
function, like this:
#include <exception>
#include <cstdio>
enum PROGRAM_EXIT {
PROGRAM_EXIT_SUCCESS = 0,
PROGRAM_EXIT_FAILED = -1,
PROGRAM_EXIT_EXCEPTION = -2
};
int ActualProgram(int argc, char** argv) {
...
}
int main(int argc, char** argv) {
try {
return ActualProgram(argc, argv);
}
catch(const std::exception& ex) {
fprintf(stderr, "ERROR: %s\n", ex.what());
return PROGRAM_EXIT_EXCEPTION;
}
catch(...) {
fprintf(stderr, "UNKNOWN ERROR.\n");
return PROGRAM_EXIT_EXCEPTION;
}
}
Besides that, if you develop for Windows using Visual Studio, there is another, parallel system of throwing and catching exceptions, called Structured Exception Handling (SEH). It allows you to handle “system” errors that are not C++ exceptions and would otherwise terminate your program, even when using code shown above. This kind of error can be memory access violation (using null or incorrect pointer) or integer division by zero, among others. To catch them, you can use the following code:
#include <Windows.h>
int main(int argc, char** argv) {
__try {
return main2(argc, argv);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
fprintf(stderr, "STRUCTURED EXCEPTION: 0x%08X.\n",
GetExceptionCode());
return PROGRAM_EXIT_EXCEPTION;
}
}
Few additional notes are needed here. First, SEH __try
-__except
section cannot exist in one function with C++ try
-catch
. It is fine, though, to call a function doing one way of error handling from a function doing the other one. Their order is important – C++ exceptions are also caught by SEH __except
, but SEH exceptions are not caught by C++ catch
. So, to do it properly, you need to make your main
function doing SEH __try
-__except
, which calls some main2
function doing C++ try
-catch
, which calls ActualProgram
– not the other way around.
If you wonder what are the process exit codes returned by default when exceptions are not caught, the answer can be found in the documentation of GetExceptionCode macro and Windows header files. When memory access violation occurs, this function (or the entire process, if SEH exceptions are not handled) returns -1073741819 = 0xC0000005, which matches EXCEPTION_ACCESS_VIOLATION
. When a C++ exception is thrown, the code is -1073740791 = 0xC0000409, which is not one of EXCEPTION_
symbols, but I found it defined as STATUS_STACK_BUFFER_OVERRUN
(strange…). Maybe it would be a good idea to extend the __except
section shown above to decode known exception codes and print their string description.
Finally, you need to know that integer division by zero throws a SEH exception, but floating-point division by zero does not – at least not by default. There is EXCEPTION_FLT_DIVIDE_BY_ZERO
and EXCEPTION_INT_DIVIDE_BY_ZERO
error code defined, but the default behavior of incorrect floating-point calculations (e.g. division by zero, logarithm of a negative value) is to return special values like Not a Number (NaN) or infinity and proceed with further calculations. This behavior can be changed, as described in “Floating-Point Exceptions”.
Comments | #windows #visual studio #c++ Share
# My Favorite Windows Apps in 2021
Sun
31
Oct 2021
Last time I showed the list of my favorite apps for the PC was in May 2009 - 12 years go, so maybe it's time post a new one :) If you know a better alternative to any of these programs, please post a comment below.
December 2023 update: I planned to release a new article with the list a of my favorite apps 2 years later, but I found that I still use mostly the same apps, so I updated this article instead, adding notes about what has changed for me in italic font like this.
Before I start with my list, I would like to stress how much the landscape of PC applications changed throughout these years. Back then, many kinds of programs (e.g. for video editing) were very expensive and had no good and free alternative. Among simpler apps, "shareware" was still a thing, so these also required a small fee (or downloading a crack :) Today, we have many excellent programs available for free. All the programs I list below are free unless explicitly mentioned.
With free programs, we have to be careful though. Some of them are free only for non-commercial use, so they shouldn't be installed on a machine provided by your employer and used for work. Examples are HWiNFO or FastStone Image Viewer. The ones licensed under GNU GPL can be freely installed and used for any purpose. It has nothing to do with the availability of the source code. We won't download the code and compile the program by ourselves, anyway. This free software/open source license also guarantees freedom to use program any way we want. With apps coming for free under a custom license (commonly referred as "freeware") this is not necessarily the case, so to be fully compliant you should always check the license (and/or ask your IT department) before installing anything on a company laptop.
There is also a trap awaiting these who download and instal new apps that many websites take free apps and repack them into their own installers, adding some malware, adware, or other unwanted software. They are often positioned higher in Google search results than the original app developer. To make sure you download the right installer, always go to the original website and not any of these app-aggregating portals. Also, be careful which "DOWNLOAD" button you click. An extreme example of developer's greed is FileZilla, which is free software licensed under GPL, but the original website hosts an installer that "may include bundled offers" and hides real installer for the app alone under "Show additional download options" link.
# Programming FreeSync 2 support in Direct3D
Sat
02
Mar 2019
AMD just showed Oasis demo, presenting usage of its FreeSync 2 HDR technology. If you wonder how could you implement same features in your Windows DirectX program or game (it doesn’t matter if you use D3D11 or D3D12), here is an article for you.
But first, a disclaimer: Although I already put it on my “About” page, I’d like to stress that this is my personal blog, so all opinions presented here are my own and do not reflect that of my employer.
Radeon FreeSync (its new, official web page is here: Radeon™ FreeSync™ Technology | FreeSync™ 2 HDR Games) is an AMD technology that covers two different things, which may cause some confusion. First is variable refresh rate, second is HDR. Both of them need to be supported by a monitor. The database of FreeSync compatible monitors and their parameters is: Freesync Monitors.
Comments | #gpu #directx #windows #graphics Share
# Programming HDR monitor support in Direct3D
Wed
27
Feb 2019
I got an HDR supporting monitor (LG 32GK850F), so I started learning how I can use its capabilities programatically. I still have much to learn, as there is a lot of theory to be ingested about color spaces etc., but in this blog post I’d like to go straight to the point: How to enable HDR in your C++ DirectX program? To test this, I used 3 graphics chips from 3 different PC GPU vendors. Below you can see results of my experiments.
Comments | #graphics #windows #directx #gpu Share
# Vulkan with DXGI - experiment results
Mon
19
Nov 2018
In my previous post, I’ve described a way to get GPU memory usage in Windows Vulkan app by using DXGI. This API, designed for Direct3D, seems to work with Vulkan as well. In this post I would like to share detailed results of my experiment on two different platforms with two graphics cards from different vendors. But before that, a disclaimer:
Update 2023-12-14: This is an old article published before Vulkan received VK_EXT_memory_budget extension. With this extension, you can now query for current memory usage and budget natively in Vulkan, with no need to resort to DXGI. This article may still be valuable as long as you observe similar numbers returned in Vulkan.