How to call a dll function that returns a structure?
How to call a dll function that returns a structure?
I'm trying to call a function from a dll that returns a structure and not a structure pointer. Is this possible to do natively in PureBasic?
If I try to call the function without a return parameter the dll crashes with an access violation. The same occurs if I try to assign the result to a structure pointer. How can this be done if PureBasic doesn't support structures as a return parameter?
I'm wrapping these commands in C to return a structure pointer. Is there any way to make this work in just PureBasic?
From what I've read here it looks like this is not possible.
http://www.purebasic.fr/english/viewtopic.php?t=29155
If I try to call the function without a return parameter the dll crashes with an access violation. The same occurs if I try to assign the result to a structure pointer. How can this be done if PureBasic doesn't support structures as a return parameter?
I'm wrapping these commands in C to return a structure pointer. Is there any way to make this work in just PureBasic?
From what I've read here it looks like this is not possible.
http://www.purebasic.fr/english/viewtopic.php?t=29155
how big is the structure? can you return it in a different type? Would it fit inside a quad? you could pull the data out afterwards with a union or something...
I heard once that fixed strings are passed on the stack and not a copied data pointer like dynamic strings, can you pass it back in a fixed string hard-set to the size of the structure?
I heard once that fixed strings are passed on the stack and not a copied data pointer like dynamic strings, can you pass it back in a fixed string hard-set to the size of the structure?
Paul Dwyer
“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
- Hroudtwolf
- Addict
- Posts: 803
- Joined: Sat Feb 12, 2005 3:35 am
- Location: Germany(Hessen)
- Contact:
A function returns a pointer if the return-variable was a dataset.I'm trying to call a function from a dll that returns a structure and not a structure pointer. Is this possible to do natively in PureBasic?
For reading datasets from functionresult, use following way.
Code: Select all
Procedure Blub ()
*dataset.point = AllocateMemory (SizeOf (POINT))
*dataset\x = 100
*dataset\y = 150
ProcedureReturn *dataset
EndProcedure
*dataset.point = Blub ()
Debug *dataset\x
Debug *dataset\y
Wolf
I have three different structures that I need to return. There is one function that returns an 8-byte structure but the dll still crashed when I tried to return it to a double.
Maybe PureBasic is incorrectly handling returning C structures? I should create my own dll in C to test this theory.
Code: Select all
PrototypeC.d ProtoFunction(VectorID)
lib=LoadLibrary_("Library.dll")
ptr=GetProcAddress_(lib,"FunctionName")
Function.ProtoFunction=ptr
this.d=Function(1)
- Hroudtwolf
- Addict
- Posts: 803
- Joined: Sat Feb 12, 2005 3:35 am
- Location: Germany(Hessen)
- Contact:
Ok. Here is an example to work with.
This gives us a starting point to work with (again, if this is even possible).
Here is the dll compiled:
http://3dfolio.com/files/Return_Struct.dll
Code: Select all
/* Return_Struct.c */
#define ExportC __declspec(dllexport)
typedef struct MyStruct {
float a;
float b;
float c;
} MyStruct;
ExportC MyStruct ReturnStruct(int Param1) {
MyStruct Local;
Local.a=1;
Local.b=3;
Local.c=5;
return Local;
}
Code: Select all
lib=LoadLibrary_("Return_Struct.dll")
ptr=GetProcAddress_(lib,"ReturnStruct")
Structure MyStruct
a.f
b.f
c.f
EndStructure
; you can't do this
*this.MyStruct=CallCFunctionFast(ptr,1)
Debug *this\a
Debug *this\b
Debug *this\c
Here is the dll compiled:
http://3dfolio.com/files/Return_Struct.dll
- Hroudtwolf
- Addict
- Posts: 803
- Joined: Sat Feb 12, 2005 3:35 am
- Location: Germany(Hessen)
- Contact:
Maybe, you have to allocate a unprotected memoryblock for that.
You could try this.
You could try this.
Code: Select all
ExportC MyStruct ReturnStruct(int Param1) {
MyStruct* Local;
Local = malloc(sizeof(MyStruct));
Local->a=1;
Local->b=3;
Local->c=5;
return Local;
}
- tinman
- PureBasic Expert
- Posts: 1102
- Joined: Sat Apr 26, 2003 4:56 pm
- Location: Level 5 of Robot Hell
- Contact:
I don't know if this kind of thing is compiler dependant, but I've coded a test in C and the assembly generated looks like this:Mistrel wrote:Ok. Here is an example to work with.
Code: Select all
; 9 : MyStruct foo;
; 10 :
; 11 : foo = ReturnStruct(6);
mov esi, esp
push 6
lea eax, DWORD PTR $T78404[ebp]
push eax
call DWORD PTR __imp__ReturnStruct
add esp, 8
cmp esi, esp
call __RTC_CheckEsp
mov ecx, DWORD PTR [eax]
mov DWORD PTR _foo$[ebp], ecx
mov edx, DWORD PTR [eax+4]
mov DWORD PTR _foo$[ebp+4], edx
mov eax, DWORD PTR [eax+8]
mov DWORD PTR _foo$[ebp+8], eax
Code: Select all
lib.l=LoadLibrary_("debug\ReturnStruct.dll")
Structure MyStruct
a.f
b.f
c.f
EndStructure
Define.MyStruct foo
; you can't do this
;*this.MyStruct=CallCFunctionFast(ptr,1)
PrototypeC ReturnStruct(*struct.MyStruct, Param1.l)
*ptr.ReturnStruct=GetProcAddress_(lib, "ReturnStruct")
If *ptr=0
Debug GetLastError_()
Else
*ptr(@foo, 6)
Debug foo\a
Debug foo\b
Debug foo\c
EndIf
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
(WinXPhSP3 PB5.20b14)
Hey! It works! That's some hack, tinman. Thank you!
I don't understand what the errors are from. I added a new function:
This function calls fine but GetLastError_() reports that the file could not be found

I don't understand what the errors are from. I added a new function:
Code: Select all
ExportC int ReturnVal() {
return 7;
}
Code: Select all
Procedure.s ShowAPIError(CheckReturnValue) ; forum code, unsure of original author
Buffer.s=Space (4096)
NumberOfChars=FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM,0,CheckReturnValue,0,Buffer.s,Len(Buffer.s),0)
ProcedureReturn Left(Buffer.s,NumberOfChars-2)
EndProcedure
lib=LoadLibrary_("Return_Struct.dll")
ptr=GetProcAddress_(lib,"ReturnVal")
Debug ShowAPIError(GetLastError_())
Debug CallCFunctionFast(ptr)
End
- tinman
- PureBasic Expert
- Posts: 1102
- Joined: Sat Apr 26, 2003 4:56 pm
- Location: Level 5 of Robot Hell
- Contact:
Are you sure that the error code is up-to-date? Usually you only call GetLastError_() if there was an error so a function may not change it if there has been no error. You can check by calling SetLastError_(0) before your LoadLibrary_() call (or somewhere else).Mistrel wrote:This function calls fine but GetLastError_() reports that the file could not be found
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
(WinXPhSP3 PB5.20b14)
I'm positive. You should see the same result if you run that code.
I don't understand how your trick works. How does the external procedure know to pass the structure to the first parameter and not to the return value? I know that's how you wrote the prototype but it doesn't match the actual function.
I don't understand how your trick works. How does the external procedure know to pass the structure to the first parameter and not to the return value? I know that's how you wrote the prototype but it doesn't match the actual function.
- tinman
- PureBasic Expert
- Posts: 1102
- Joined: Sat Apr 26, 2003 4:56 pm
- Location: Level 5 of Robot Hell
- Contact:
No, I get "The operation completed successfully" in the debug window using your original code.Mistrel wrote:I'm positive. You should see the same result if you run that code.
With this (MSVC2005) compiler it looks like the behaviour for returning a structure by value is to require an additional hidden parameter that the compiler inserts automatically and then uses that as the destination for the return statement. But I think this behaviour is compiler dependant. I found a draft C standard on the net and I could not find anything that said how values should be returned.Mistrel wrote:I don't understand how your trick works. How does the external procedure know to pass the structure to the first parameter and not to the return value? I know that's how you wrote the prototype but it doesn't match the actual function.
IMO returning by value is fine within an application (or perhaps even an application private DLL) but if you have some control over it then do it differently for DLL functions.
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
(WinXPhSP3 PB5.20b14)