Help with API stuff

letdown427

Golden Member
Jan 3, 2006
1,594
1
0
I'm aware that VB6 is hardly the best language out there, but I haven't started learning C++ yet (only been doing VB6 for about a year I spose)

Anyway, I want to programmatically get the temp from my nvidia GPU. I've found what I need to use, an API call to the nvcpl.dll. I've found the documentation for using it, but unfortunately, don't know how to use that :confused:

I'll put it at the bottom of the post, hopefully someone can show me how to make it into a useable function.

I tried doing it like:

Private Declare Function (Name) Lib "nvcpl.dll" Alias "NVcplgetthermalSettings" and so on, but on calling that, Vb6 just crashed, so I'm fairly sure that I did that wrong. I haven't had to structure a functino declare like that myself before, I've managed to tweak existing ones, and so though I'd give it a go, but any help would be much appreciated.

In the API documentation, there is a VB script that they provided, so I was hoping that I'd be able to call this from VB6.

Thanks for any help.

Function_______________________BOOL CDECL NvCplGetThermalSettings
Prototype______________________(IN UINT nWindowsMonitorNumber,
_______________________________OUT DWORD* pdwCoreTemp,
_______________________________OUT DWORD* pdwAmbientTemp,
_______________________________OUT DWORD* pdwUpperLimit);

Parameters In ___________________UINT nWindowsMonitorNumber --
________________________________The display number shown on the Windows Display
________________________________Properties->Settings page. A value of 0 indicates
________________________________the current primary Windows display device.
________________________________DWORD* must be a valid pointer --
________________________________pdwCoreTemp -- GPU temperature in degrees Celsius.
________________________________pdwAmbientTemp -- Ambient temperature in degrees Celsius.
________________________________pdwUpperLimit -- Upper limit of the GPU temperature specification.

Return Values __________________True on success.
______________________________False on failure.
 

xtknight

Elite Member
Oct 15, 2004
12,974
0
71
When it asks you for a pointer, you need to specify one by using the ByRef operator. You put this in the declaration of the function in VB.

Unless it indicates otherwise, you should pass a value, not a pointer. Ensure you're doing this by using the ByVal operator prior to any variables you're passing. The last three do need to be pointers, and since you used ByRef in the declaration, you can't put ByRef in the call. For some reason ByVal is fine in both places. Just use it in both the declaration and the call to make sure. The code below shows how it should be done. I haven't tested it however.

UINT is an unsigned integer - 32-bit in length. Unfortunately, no such type exists in VB. Only a 32-bit signed integer ("Long") does. It should be fine though as long as you don't have more than 2^16 monitors. I don't even know why they decided to make nWindowsMonitorNumber so big. With the example code I'm assuming the first monitor is a 0.

DWORD is an unsigned long in the Windows API. The max we can get in VB6 is a signed integer (the rather misnamed "Long" type). I can't guarantee that it'll work but it might. I'm not sure how to get around those differences. You may have to write a C library to be called from VB.

With BOOL in C, 0 is FALSE, and 1 is TRUE. However, in VB, if I remember right, 'true' is -1 and 'false' is 0. You must account for these differences.

P.S. It's important to note:

VB6:
'Integer' = Signed 16-bit integer
'Long' = Signed 32-bit integer

C:
'int' = Signed 32-bit integer
'long' = Signed 64-bit integer (no VB6 equivalent exists)
'UINT' = Unsigned 32-bit integer (no VB6 equivalent exists)
'DWORD' (wrt Windows API) = Unsigned 64-bit integer (no VB6 equivalent exists)

Please let me know whether/how well the code works. If it doesn't, you will have to write a C library to call nvcpl.dll and then pass supported variable types back to VB6. You might be able to call it with VB.NET too. I believe they have signed/unsigned types for all CLR languages. Signed/unsigned simply indicates the presence of a 'signed' bit, one that marks a number as negative or positive. A 32-bit signed integer has space for half of a 32-bit unsigned integer in each direction (positive and negative). It's like either having 0-50 or -25 to 25, except -(2^16) to ((2^16)-1)..... :)

You might be able to get around variable type limitations by passing a byte() array.

Dim b(1 to 4) as Byte ' (8*4) 32-bit unsigned integer?
Then, you would have to write some binary code to read it in properly and you'd have to store it in a string. Not easy, but probably still possible in VB6.
 

letdown427

Golden Member
Jan 3, 2006
1,594
1
0
On calling the function, I get RTE 49, bad DLL calling convention. Any ideas? :)

Thanks very much!

EDIT:
Some googling makes it look like maybe the thing you said about types expected etc isn't working out... :(
linky
And as I don't know C either, looks like I'm at a dead end for the moment...



Just noticed your edit,

"You might be able to get around variable type limitations by passing a byte() array.

Dim b(1 to 4) as Byte ' (8*4) 32-bit unsigned integer?
Then, you would have to write some binary code to read it in properly and you'd have to store it in a string. Not easy, but probably still possible in VB6."

So instead of passing the various Longs, I'd have to define byte arrays and pass those in instead yeah?

I'll try my best! Thanks again.
 

xtknight

Elite Member
Oct 15, 2004
12,974
0
71
I suspected there would be problems. (You rarely get it the first try with these things.)

Bad DLL calling convention

Arguments passed to a dynamic-link library (DLL) must exactly match those expected by the routine. Calling conventions deal with number, type, and order of arguments. Your program may be calling a routine in a DLL that is being passed the wrong type or number of arguments.

Yikes. It uses CDECL. STDCALL is needed for VB6 compatibility, so unfortunately you can not call functions in NvCpl.dll from VB6. CDECL/STDCALL is something they have to code into the nvcpl.dll.

Function_______________________BOOL CDECL NvCplGetThermalSettings....

I think you can call CDECL functions from VB.NET using <DllImport(.....CallingConvention:=CallingConvention.Cdecl)>.

You could try this in VB6: http://www.pscode.com/vb/scripts/ShowCode.asp?lngWId=1&txtCodeId=49776
 

letdown427

Golden Member
Jan 3, 2006
1,594
1
0
Originally posted by: xtknight
Yikes. It uses CDECL. STDCALL is needed for VB6 compatibility, so unfortunately you can not call functions in NvCpl.dll from VB6. CDECL/STDCALL is something they have to code into the nvcpl.dll.

If you're saying Yikes, then I'm not going to be able to do this just yet! I've only really looked at VB6 in my entire year of programming, so for the moment, I think this is going to be beyond me...

Once I've got some C under my belt ( :confused: ) I'll have to take another look.

Thanks for the help, I know who to PM if I'm in trouble again :p:p

EDIT:

Missed your edit. OK, I'll have a look!
 

xtknight

Elite Member
Oct 15, 2004
12,974
0
71
This guy's CDECL class is awesome. I'm already having success calling some CDECL functions with that code. Let's see what we can do.

Another thing is, VB uses unicode strings. Many CDECL functions like ANSI strings. I used a Byte() array to get around that and it worked perfectly. Fortunately your function doesn't need a string. Just for reference, though:

Dim sBuf2(0 To 19) As Byte (8-bit data type, or 'char' in C)
sBuf2(0) = Asc("5") ' get ASCII code for the number 5
sBuf2(1) = Asc("6")
sBuf2(2) = Asc("4")
sBuf2(3) = 0 'null-terminated string

'atoi prototype: int atoi (char* string);

Dim r as Long
r = p.CallFunc("atoi", StrPtr(sBuf2))
MsgBox CStr(r)


'I called the ASCII to Integer function in the Standard C library, and I got back my answer as expected: 564, which is what I filled my string with. Apparently I should use StrPtr and VarPtr in some cases instead of ByRef.

We don't need to do anything as complicated as what he did in his example code. This is a pretty basic function call we're doing here. In fact it's very similar to 'atoi' with a few changes. His class requires that we receive a Long, but that's not a problem.

Look in frmMain:Form_Load() in his example so you're not totally lost with me. Basically, he made a class called cCDECL and this is a 'wrapper' to call CDECL functions from VB6. That means we can instantaniate his class to do so.

Code excerpts and changes I suspect are required:
...
Set p = New cCDECL 'Create cDECL instance
sDLL = "NVCPL"

'Load the DLL
...

Dim r as Long
Dim coretemp as Long, ambienttemp as Long, upperlimit as Long
r = p.CallFunc("NvCplGetThermalSettings", ByVal 0&, VarPtr(coretemp), VarPtr(ambienttemp), VarPtr(upperlimit))

...

I have an NVIDIA card as well and I'd love to see if I could do this so I'll see what I come up with later tonight. I'm confident I can get this to work somehow. Working around limitations is the beauty of working with VB6. ;) Everybody else will think we're insane for going thru this with VB6, but I think it's a great language that has lots of potential. I have lots of sympathy for people trying to expand on VB6, because I know when I was trying to, help was hard to find (everybody just said use C, etc). And, you know what, you will learn more about the underlying concept of function calls using these hacks than just by making a C library for it.
 

letdown427

Golden Member
Jan 3, 2006
1,594
1
0
Awesome, thanks!

I'd got to the stage where I had to put in the ParamArray ParmLongs() AS Variant, but as I haven't seen that VarPtr() before, I don't think I would've got that bit!

Now, to find the equivalent for ATI cards.... :p

:beer:
 

xtknight

Elite Member
Oct 15, 2004
12,974
0
71
moo.dll is what the SystemInfo mIRC script is based on. I forgot about that one. I thought mIRC required stdcall as well though?
 

letdown427

Golden Member
Jan 3, 2006
1,594
1
0
Originally posted by: xtknight
moo.dll is what the SystemInfo mIRC script is based on. I forgot about that one. I thought mIRC required stdcall as well though?
I've no idea about mIRC at all to be honest, I just stumbled across moo.dll as part of my googling for how to get any sort of temperature reading out of the PC. But as it turns out, the functions in moo return mainly just information, so it still won't help.

It's also a massive PITA that none of the WMI stuff really seems to have been finished. Like I said, all of the useful typically hard to get to things are in there, but haven't been implemented yet.
That was a major letdown to keep working through wbemtest.exe to the result you wanted, only to find that it showed nothing, or a completely random non-changing value...

Still, s'all part of the learning process I'm sure.

On a side note, I had a look for an ATI equivalent of the NvCpl.dll, and any sort of documentation, but they seem to offer nothing. Couldn't find anything related to an ATI GPU API other than DirectX/OpenGL things. The CCC definately has a temperature reading though, but it seems it's very selfish with it.
 

xtknight

Elite Member
Oct 15, 2004
12,974
0
71
Yeah, programming with graphics cards is a pain. NVCPL is pretty decent but I couldn't find a way to read clock speed. All the software like RivaTuner, Coolbits, and PowerStrip do it, but there's no indication of how. There's 'nvclock' for Linux and Linux software is always great because it's open-source. But, then where's the ATI equivalent? There's no excuse for them to not release a library.

I hate it when people release programs and just keep it all under closed doors as to how they did it. It's pretty frustrating and it doesn't help anything. If you want money for the program I can understand that, but at least if you release it free just tell us how you did it too! /rant

Very silly of MS not to implement something they have the capability of doing, but to put the responsibility on the developer instead to figure out what is going on with all this stuff. Vista better have a better API.