Passing Strings out of Procedures

Just starting out? Need help? Post your questions and find answers here.
Slyvnr
User
User
Posts: 58
Joined: Wed Jun 27, 2007 10:10 pm
Location: USA
Contact:

Passing Strings out of Procedures

Post by Slyvnr »

Greetings All!

I am working on a procedure that uses another companies dll to return information from their web-based database. The information is related to software licensing and activation.

Here is some base information regarding the procedure.

Sample procedure Calls for

VBasic

Code: Select all

Public Function DNA_Param(ByVal param As String, ByRef value As String, ByVal value_size As
Integer) As Integer
C/C++/Objective C

Code: Select all

int __stdcall DNA_Param(char *param,char *value,int value_size);
For VB.NET and C#.NET, the function returns a string with the value of <param>. (I did not include sample code for these languages since we are not working with them, I can if needed).

For all other programming environments, <value> should be a buffer of 256 bytes or greater. <value_size> should
indicate the size of buffer allocated.
If DNA_Param returns “0”, then <value> will contain the value of the <param> from the CDM.
If DNA_Param returns “1”, then a problem occurred with the DNA.DLL.

I am assuming that we fall under the "All other programming environments" and have come up with this for the procedure

Code: Select all

Procedure DNA_Param(Param.s, returnval.s, size.i)
     Result=CallFunction(DNAdll, "DNA_PARAM", @Param, @returnval, @size)
     ProcedureReturn @Result
EndProcedure
I think I should be passing returnval and size in a structure instead so that I can then pull those values. However, I basically just need to have ProcedureReturn returnval and am trying to figure out a way to get the string data that is at @returnval memory. I have tried peeks() and different pointer functions but just get a large integer value. The actual data for the Param="ACTIVATION_DATE" should be a string in "MM/DD/YYYY" format.

Can anyone provide me with a clue as to how to get the actual string and return it. I know I will change the line

Code: Select all

Procedure DNA_Param(Param.s, returnval.s, size.i)
to

Code: Select all

Procedure.s DNA_Param(Param.s, returnval.s, size.i)
in order to return the string but I need to get Result.s to be the correct data first. Any clues or hints. I have looked at this so much for so long, I am now confusing myself and getting off track.

Thanks

Slyvnr
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Passing Strings out of Procedures

Post by luis »

I'm not sure (it's a little confusing with all the params renamed), but something of this kind maybe ?

Assuming DNAddl and "DNA_PARAM" and Param.s are correct:

Code: Select all


returnval = Space(256) ; did you do this ?
size = 256 ; did you do this ?

Procedure.s DNA_Param(Param.s, returnval.s, size.i)
     Result = CallFunction(DNAdll, "DNA_PARAM", @Param, @returnval, size)
     If Result = 0
        ProcedureReturn returnval
     EndIf
     ProcedureReturn ""
EndProcedure

You said
If DNA_Param returns “0”, then <value> will contain the value of the <param> from the CDM.
If DNA_Param returns “1”, then a problem occurred with the DNA.DLL.

So what you did is wrong. You must test result and return the string buffer you allocated (don't need peeks because the buffer you passed is a PB string, you could have allocate them as memory buffers and in that case you should have used peeks).

And size is passed by value, it's not a pointer.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
skywalk
Addict
Addict
Posts: 4211
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Passing Strings out of Procedures

Post by skywalk »

I think you're over complicating things. :?

Code: Select all

Prototype.i DNA_param(param.s, *value, val_size.i)
DNAdll = OpenLibrary(#PB_Any, "DNA.dll") ;<-- Or whatever it is called
If DNAdll
  Global DNA_param.DNA_param = GetFunction(DNAdll, "DNA_PARAM")
Else
  MessageRequester("DNALibOpen", "Error opening DNA.dll.", #MB_ICONERROR)
EndIf
define param$ = "ACTIVIATION_DATE", r$ = Space(255)
define.i ri, somesize = 32 ; or whatever works?
ri = DNA_param(param$, @r$, somesize)
debug trim(r$)
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Slyvnr
User
User
Posts: 58
Joined: Wed Jun 27, 2007 10:10 pm
Location: USA
Contact:

Re: Passing Strings out of Procedures

Post by Slyvnr »

Thanks for the quick replay.

Ok this is the small sample code I used

Code: Select all

;procedure to Open DNA.dll
Procedure UseDNAdll()
     DNAdll=OpenLibrary(#PB_Any,"DNA.dll")
EndProcedure

;release DNA.dll resources
Procedure FreeDNAdll()
     CloseLibrary(DNAdll)
EndProcedure

Procedure.s DNA_Param(Param.s, returnval.s, size.i)
     Result=CallFunction(DNAdll, "DNA_PARAM", @Param, @returnval, size)
     If Result=0
          Debug returnval
          Debug size
     EndIf
     ProcedureReturn returnval
EndProcedure


returndate.s{256}=Space(256)   ;fixed length string with space fill
size.i=256

R=UseDNAdll()
If R=0
     TestingResult$=DNA_Param("ACTIVATION_DATE", returndate, size)
     Debug TestingResult$
Else
     Debug "ERROR OPENING DLL"
     Debug Str(R)
     
EndIf
When I run this result=0 and returnval = blank and size=256 from debug output.

If I change the Debug returnval to Debug @returnval I get a large integer (I assume is a memory address). If I try to Debug PEEKS(@returnval,size) I get blank string of length 256. TO ME, it seems that the CallFunction(DNAdll, "DNA_PARAM", @Param, @returnval, size) is not actually "working". It is simple returning a result code of 0 and nothing else.

I tried changing "ACTIVATION_DATE" to garbage to see if it would at least return an error code and I got a Result =0 still. I do not think the "DNA_Param" function is working right. I will need to do more research. But the changes you offered, make the code seem more "workable" to me. Will post more as I find out what is going on with the actual DNA.dll function.

Slyvnr
User avatar
skywalk
Addict
Addict
Posts: 4211
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Passing Strings out of Procedures

Post by skywalk »

argg...with the prototype you don't need the procedure and callfunction stuff. :wink:
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Passing Strings out of Procedures

Post by luis »

Slyvnr wrote:TO ME, it seems that the CallFunction(DNAdll, "DNA_PARAM", @Param, @returnval, size) is not actually "working". It is simple returning a result code of 0 and nothing else.
There is another possibility. Are you sure the name you are using for the function is correct ?

I never used CallFunction() but I would say one of its problems is the fact you are not sure the name you are using is the correct one ("DNA_PARAM"). This would explain why the return value is always zero (no function in DLL is actually called).

It's a lot safer to use CallFunctionFast(), where you have to get a pointer to that function and you can check it's not ZERO. So I suggest you to try a two step approach: GetFunction() and then CallFunctionFast() only if GetFunction() is successful. Anyway this would be better even if it's not the cause of the problem. So keep it in mind.

Obviously you can also use prototypes as suggested by skywalk. But if you are not familiar with them there is nothing wrong using the more traditional CallFunctionFast() in your case. Prototypes have some advantages though, so if in the end your code will finally work you can check the docs to see about them and experiment with them for future uses.
Last edited by luis on Wed Dec 14, 2011 3:31 pm, edited 1 time in total.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Passing Strings out of Procedures

Post by Danilo »

luis wrote:There is another possibility.
1. The function wants and returns ASCII chars. Does not work with unicode enabled. ;)
2. The last param (size) is .l not .i
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Passing Strings out of Procedures

Post by luis »

Well, aren't those possibilities only if he's compiling the program as unicode and 64 bit ?

I hope he would have mention that :wink:
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Passing Strings out of Procedures

Post by Danilo »

luis wrote:Well, aren't those possibilities only if he's compiling the program as unicode and 64 bit ?

I hope he would have mention that :wink:
Yes. Everybody has unicode enabled by default today.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Passing Strings out of Procedures

Post by luis »

Didn't know that. Wait, I don't have it enabled by default. :)

Let's see if Slyvnr has it. If true then certainly his code must be modified.
"Have you tried turning it off and on again ?"
A little PureBasic review
bosker
Enthusiast
Enthusiast
Posts: 105
Joined: Fri Jan 08, 2010 11:04 pm
Location: Hampshire, UK

Re: Passing Strings out of Procedures

Post by bosker »

@Slyvnr

There are a couple of fundamental problems with your sample code..
1. The function UseDNAdll doesn't return anything but it's used later with R = UseDNAdll(). Result will always be 0.
2. The variable DNAdll isn't declared so it's local in all the various places it's used.

The result of all this is that you are not calling what you think you are.

I would recommend using EnableExplicit which helps greatly. (ie the sample will not compile
Also, as Skywalk suggested, using Prototypes works wonders for calling foreign code.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Passing Strings out of Procedures

Post by luis »

@bosker

Gosh, you are right. At his second post I given for granted the usual stuff was correct and didn't actually looked at the program, only the output. Honestly I thought is was only a fragment, not a completed program.

My bad!

Well the possibilities are growing exponentially. A lot of things to check for him !
"Have you tried turning it off and on again ?"
A little PureBasic review
Slyvnr
User
User
Posts: 58
Joined: Wed Jun 27, 2007 10:10 pm
Location: USA
Contact:

Re: Passing Strings out of Procedures

Post by Slyvnr »

luis wrote: I would say one of this problem is the fact you are not sure the name you are using is the correct one ("DNA_PARAM")
No the function is called "DNA_PARAM". That is the correct function. What I am unsure of is all of the pointer business in the examples and how it needs to be implemented in PureBasic. I understand what pointers are and how they are suppose to be used, but I am still unsure of implementation of pointers and such. I will add the GetFunction() call to verify that the function exists before calling it and will actually return one of my own error messages if it fails.
Thanks for this pointer. (no pun intended)
luis wrote: Well, aren't those possibilities only if he's compiling the program as unicode and 64 bit ?
In Compiler Options I have Create unicode Executabe unchecked. I am on a 64-bit computer running 64-bit windows but am using the PureBasic 32-bit compiler, not the 64-bit compiler. At least I am using the Compiler located in the C:\Program Files (x86)\Purebasic4.41 subdirectory and not the one installed in C:\Program Files\Purebasic4.41. I believe that the (x86) is 32-bit programs and the other is 64-bit programs?
bosker wrote:@Slyvnr

There are a couple of fundamental problems with your sample code..
1. The function UseDNAdll doesn't return anything but it's used later with R = UseDNAdll(). Result will always be 0.
2. The variable DNAdll isn't declared so it's local in all the various places it's used.
Sorry in my haste to finish the post and get out of work I missed the first line of code which is

Global DNAdll.l

which with what you point out I need to modify

Code: Select all

DNAdll=OpenLibrary(#PB_Any,"DNA.dll")
to

Code: Select all

DNAdll=OpenLibrary(#PB_Any,"DNA.dll")
ProcedureReturn DNAdll
- or -
simply change the line

Code: Select all

R=UseDNAdll()
If R=0
to

Code: Select all

UseDNAdll()
If DNAdll<>0  ; Since #PB_Any is used then DNAdll would = the Library # assigned by Purebasic  (Right?)  If it = 0 then it was not open.
Thanks for that point out. Will modify and work with it.

Slyvnr
Slyvnr
User
User
Posts: 58
Joined: Wed Jun 27, 2007 10:10 pm
Location: USA
Contact:

Re: Passing Strings out of Procedures

Post by Slyvnr »

THANKS TO ALL WHO REPLIED!

I GOT IT TO WORK FINALLY.

Procedure Code

Code: Select all

Procedure.s DNA_Param(Param.s, returnval.s, size.l)
     If GetFunction(DNAdll,"DNA_Param")
          Result=CallFunction(DNAdll, "DNA_Param", @Param, @returnval, size)
          Debug Result
          If Result=0
               Debug returnval
               Debug size
          EndIf
          ProcedureReturn returnval
     Else
          ProcedureReturn "Invalid Function Name"
     EndIf
EndProcedure
test code

Code: Select all

Global DNAdll.l

Enumeration
     #ERR_NO_ERROR=0
     #ERR_ACTIVATIONS_EXCEEDED = -3
     #ERR_DNA_DISABLE = -2
     #ERR_VALIDATION_WARNING = -1
     #ERR_NO_CONNECTION = 1
     #ERR_CONNECTION_LOST = 2
     #ERR_LOCKOUT = 3
     #ERR_INVALID_COMMAND = 4
     #ERR_INVALID_PRODUCT_KEY = 5
     #ERR_INVALID_ACTIVATION_CODE = 6
     #ERR_INVALID_PASSWORD = 7
     #ERR_ACTIVATION_EXPECTED = 8
     #ERR_REACTIVATION_EXPECTED = 9
     #ERR_BANNED_ACTIVATION_CODE = 10
     #ERR_NO_EMAIL_PROVIDED = 11
     #ERR_INVALID_BUILD_NO = 12
     #ERR_EVAL_CODE_ALREADY_SENT = 13
     #ERR_EVAL_CODE_UNAVAILABLE = 14
     #ERR_CDM_HAS_EXPIRED = 15
     #ERR_CODE_HAS_EXPIRED = 16
     #ERR_INVALID_NEW_PASSWORD = 17
     #ERR_CDM_WRITE_PROTECTED = 18
     #ERR_CANCELLED_BY_USER = 98
     #ERR_OPERATION_FAILED = 99
EndEnumeration

;procedure to Open DNA.dll
Procedure UseDNAdll()
     DNAdll=OpenLibrary(#PB_Any,"DNA.dll")
EndProcedure

;release DNA.dll resources
Procedure FreeDNAdll()
     CloseLibrary(DNAdll)
EndProcedure

Procedure DNA_SetCDMPathName(pathname.s)
     If GetFunction(DNAdll,"DNA_SetCDMPathName")
          ProcedureReturn CallFunction(DNAdll, "DNA_SetCDMPathName", @pathname)
     Else
          ProcedureReturn -88888
     EndIf
EndProcedure

Procedure.s DNA_Param(Param.s, returnval.s, size.l)
     If GetFunction(DNAdll,"DNA_Param")
          Result=CallFunction(DNAdll, "DNA_Param", @Param, @returnval, size)
          Debug Result
          If Result=0
               Debug returnval
               Debug size
          EndIf
          ProcedureReturn returnval
     Else
          ProcedureReturn "Invalid Function Name"
     EndIf
EndProcedure

returndate.s{260}=Space(260)
size.i=260

UseDNAdll()
Debug DNA_SetCDMPathName("C:\Users\All Users\TestingProgram\TestingProgram.CDM")
Debug DNA_SetINIPathName("C:\Users\All Users\TestingProgram\TestingProgram.INI")
Debug "===="
If DNAdll
     result$=DNA_Param("REACTIVATION_DATE", returndate, size)
     Debug result$
Else
     Debug "ERROR OPENING DLL"
    ; code to process error codes
EndIf

FreeDNAdll()
The problem turned out to be some of the minor things everyone pointed out here plus the BIG PROBLEM was that when running the program from within PureBasic even with the SetCDMPathName command being issued, Purebasic Compiler.exe placed the file not in the defined path but in the PureBasic Temp path which is "C:\Users\{Username}\Local\TEMP\TestingProgram.CDM". Totally disregarding the SetCDMPathName. Not sure if this is a function of running the compile and run command from within Purebasic or not. Will ave to test by building an exe and placing in the correct directory path for finished product and see if it will create the file in the correct SetCDMPathName location.

Again, Thanks all! Once I have this process worked out, I will be creating a wrapper system that can be dropped into any program so that any purebasic programmer who wants to sell their product can do so with an easy to implement software licensing and activation system.

Softworkz.com licensing and activation is cheap (I am looking at selling my program for $6.99 and their charges are $1.09) Kagi.com will be my digitial products storefront/backend and they will charge me $1.31 per sale. Kagi will pay Softworkz.com directly so I do not have to hassle with that bill. I will net $4.59 a sale which I was wanting to make around $5 per sale. I could change my pricing some to make it so that i make $5 each sale but figure the $6.99 is a good price.

Anyway, it is a low cost method for doing software licensing and activation. Cheaper than the $400-$6000 solutions I found elsewhere.

Slyvnr
Post Reply