views:

36

answers:

1

Hey guys,

I downloaded the ATI AGS (ATI GPU Services) Libary, and am attempting to retrieve some basic driver information using this API, from C#. The ATI AGS library is available for download from here:

http://developer.amd.com/gpu/ags/Pages/default.aspx

I wrote a little bit of C# code to pull driver information from the GPU using the AGS API, but I'm having some trouble calling the unmanaged method. I've tried all sorts of different permutations of DllImportAttribute parameters, to no avail. I'm getting either a MarshalDirectiveException or a pInvokeStackImbalance.

I'm pretty sure that this is all due to an incorrect P/Invoke signature, but I have exhausted my knowledge of this API.

By the way, as an aside, you'll see that I'm using the 32-bit DLL, and I seem to be getting farther with it, but when I use the 64-bit DLL, I get a BadImageFormatException.

Here is the code that I'm using:

    [DllImport(
            "atiags.dll"
            , PreserveSig=false
            , ExactSpelling=true
            , ThrowOnUnmappableChar=true
            , CharSet=CharSet.Unicode
            , EntryPoint="agsDriverGetVersionInfo"
    )]
    public static extern void agsDriverGetVersionInfo(
        [MarshalAs(UnmanagedType.Struct)]
        out agsDriverVersionInfoStruct DriverInfo
    );

    public static agsDriverVersionInfoStruct GetAgsDriverVersion()
    {
       agsDriverVersionInfoStruct DriverInfo = new agsDriverVersionInfoStruct();
       agsDriverGetVersionInfo(out DriverInfo);
    }

    public struct agsDriverVersionInfoStruct
    {
        [MarshalAs(UnmanagedType.LPTStr)]
        public string strDriverVersion;
        [MarshalAs(UnmanagedType.LPStr)]
        public string strCatalystVersion;
        [MarshalAs(UnmanagedType.LPStr)]
        public string strCatalystWebLink;
    }

Any ideas?

Edit: Here is the definition of the ATIAGSDriverGetVersionInfo() function in ati_ags.h. According to the ATI AGS documentation (a PDF included in the download), it says to define _ATI_AGS_USE_DLL, so I added this line at the top of my C# class code file:

Documentation Quote

Determine if AGS functionality will be accessed through a dll or static lib. If the dll option is chosen, make sure to define _ATI_AGS_USE_DLL in your project properties. If the static lib option is chosen, no special token needs to be defined.

__inline AGSReturnCode ATIAGSDriverGetVersionInfo( AGSDriverVersionInfoStruct *lpDriverVersionInfo )
{
AGSReturnCode iReturnValue = AGS_SUCCESS;

// Validate params
if ( NULL == lpDriverVersionInfo )
{
    return AGS_FAILURE;
}

#ifdef _ATI_AGS_USE_DLL
// Load the lib
HINSTANCE lib = NULL;
lib = LoadLibrary(TEXT("atiags.dll"));
if (NULL == lib)
{
    lib = LoadLibrary(TEXT("atiags64.dll"));
    if (NULL == lib)
    {
        return AGS_FAILURE;     
    }
}

// Get the function pointer
AGSDRIVERGETVERSIONINFO agsDriverGetVersionInfo = NULL;
agsDriverGetVersionInfo = (AGSDRIVERGETVERSIONINFO)GetProcAddress(lib, "agsDriverGetVersionInfo");
if (NULL == agsDriverGetVersionInfo)
{
    FreeLibrary(lib);
    return AGS_FAILURE;
}
#endif // _ATI_AGS_USE_DLL

// Get the number of GPUs
iReturnValue = agsDriverGetVersionInfo( lpDriverVersionInfo );

#ifdef _ATI_AGS_USE_DLL
// Free the lib
FreeLibrary(lib);
#endif // _ATI_AGS_USE_DLL

return iReturnValue;
}
A: 

In ati_ags.h the AGSDriverVersionInfoStruct struct is declared as follows:

typedef struct _AGSDriverVersionInfoStruct {
  char strDriverVersion[256];
  char strCatalystVersion[256];
  char strCatalystWebLink[256];
} AGSDriverVersionInfoStruct;

Here's how I would declare the equivalent in C#:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct AGSDriverVersionInfoStruct {
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
  public string strDriverVersion;
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
  public string strCatalystVersion;
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
  public string strCatalystWebLink;
}
Richard Cook
Thanks, I will give this a shot.
Trevor Sullivan
Cannot marshal field 'strDriverVersion' of type 'ATI_Config_Reader.agsDriverVersionInfoStruct': Struct or class fields cannot be of type StringBuilder. The same effect can usually be achieved by using a String field and preinitializing it to a string with length matching the length of the appropriate buffer.
Trevor Sullivan
Try with `SizeConst` and using `string` instead.
Richard Cook
Trying to change back to System.String and initialize them to 256 characters in the constructor ....
Trevor Sullivan
[StructLayout(LayoutKind.Sequential)] public struct agsDriverVersionInfoStruct { [MarshalAs(UnmanagedType.LPStr, SizeConst=256)] public string strDriverVersion; [MarshalAs(UnmanagedType.LPStr, SizeConst = 256)] public string strCatalystVersion; [MarshalAs(UnmanagedType.LPStr, SizeConst = 256)] public string strCatalystWebLink; public agsDriverVersionInfoStruct(int dummy) { strDriverVersion = ""; strCatalystVersion = ""; strCatalystWebLink = ""; } }
Trevor Sullivan
It's still returning null values for these fields.
Trevor Sullivan
Have you set `CharSet = CharSet.Ansi`? You should also set that in the p/invoke declaration for `agsDriverGetVersionInfo`.
Richard Cook
I did also try that. I forced it to both Ansi and Unicode. Both continue to return null values.One interesting thing that's missing in the doc is the 3rd property, strCatalystWebLink. It's in the typedef in the header, but not the documentation. They're all defined as 256 bytes ... so I also tried forcing the struct size to 768 bytes, but that didn't help at all either.
Trevor Sullivan
If you set `PreserveSig` to `true` and declare the return type as `int`, what value does the method return?
Richard Cook
Null also. Same for void retval.
Trevor Sullivan
If by "null" you mean zero, this corresponds to `AGS_FAILURE` so there must be something else wrong with the method p/invoke declaration. Hopefully somebody with more ATI knowledge than me can help you out!
Richard Cook
I'm pretty sure it's null, because I am echoing the results to a MessageBox, and it's empty. I also tried getting a retval of _AGSReturnCode by declaring that enum in my C# code and marshaling those values also -- I failed also at that. I appreciate your insight!
Trevor Sullivan
I've submitted a ticket to AMD's developer center. The ticket ID# is 1125, for anyone wanting to reference it. Cheers
Trevor Sullivan
Good luck! Let us know how it works out.
Richard Cook