Page 1 of 2

Posted: Wed Jul 03, 2002 7:14 pm
by BackupUser
Restored from previous forum. Originally posted by Shawn.

Hi.

I am writing a program using procedures with memory and library functions, and am having difficulty returning results from the procedure. I have rewritten the sample below without procedures and it works fine. With procedures, the program crashes on the ProcedureReturn line.

I am using Windows2000 and Dr Watson gives the error "Exception number: 0000005 (access violation)"

The program is for a travel agency on a private network so you won't be able to test this example, but here is what it is supposed to do:

The program should establish a connection with the airline reservation system (a.k.a. Sabre, "the host") in order to send and recieve messages later on in the program.

The dll provides a function for establishing a connection (ConnectToHost). It takes a pointer to a string (#SabreRoute) and will return a pointer (*SabreHandle) to a session handle to be used later.

I have shared the 2 pointers in the procedure because otherwise I get a message saying that the "Specified address is null" when trying the line "result = PeekL(*SabreHandle)"

I am using PB version 3.20.

Does anyone know why this doesn't work and what I can do instead?

Thanks.

Shawn

This code doesn't work. (with procedures)

Code: Select all

#ProgramName = "Sabre Connection"
#SabreRoute = "FIXEDOFEPSABRE"
Global SabreHandle.l
 
If OpenLibrary(0, "CCSAPI.DLL")
Else
  MessageRequester(#ProgramName, "Error opening Library - This program will end.",0)
  End
EndIf
 
Procedure.l ConnectToSabre()
  Shared *Route, *SabreHandle
  CallDebugger
  result.l = 0
  *Route = AllocateMemory(0, Len(#SabreRoute), 0)
  *SabreHandle = AllocateMemory(1, 1, 0)
  PokeS(*Route, #SabreRoute)
  Debug "*Route = " + Str(*Route) ; yields *Route = 8003216
  Debug "*SabreHandle = " + Str(*SabreHandle) ; yields *SabreHandle = 8003240
  If CallFunction(0, "ConnectToHost", *SabreHandle, *Route) = 0
    result = PeekL(*SabreHandle)
  EndIf
  Debug "result = " + Str(result) ; yields result = 10682440 (random number generated by the host)
  ProcedureReturn result
EndProcedure 
 
SabreHandle.l = ConnectToSabre()
If SabreHandle.l = 0 
  MessageRequester(#ProgramName, "Error connecting to host - This program will end.",0)
  End
EndIf
 
CloseLibrary(0)
This code works. (without procedures)

Code: Select all

 
#ProgramName = "Sabre Connection"
#SabreRoute = "FIXEDOFEPSABRE"
Global SabreHandle.l
 
If OpenLibrary(0, "CCSAPI.DLL")
Else
  MessageRequester(#ProgramName, "Error opening Library - This program will end.",0)
  End
EndIf
 
;Procedure.l ConnectToSabre()
;  Shared *Route, *SabreHandle
  CallDebugger
  result.l = 0
  *Route = AllocateMemory(0, Len(#SabreRoute), 0)
  *SabreHandle = AllocateMemory(1, 1, 0)
  PokeS(*Route, #SabreRoute)
  Debug "*Route = " + Str(*Route) ; yields *Route = 8003216
  Debug "*SabreHandle = " + Str(*SabreHandle) ; yields *SabreHandle = 8003240
  If CallFunction(0, "ConnectToHost", *SabreHandle, *Route) = 0
    result = PeekL(*SabreHandle)
  EndIf
  Debug "result = " + Str(result) ; yields result = 10682440 (random number generated by the host)
;  ProcedureReturn result
;EndProcedure 
 
SabreHandle.l = result
If SabreHandle.l = 0 
  MessageRequester(#ProgramName, "Error connecting to host - This program will end.",0)
  End
EndIf
 
CloseLibrary(0)

 

Posted: Thu Jul 04, 2002 8:13 pm
by BackupUser
Restored from previous forum. Originally posted by Shawn.

Through the process of elimination, I have found that the problem happens only when the ConnectToHost function is called, and it writes to *SabreHandle.

Does anyone know what could be different inside a procedure? It is curious that it doesn't crash otherwise.

Thanks.

Shawn

Posted: Fri Jul 05, 2002 8:56 am
by BackupUser
Restored from previous forum. Originally posted by tinman.
Does anyone know what could be different inside a procedure? It is curious that it doesn't crash otherwise.
You are allocating 1 byte of memory for the *SabreHandle and trying to peek a longword from it (I also guess that the ConnectToHost function pokes a long in there). I don't know why it would work inside or outside and procedure, and that might not even be the thing causing it, but it is defaintely wrong.



--
It's not minimalist - I'm increasing efficiency by reducing input effort.
(Win98first ed. + SP1, PB3.20)

Posted: Fri Jul 05, 2002 12:19 pm
by BackupUser
Restored from previous forum. Originally posted by Shawn.

You are allocating 1 byte of memory for the *SabreHandle and trying to peek a longword from it (I also guess that the ConnectToHost function pokes a long in there). I don't know why it would work inside or outside and procedure, and that might not even be the thing causing it, but it is defaintely wrong.
Thanks for pointing it out.

I changed the line to read
*SabreHandle = AllocateMemory(1, 4, 0)
but it still crashes.

Thanks.

Shawn

Posted: Fri Jul 05, 2002 1:38 pm
by BackupUser
Restored from previous forum. Originally posted by tinman.
Thanks for pointing it out.

I changed the line to read
*SabreHandle = AllocateMemory(1, 4, 0)
but it still crashes.
Weird. I don't know whats happening, because I don;t think anything else in your code looks wrong. I never knew PB could handle string constants, so it might be worth trying something else in case it is that (I don't know for sure though, maybe they work fine).

This is how I'd do the code, but I do not know what the ConnectToHost function is, so I cannot comment on that. You also need to allocate 1 more byte for a NULL character at the end of strings. You should really check the result of memory allocation before poking or peeking the memory. You might also want to free the memory, but maybe not if it needs to stick around for the entire time that the connection is made to the host.

Code: Select all

ProgramName$ = "Sabre Connection"
SabreRoute$ = "FIXEDOFEPSABRE"
Global SabreHandle.l
 
If OpenLibrary(0, "CCSAPI.DLL")
Else
  MessageRequester(ProgramName$, "Error opening Library - This program will end.",0)
  End
EndIf
 
Procedure.l ConnectToSabre()
  DefType.l *SabreHandle
  DefType.b *Route
  Shared SabreRoute$

  result.l = 0
  *Route = AllocateMemory(0, Len(SabreRoute$)+1, 0)
  If *Route0
    *SabreHandle = AllocateMemory(1, 4, 0)
    If *SabreHandle0
      PokeS(*Route, SabreRoute$)
      Debug "*Route = " + Str(*Route) ; yields *Route = 8003216
      Debug "*SabreHandle = " + Str(*SabreHandle) ; yields *SabreHandle = 8003240
      If CallFunction(0, "ConnectToHost", *SabreHandle, *Route) = 0
        result = PeekL(*SabreHandle)
      EndIf
      Debug "result = " + Str(result) ; yields result = 10682440 (random number generated by the host)
    EndIf
  EndIf
  ProcedureReturn result
EndProcedure 
 
SabreHandle.l = ConnectToSabre()
If SabreHandle.l = 0 
  MessageRequester(ProgramName$, "Error connecting to host - This program will end.",0)
  End
EndIf
 
CloseLibrary(0)

--
It's not minimalist - I'm increasing efficiency by reducing input effort.
(Win98first ed. + SP1, PB3.20)

Posted: Sat Jul 06, 2002 4:24 am
by BackupUser
Restored from previous forum. Originally posted by Shawn.

Thanks Tinman for your help with this.

I got the same result. I also tried freeing the memory banks as you suggested.

The program crashes when the procedure ends. I even changed the procedure so that it didn't return a result.

Since PB can create dll's now, maybe I can write a test one to use instead. I guess it could be a bug in PB.

Thanks again.

Shawn

Posted: Tue Jul 09, 2002 2:55 am
by BackupUser
Restored from previous forum. Originally posted by Shawn.

I wrote a test dll using PB and did not find any problem with the program crashing at the end of the procedure. FYI, I have included the test dll code I used in the test.

It looks like PB and the other dll do not get along. Unless someone has a brainstorm, I will give up on using PB for this project.

Thanks all.

Shawn

Code: Select all

;test dll code
ProcedureDLL.l ConnectToHost(HandleOutPointer.l, StringInPointer.l)
  If StringInPointer.l  0
    str$ = PeekS(StringInPointer.l)
    MessageRequester("Test", "StringIn = " + str$, 0)
  EndIf

  If HandleOutPointer.l  0 
    MessageRequester("Test", "HandleOutPointer = " + Str(HandleOutPointer), 0)
    PokeL(HandleOutPointer.l,58)
    MessageRequester("Test", "HandleOut value = " + Str(PeekL(HandleOutPointer.l)), 0)
  EndIf
  ProcedureReturn 0
EndProcedure
  
 

Posted: Tue Jul 09, 2002 11:54 am
by BackupUser
Restored from previous forum. Originally posted by El_Choni.

Shouldn't this be Long instead of Byte? (probably doesn't make a difference, but who knows):
DefType.b *Route
Bye,

El_Choni

Posted: Tue Jul 09, 2002 2:16 pm
by BackupUser
Restored from previous forum. Originally posted by Shawn.
Shouldn't this be Long instead of Byte? (probably doesn't make a difference, but who knows):
DefType.b *Route
I tested it both ways.

There seems to always be a problem returning from the procedure. The results are great inside the procedure, and also great if I don't use procedures at all.

Dr Watsons says the problem is an access violation.

Thanks.

Shawn

Posted: Tue Jul 09, 2002 3:46 pm
by BackupUser
Restored from previous forum. Originally posted by Danilo.

Code: Select all

;test dll code
ProcedureDLL.l ConnectToHost(HandleOutPointer.l, StringInPointer.l)


  If StringInPointer.l  0
    str$ = PeekS(StringInPointer.l)
    MessageRequester("Test", "StringIn = " + str$, 0)
  EndIf


  If HandleOutPointer.l  0 
    MessageRequester("Test", "HandleOutPointer = " + Str(HandleOutPointer), 0)
    PokeL(HandleOutPointer.l,58)
    MessageRequester("Test", "HandleOut value = " + Str(PeekL(HandleOutPointer.l)), 0)
  EndIf


  ProcedureReturn 0
EndProcedure


;
; Test Code
;
*StringInPointer = AllocateMemory(1,1000)
*HandleOutPointer = AllocateMemory(2,1000)


PokeS(*StringInPointer,"Hello World!")


x = ConnectToHost(*HandleOutPointer, *StringInPointer)


MessageRequester("INFO","Return = "+StrU(x,2)+Chr(10)+"HandleOut = "+StrU(PeekL(*HandleOutPointer),2),0)
Your last procedure works fine in a program.
Maybe the way you call the DLL is wrong ??

Can you give us the code that calls the DLL
with this last procedure ??

cya,
...Danilo

(registered PureBasic user)

Posted: Tue Jul 09, 2002 4:30 pm
by BackupUser
Restored from previous forum. Originally posted by Shawn.

Your last procedure works fine in a program.
Maybe the way you call the DLL is wrong ??

Can you give us the code that calls the DLL
with this last procedure ??

cya,
...Danilo

(registered PureBasic user)
Yes, the code entitled "test dll code" works. I am calling it with the code in tinman's post above (with underscore added to front of function name, and *Route defined as long). I wrote the test dll to see if PB had a generic problem returning from a procedure that used a dll. PB works fine with this test dll.

The problem occurs when I try to use the real dll. No code available for this one - sorry. It is an API used to communicate with the airline reservation system. My program communicates with this dll fine and give correct responses to all functions in the dll. When my procedure ends however, *bang*, my program crashes with the access violation error.

I have tried changing my procedure so that it doesn't return a value, so that isn't the problem.

I could write everything without accessing any DLL function within a procedure and there would be no crashes, but the program would get kind of long and ugly. :)

Thanks.

Shawn

Posted: Tue Jul 09, 2002 5:34 pm
by BackupUser
Restored from previous forum. Originally posted by El_Choni.

It looks like a stack problem. Are you sure that the function takes two arguments as parameters? And that it's stdcall (I mean, it cleans the stack before returning)?

If not, I can't figure out the problem, sorry.

El_Choni

Posted: Tue Jul 09, 2002 6:32 pm
by BackupUser
Restored from previous forum. Originally posted by Shawn.
It looks like a stack problem. Are you sure that the function takes two arguments as parameters? And that it's stdcall (I mean, it cleans the stack before returning)?
Thanks. I have posed the question to the developers. I will wait to see what answer I get back.

Shawn

Posted: Tue Jul 09, 2002 6:37 pm
by BackupUser
Restored from previous forum. Originally posted by Shawn.
It looks like a stack problem. Are you sure that the function takes two arguments as parameters? And that it's stdcall (I mean, it cleans the stack before returning)?
Thanks. I have posed the question to the developers. I will wait to see what answer I get back.

Shawn


I forgot to mention...
Yes, the function takes 2 arguments. It also returns an integer result for an error code - might this make a difference?



Edited by - shawn on 09 July 2002 19:39:23

Posted: Wed Jul 10, 2002 1:15 pm
by BackupUser
Restored from previous forum. Originally posted by Shawn.

It seems that the DLL I am working with uses cdecl.

Thanks for the clue El_Choni.

Is there anything I can do in my code to make it work? I read the BlitzBasic DLL thread on the subject, but it was a bit beyond me.

There is a COM interface to the dll. However, I haven't seen the PB COM documentation yet. Can someone point me to it?

Thanks.

Shawn



Edited by - shawn on 10 July 2002 14:21:37