When using the NVAPI I'm having problems with NvAPI_DISP_GetDisplayConfig. I get an AppCrash on the second call to NvAPI_DISP_GetDisplayConfig.
Can't seem to figure out why.
NvU32 count = 0;
status = NvAPI_DISP_GetDisplayConfig(&count, NULL);
if (status != NVAPI_OK)
PrintError(status);
printf("Configs: %i\n", count);
NV_DISPLAYCONFIG_PATH_INFO *configinfos = new NV_DISPLAYCONFIG_PATH_INFO[count];
configinfos[0].version = NV_DISPLAYCONFIG_PATH_INFO_VER;
status = NvAPI_DISP_GetDisplayConfig(&count, configinfos);
if (status != NVAPI_OK)
PrintError(status);
On my system, count = 2 after the first call.
The notes on NvAPI_DISP_GetDisplayConfig say:
NVAPI_INTERFACE
NvAPI_DISP_GetDisplayConfig(
__inout NvU32 * pathInfoCount,
__out_ecount_full_opt *pathInfoCount NV_DISPLAYCONFIG_PATH_INFO * pathInfo
)
DESCRIPTION: This API lets caller retrieve the current global display
configuration.
USAGE: The caller might have to call this three times to fetch all the required
configuration details as follows:
First Pass: Caller should Call NvAPI_DISP_GetDisplayConfig() with pathInfo set
to NULL to fetch pathInfoCount.
Second Pass: Allocate memory for pathInfo with respect to the number of
pathInfoCount(from First Pass) to fetch //! //! targetInfoCount. If
sourceModeInfo is needed allocate memory or it can be initialized to NULL.
Third Pass(Optional, only required if target information is required): Allocate
memory for targetInfo with respect to number of
targetInfoCount(from Second Pass). SUPPORTED OS: Windows Vista and higher
Thanks.
Edit: I've also tried to set configinfos[0].sourceModeInfo = NULL to no avail. I've also tried to iterate over the array to set all .version and .sourceModeInfo to no avail (an example in the docs I saw only set version on the first item in the array)
This should work for you:
NvAPI_Status status = NVAPI_OK;
NvU32 deviceCount = 0;
NV_DISPLAYCONFIG_PATH_INFO_V2 * pathInfo = NULL;
status = NvAPI_Initialize();
if (status == NVAPI_OK) {
status = NvAPI_DISP_GetDisplayConfig(&deviceCount, pathInfo);
if ((status == NVAPI_OK) && (deviceCount > 0)) {
pathInfo = new NV_DISPLAYCONFIG_PATH_INFO_V2[deviceCount];
for (int i = 0; i < deviceCount; i++)
{
pathInfo[i].targetInfo = 0;
pathInfo[i].targetInfoCount = 0;
pathInfo[i].version = NV_DISPLAYCONFIG_PATH_INFO_VER2;
pathInfo[i].sourceModeInfo = 0;
pathInfo[i].reserved = 0;
}
status = NvAPI_DISP_GetDisplayConfig(&deviceCount, pathInfo);
if (status == NVAPI_OK) {
for (int i = 0; i < deviceCount; i++)
{
pathInfo[i].sourceModeInfo = new NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1;
pathInfo[i].sourceModeInfo->reserved = 0;
pathInfo[i].targetInfo = new NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2[pathInfo[i].targetInfoCount];
for (int j = 0; j < pathInfo[i].targetInfoCount; j++) {
pathInfo[i].targetInfo[j].details = 0;
}
}
}
status = NvAPI_DISP_GetDisplayConfig(&deviceCount, pathInfo);
for (int i = 0; i < deviceCount; i++)
{
if (pathInfo[i].sourceModeInfo) delete pathInfo[i].sourceModeInfo;
if (pathInfo[i].targetInfo) delete [] pathInfo[i].targetInfo;
}
delete[] pathInfo;
}
}
Marcos answer is a more thorough. I believe that the specific problem in your code is that you did not initialize the second pathInfo. So you need to add:
configinfos[1].version = NV_DISPLAYCONFIG_PATH_INFO_VER;
It is also good form to always ininialize your memory. So immediately after allocation you should do:
memset(configinfos, 0, sizeof(NV_DISPLAYCONFIG_PATH_INFO) * count);
or you can individually set the values.
There is a sample named DisplayConfiguration in the sample code that comes with NvAPI that has exploits GetDisplayConfig entirely. Copy pasting the function from DisplayConfiguration.cpp:
NvAPI_Status AllocateAndGetDisplayConfig(NvU32* pathInfoCount, NV_DISPLAYCONFIG_PATH_INFO** pPathInfo)
{
NvAPI_Status ret;
// Retrieve the display path information
NvU32 pathCount = 0;
NV_DISPLAYCONFIG_PATH_INFO *pathInfo = NULL;
ret = NvAPI_DISP_GetDisplayConfig(&pathCount, NULL);
if (ret != NVAPI_OK) return ret;
pathInfo = (NV_DISPLAYCONFIG_PATH_INFO*) malloc(pathCount * sizeof(NV_DISPLAYCONFIG_PATH_INFO));
if (!pathInfo)
{
return NVAPI_OUT_OF_MEMORY;
}
memset(pathInfo, 0, pathCount * sizeof(NV_DISPLAYCONFIG_PATH_INFO));
for (NvU32 i = 0; i < pathCount; i++)
{
pathInfo[i].version = NV_DISPLAYCONFIG_PATH_INFO_VER;
}
// Retrieve the targetInfo counts
ret = NvAPI_DISP_GetDisplayConfig(&pathCount, pathInfo);
if (ret != NVAPI_OK)
{
return ret;
}
for (NvU32 i = 0; i < pathCount; i++)
{
// Allocate the source mode info
pathInfo[i].sourceModeInfo = (NV_DISPLAYCONFIG_SOURCE_MODE_INFO*) malloc(sizeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO));
if (pathInfo[i].sourceModeInfo == NULL)
{
return NVAPI_OUT_OF_MEMORY;
}
memset(pathInfo[i].sourceModeInfo, 0, sizeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO));
// Allocate the target array
pathInfo[i].targetInfo = (NV_DISPLAYCONFIG_PATH_TARGET_INFO*) malloc(pathInfo[i].targetInfoCount * sizeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO));
if (pathInfo[i].targetInfo == NULL)
{
return NVAPI_OUT_OF_MEMORY;
}
// Allocate the target details
memset(pathInfo[i].targetInfo, 0, pathInfo[i].targetInfoCount * sizeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO));
for (NvU32 j = 0 ; j < pathInfo[i].targetInfoCount ; j++)
{
pathInfo[i].targetInfo[j].details = (NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO*) malloc(sizeof(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO));
memset(pathInfo[i].targetInfo[j].details, 0, sizeof(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO));
pathInfo[i].targetInfo[j].details->version = NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_VER;
}
}
// Retrieve the full path info
ret = NvAPI_DISP_GetDisplayConfig(&pathCount, pathInfo);
if (ret != NVAPI_OK)
{
return ret;
}
*pathInfoCount = pathCount;
*pPathInfo = pathInfo;
return NVAPI_OK;
}
Now this function can be used as easily as:
NV_DISPLAYCONFIG_PATH_INFO *pathInfo = NULL;
NvU32 pathCount = 0;
_allocateAndGetDisplayConfig(&pathCount, &pathInfo);
// Do whatever you need with the queried display data here