Userlibs

Blitz3D Forums/Blitz3D Beginners Area/Userlibs

Chalky(Posted 2006) [#1]
I am trying to create my first userlib program and am having problems.

My "kernel32.decls" file (stripped to show only relevant entry) looks like this (the declaration is on one line - I have inserted the "_" here for readability on the screen):

.lib "kernel32.dll"
GetVolumeInformation%(lpRootPathName$,lpVolumeNameBuffer$,nVolumeNameSize%,lpVolumeSerialNumber%,lpMaximumComponentLength%,lpFileSystemFlags%, _
  lpFileSystemNameBuffer$,nFileSystemNameSize%):"GetVolumeInformationA"


and my bb code looks like this:

Temp1$=String$(Chr$(0),255)
Temp2$=String$(Chr$(0),255)
SerialNum%=0

APICall%=GetVolumeInformation%("C:\",Temp1$,Len(Temp1$),SerialNum%,0,0,Temp2$,Len(Temp2$))

Print APICall%
Print SerialNum%

WaitKey
End


When I run the above, APICall%=1, which I assume means the call has been successful, but SerialNum%=0. I have adapted this from an identical function I created successfully in VB. The only thing I can think that could be causing problems is the difference between Long and Integer variables. Dumb question, but what is the upper limit of the Blitz Integer? If this is a red herring, does anyone have any ideas why SerialNum% is not populated during the call?


Beaker(Posted 2006) [#2]
I think you may have to do something like this:
;.lib "kernel32.dll"
;GetVolumeInformation%(lpRootPathName$,lpVolumeNameBuffer$,nVolumeNameSize%,lpVolumeSerialNumber*,_
;lpMaximumComponentLength%,lpFileSystemFlags%,lpFileSystemNameBuffer$,nFileSystemNameSize%):"GetVolumeInformationA"


Temp1$=String$(Chr$(0),255)
Temp2$=String$(Chr$(0),255)
serialnumbank = CreateBank(4)
Print PeekInt(serialnumbank,0)
	
APICall%=GetVolumeInformation%("C:\",Temp1$,Len(Temp1$),SerialNumbank,0,0,Temp2$,Len(Temp2$))
Print PeekInt(serialnumbank,0)

Print APICall%

WaitKey
End


You will probably have to re-arrange the banks bytes to construct an Int. [EDIT: it seems not]

This gives you some more clues:
Memory thing in code archive


Chalky(Posted 2006) [#3]
Thanks Beaker. I tried your bank version, but the value was still zero. I must admit to being somewhat confused as to how you are supposed to access the windoze api via userlibs. Has any documentation been published anywhere on how to do it? I can't seem to find any, and though I have studied the code in the archives/forums (some of which worked ok), even some of that crashed the Visual C/C++ runtime library!


Chalky(Posted 2006) [#4]
Okay - I take it back Beaker! I have now sussed the fact that parameters passed via banks require a * next to them in the decls. This now returns the correct value in serialnumbank. Thanks for your help!

PS: Mind you - creating a 255 byte bank for the volume name (Temp1$) using the same technique returns 255 zeros... :o/


Boiled Sweets(Posted 2006) [#5]
I stuck a FULL kernel.decls in the code archives


Chalky(Posted 2006) [#6]
Hi Boiled Sweets - you did, and an impressive post it is - I can only imagine how long that took to do! Unfortunately it alone did not enable me as a beginner to blitz userlibs to know what to do with it. I have done extensive api programming with VB, so the api bit I am fine with. What I am struggling with is how parameters are sent back to blitz? Some examples I downloaded from the archives worked fine using variables or types instead of banks - while others crashed the Visual C/C++ runtime from blitzcc.exe. To get my serialnum problem to work I had to modify the decls so that lpVolumeSerialNumber was a bank instead of an integer before I actually retrieved anything other than zero. Doing the same for string variables did not work however. I am confused!


Boiled Sweets(Posted 2006) [#7]
I think this is really down to whether the called API is actually changing the values, i.e. are they call by value or reference.

  Public Declare Function GetVolumeInformation Lib "kernel32" Alias "GetVolumeInformationA" _

(ByVal lpRootPathName As String, _

             ByVal lpVolumeNameBuffer As StringBuilder, _

             ByRef nVolumeNameSize As Integer, _

             ByRef lpVolumeSerialNumber As Integer, _

             ByRef lpMaximumComponentLength As Integer, _

             ByRef lpFileSystemFlags As Integer, _

             ByVal lpFileSystemNameBuffer As StringBuilder, _

             ByRef lpFileSystemNameBuffer As Integer , _

             ByRef nFileSystemNameSize As Integer) As Integer



Please send me a full test case and I'll take a look


Beaker(Posted 2006) [#8]
This works (mostly):
;.lib "kernel32.dll"
;GetVolumeInformation%(lpRootPathName$,lpVolumeNameBuffer*,nVolumeNameSize%,lpVolumeSerialNumber*,_
;lpMaximumComponentLength%,lpFileSystemFlags%,lpFileSystemNameBuffer*,nFileSystemNameSize%):"GetVolumeInformationA"
serialnumbank = CreateBank(4)
volnamebank = CreateBank(255)
For f = 0 To 253
	PokeByte volnamebank,f,65
Next
PokeByte volnamebank,254,0

filesysbank = CreateBank(255)
For f = 0 To 253
	PokeByte filesysbank ,f,65
Next
PokeByte filesysbank ,254,0

Print PeekInt(serialnumbank,0)
	
APICall%=GetVolumeInformation%("C:\",volnamebank,BankSize(volnamebank),SerialNumbank,0,0,filesysbank,BankSize(filesysbank))
Print PeekInt(serialnumbank,0)

Print bankToStr(volnamebank)
Print bankToStr(filesysbank)

Print APICall%

WaitKey
End

Function bankToStr$(bank)
	Local newStr$, f
	For f = 0 To BankSize(bank)-1
		If PeekByte(bank,f)=0 Exit
		newStr = newStr + Chr(PeekByte(bank,f))
	Next
	Return newStr
End Function
As you can see you need to construct a long C style string inside your bank, otherwise the dll will think its an empty string.


Chalky(Posted 2006) [#9]
Ah - NOW I understand! Thanks Beaker - you're a star!


Beaker(Posted 2006) [#10]
Actually, just noticed that this works (for me):
serialnumbank = CreateBank(4)
volnamebank = CreateBank(255)
filesysbank = CreateBank(255)

Print PeekInt(serialnumbank,0)
	
APICall%=GetVolumeInformation%("C:\",volnamebank,BankSize(volnamebank),SerialNumbank,0,0,filesysbank,BankSize(filesysbank))
Print PeekInt(serialnumbank,0)

Print bankToStr(volnamebank)
Print bankToStr(filesysbank)

Print APICall%

WaitKey
End

Function bankToStr$(bank)
	Local newStr$, f
	For f = 0 To BankSize(bank)-1
		If PeekByte(bank,f)=0 Exit
		newStr = newStr + Chr(PeekByte(bank,f))
	Next
	Return newStr
End Function



Chalky(Posted 2006) [#11]
Yeah - works for me too - not convinced I hadn't been a muppet with my decls definition before I tried your chr$(65) bank version (at which point I copied your decls to mine)... :0/