Tag: windows

Entries for tag "windows", ordered from most recent. Entry count: 52.

Pages: 1 2 3 ... 7 >

# 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

# 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.

Introduction

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.

 

 

 

Comments | #windows Share

# 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.

 

 

 

Comments | #vulkan #directx #graphics #windows Share

Pages: 1 2 3 ... 7 >

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