Is there any way to get more detailed error reports from a windows API call? - c++

I'm working on a pretty large program that makes calls to ChangeDisplaySettingsEx in order to change the layout/resolution around of displays.
I've been running into issues where these calls sometimes work and sometimes they don't, and I can't determine what's causing the failures.
Whenever it fails, I get a return code of -1 which corresponds to DISP_CHANGE_FAILED which clearly is not very descriptive.
I'm wondering if there's any better way to debug the result of the call so I can tell what's causing it to fail?

"I'm wondering if there's any better way to debug the result of the call so I can tell what's causing it to fail?"
You may try to query the actual displays capabilities beforehand, as recommended in the reference documentation:
Remarks
"To ensure that the DEVMODE structure passed to ChangeDisplaySettingsEx is valid and contains only values supported by the display driver, use the DEVMODE returned by the EnumDisplaySettings function."
After doing so you can compare the returned DEVMODE with what you've tried to pass as settings.

Related

Is there a way to receive as a string, the errors from DX12?

Example: Here's the debug log for CreateGraphicsPipelineState, it tells me what went wrong:
D3D12 ERROR: ID3D12Device::CreateGraphicsPipelineState: Root Signature doesn't match Vertex Shader: Shader CBV descriptor range (RegisterSpace=0, NumDescriptors=1, BaseShaderRegister=0) is not fully bound in root signature
However, a call to windows FormatMessage(MESSAGE_FROM_SYSTEM...) will return this for the exact same error:
The parameter is incorrect.
The first is obviously far more useful...
We used to have dxerr.lib, and we have source for dxerr.cpp in DXUT. But this doesn't cover DX12. I can't see any way for a shader-tool to retrieve the error and present it to the user from the API.
This can be done with the ID3D12InfoQueue interface, as documented here:
https://learn.microsoft.com/en-us/windows/win32/api/d3d12sdklayers/nn-d3d12sdklayers-id3d12infoqueue
As far as I can tell it's currently not possible to set a callback, which means that you'll need to explicitly query for feedback.
There are two different sources of error/status information involved here. The error code you have returned from the API call is E_INVALIDARG and you obtained a good string for it. This is the status code from the API.
The descriptive message you see in debug output is emitted by Direct3D 12 debug layer, which you loaded during API initialization. It is, generally speaking, an optional component and might be not available in the system while the API itself is available.
To intercept debug output programmatically you can either
utilize this trick: Capture OutputDebugString output
or, attach as a debugger to your application and process debug output event recording the contents

DirectInput console application

I'm working in C++ in Windows and I need to deal with an input device with force feedback. I found out that one solution could be to use DirectInput and so I start looking at that.
FIRST QUESTION: any suggestions on other ways for dealing with force feedback devices? (Win32 app, not UWP)
Coming back to DirectInput
The reference starting point I have got in my mind is the DirectInput Samples, in particular the FFconst example where a constant feedback force is applied to the first device axis according to a value grabbed from a simple GUI. In my case what I want to achieve is having a simple console application where I set a constant force according to a value grabbed from the standard input.
The basic steps for using the DirectInput API, according to the samples and the documentation, are:
create direct input device calling DirectInput8Create;
look for devices calling EnumDevices filtering devices and limiting scope to the enumeration according to what you are looking for (in my case I'm filtering for looking only in DI8DEVCLASS_GAMECTRL devices and limiting the scope to DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK);
set data format for the selected device(s) calling SetDataFormat in order to be able to acquire the device;
set the cooperative level for the device(s) calling SetCooperativeLevel once again in order to acquire the device;
use the device...
Now, all goes well until we encounter the SetCooperativeLevel mehtod since it needs as input a HWND window handle "to be associate to the device" and which "must be a valid top-level window handle that belongs to the process". Since I'm writing a console application I need to find a valid HWND pointer: I sorted the problem out following this suggestion. Anyway, the HWND pointer I get in that way seems not to be a valid window handle since I get a E_HANDLE error, as I would specify nullptr as argument. I found out that specifying the argument through the call of GetTopWindow allows not to get the invalid handle error. However I'm not able to acquire the device and I get the DIERR_OTHERAPPHASPRIO error, which is nothing more than E_ACCESSDENIED. I found that it seems someone use to treat that error in the same way the DIERR_INPUTLOST error is treated, i.e. re-acquiring the device in a while loop as shown in the Joystick direct input sample in the UpdateInputState function. Anyway trying this I'm not able to exit that loop, i.e. the device device keep being denied.
That said I end up with the
SECOND QUESTION: how to use the DirectInput API in a console application or inside a DLL? (Win32) In case of a console application I'd like to understand why the steps I've done don't work, and in case of a DLL I'd like to know if anyone has an idea on which HWND pointer could be used.
Microsoft provides a function to get a console application's window for uses like this.
HWND WINAPI GetConsoleWindow(void);

Handling WinAPI error return values

I am currently learning C++ in connection with WinAPI. I am struggling to come up with meaningful error handling strategy for WinAPI functions.
PROBLEM:
Most of WinAPI functions can return 0 in case of error, but in many cases I don't see any information on MSDN as to what could cause such error and how to address / resolve it. Taking GetCursorPos as an example:
Returns nonzero if successful or zero otherwise. To get extended error information, call GetLastError.
(...)
The input desktop must be the current desktop when you call GetCursorPos. Call OpenInputDesktop to determine whether the current desktop is the input desktop. If it is not, call SetThreadDesktop with the HDESK returned by OpenInputDesktop to switch to that desktop.
If I follow the route of GetLastError I am interested in what errors could be returned by that specific function so that I can inspect what can be done about them. But error codes are organized on this MSDN page into 10 groups based on just error number and without any specification of what errors are listed in which group.
When I tried to discover how would OpenInputDesktop help me make my code more bulletproof I discovered that again:
If the function fails, the return value is NULL. To get extended error information, call GetLastError.
To sum it up: almost every function in WinAPI can return value determining occurrence of error and I can get information on the error when it happens using GetLastError function. But no information whatsoever on what kinds of errors I can expect and what steps to make to resolve them.
The examples are many, GetWindowRect is also widely used and MSDN delivers the very same limited information as for GetCursorPos.
QUESTION:
Please are there any standards on how to approach WinAPI function error return values that would retain error handling from becoming just showing a message box and exiting the application? Thank you!
As far as knowing ahead of time what possible error codes can be returned by a particular function, I'm afraid that Microsoft decided long time ago that maintaining such documentation for all functions would be too cumbersome and costly, as an API function may call any number of other API functions, which in turn may call others and so on. Sometimes you get lucky and the MSDN doc calls out error codes specific to that function, as is the case with ReadFile but this is not the case with all functions as you have noticed.
That being said, the standard way of dealing with the error codes returned by GetLastError() is to format them with FormatMessage.
If you passed LANG_USER_DEFAULT for lang ID, this will return the sometimes helpful, sometimes not so helpful error message formatted in the user's chosen locale from the error code. You can show this message to the user. If you wanted to format it in your own language for logging purposes, assuming it's English, you would pass MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) for lang ID.
And this is the best you can do if the error codes are not documented and you haven't come across them in testing: log them and get the log with other debug info attached to the issue report.

Calling SetupDiGetClassDevs from Python only returns an integer value

I'm trying to create a simple read/write application for a fairly simple USB device, but it's turning out to be not so simple at all.
I'm using WinUSB and SetupAPI DLLs and working from scratch since I can't seem to find anything that actually works for what I need. PyWinUSB and PyUSB and so on and so forth came close, but when I tried actually writing to the device with them they failed.
Anyway, right now I'm still at about ground zero. Following the instructions, I'm calling the SetupDiGetClassDevsExW function from the SetupAPI.dll. The function executes correctly as indicated by a call to the kernel32.lasterror function returning zero, but the only thing I'm getting back from the call is an integer value. Is that correct? Is this even the correct function? (There are 4 that are similar, and there is no just plain SetupDiGetClassDevs function. The 4 functions are SetupGetClassDevsExW, SetupGetCLassDevsExA, SetupGetClassDevsA, and SetupGetClassDevsW.) Do I need to create a class to work with this? I ask because calling the next function, SetupDiEnumDeviceInterfaces, has only been returning a fail with code 259, which means ERROR_NO_MORE_ITEMS according to a quick google search.
I've made some headway in that someone has showed me the correct class structure method for creating a structure for holding some information, but being that I've never actually worked with programming for a USB device before, let alone in Python, I'm still kind of stuck. I'll provide any more information that is needed for an answer, but right now I don't want to bog this Q/A down with needless information.
Thanks.
There is a SetupDiGetClassDevsA and SetupDiGetClassDevsW. The Ex versions allow connecting to a remote machine. The A version takes a byte string for the second parameter, while the W version takes a Unicode string. The return value is a handle to a device information set.
The device information set has to be iterated with either SetupDiEnumDeviceInfo or SetupDiEnumDeviceInterfaces. The second function only works if you pass DIGCF_DEVICEINTERFACE as a flag to SetupDiGetClassDevs and pass an interface GUID for the ClassGuid parameter; otherwise, you pass a device class GUID and only SetupDiEnumDeviceInfo will return anything.

SetPixelFormat returns 0, but no error is set?

I'm running a VB6 app in WINE and the OpenGL portion of the program doesn't work. It is using PFD_DRAW_TO_BITMAP. PFD_DRAW_TO_WINDOW formats seem to work.
I've enumerated all the pixel formats (there are around 256) and a few of them match what I request. ChoosePixelFormat seems to return a correct format (in this case pixelFormat 6), but when I pass this value into SetPixelFormat it returns 0. I looked at the documentation and it says to check GetLastError() for more information, but when I call that, it returns 0 which formats to a blank error message.
Does anyone know anyway to figure out why SetPixelFormat would fail? I've done some reading and it sounds like DRAW_TO_BITMAP has been implemented since like May 2009.
I know DRAW_TO_BITMAP is not hardware accelerated. That is perfectly acceptable. This app works fine in Windows, -- I just need to figure out why a supported pixel format doesn't seem to get recognized.
I'm running Ubuntu, most recent version of WINE in their package manager, -- on a Quadro if that matters (not sure if Wine attempts to use the underlying graphics card or if it virtualizes all the pixel formats for software rendering)
I don't know why SetPixelFormat would be failing only on WINE, but it is in any case incorrect to call GetLastError manually from VB6 code. VB makes its own DLL calls behind the scenes. These will (generally) succeed, resetting the error code seen by GetLastError and making it useless from VB code.
Instead, VB calls GetLastError itself immediately after every user-initiated DLL call. It saves the value and makes it available as the property Err.LastDllError. Use that to find out the real error code.