Using a C library

Just starting out? Need help? Post your questions and find answers here.
User avatar
hallodri
Enthusiast
Enthusiast
Posts: 208
Joined: Tue Nov 08, 2005 7:59 am
Location: Germany
Contact:

Post by hallodri »

use pointer

Code: Select all

*MyString.vstring [...]
Lazarus404
User
User
Posts: 74
Joined: Fri Dec 02, 2005 3:11 pm
Location: England
Contact:

Post by Lazarus404 »

No, it isn't helping :( Aren't there any examples of using external libs with pointers or structs being passed in and out of PB? I would have though it a necessity to get half of the libraries that exist in PB to work :-S

Thanks,
Laz

Registered PureBasic user since Nov 2005
Check out FlashML at www.designrealm.co.uk... The ultimate Flash Component
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Post by tinman »

Have you tried something like:

Code: Select all

strng$ = "some string"
*mystruct.type = getString(@strng$)
result$ = PeekS(returnString(*mystruct))
Unfortunately I can't test that here. I can't get the .lib file I've created imported correcrtly. Perhaps you could share the header and c source for your lib if you have it? Or the releavant sections anyway.

The above code can be improved using prototypes, but you can't catch an imported function return as a string according to the docs, so PeekS() is the easiest way to get it as a string.
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
Lazarus404
User
User
Posts: 74
Joined: Fri Dec 02, 2005 3:11 pm
Location: England
Contact:

Post by Lazarus404 »

Thanks, but I now get:

POLINK: warning: Unrecognised option 'manifestdependency:"type='win32"; ignored.
POLINK: fatal error: File not found: 'name='Microsoft.VC().Debug.CRT".

I'd guess it's found an error in my dll, so I'll look into this :)

Regards,
Laz

Registered PureBasic user since Nov 2005
Check out FlashML at www.designrealm.co.uk... The ultimate Flash Component
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Post by tinman »

Sounds like you've got two things going on there:

1) You're using a debug version of your C lib, which probably isn't a problem in itself.
2) You're using some visual C runtime functions. You'll need to link the final executable with the correct library - you can probably get this from the linker command line options in your C lib project's property page. I think you can set extra linker options for the PB compiler in the IDE somewhere.

Out of curiosity, how did you get your (I assume) VC library to import correctly, I can't get it to work at all here :(
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
Lazarus404
User
User
Posts: 74
Joined: Fri Dec 02, 2005 3:11 pm
Location: England
Contact:

Post by Lazarus404 »

I specified the complete path to the lib. Here's what I actually have (not that mine is working either :( )

ImportC "C:\Documents and Settings\Lee\My Documents\__Development\devlib\devlib.lib"

n_alloc_string( str$ )
n_val_string( str )

EndImport
Laz

Registered PureBasic user since Nov 2005
Check out FlashML at www.designrealm.co.uk... The ultimate Flash Component
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Post by tinman »

Looks like the PellesC linker (polink.exe) does not like the "/manifestdependency" linker option that MSVC adds to the resulting .lib file. I installed PellesC to get the latest link (NB: this might have an effect on it finding the runtime libraries if you have probs with that) but that still didn't work.

What did work was editing out the section of the .lib file which read as follows (replace it all with spaces):

Code: Select all

/manifestdependency:"type='win32' name='Microsoft.VC80.CRT' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b'"
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
Lazarus404
User
User
Posts: 74
Joined: Fri Dec 02, 2005 3:11 pm
Location: England
Contact:

Post by Lazarus404 »

That didn't work for me. Windows throws up a debug error, asking if I'd like to open it in Visual Studio. Not good.
Laz

Registered PureBasic user since Nov 2005
Check out FlashML at www.designrealm.co.uk... The ultimate Flash Component
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Post by tinman »

But that at least sounds like it's linked and you're getting an exception/assert/whatever in your code as it runs. What type of debug error are you getting?
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
Lazarus404
User
User
Posts: 74
Joined: Fri Dec 02, 2005 3:11 pm
Location: England
Contact:

Post by Lazarus404 »

I'm not sure. It's one of those Windows debug errors that allow you to traverse the hex values in memory. It's not one I can work out with a "normal" developers eye ;) My guess is, the lib is no longer an acceptable win32 library.

Surely someone has traversed this path before. Aren't there any simple Lib examples for PB?
Laz

Registered PureBasic user since Nov 2005
Check out FlashML at www.designrealm.co.uk... The ultimate Flash Component
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Post by tinman »

I wrote a simple example during the course of this thread, but it really was simple (I can send you the code later, but I forgot my memory stick so I don't have it with me). The code was something like this:

C lib

Code: Select all

struct lib_struct
{
    int type;
    char* f;
};

extern "C" struct lib_struct* getString(char* string)
{
    static struct lib_struct foo;
    foo.f = string;
    foo.type = strlen(string);
    return(&foo);
}

extern "C" char* returnString(struct lib_struct* str)
{
    return(str->f);
}
Compile it as a static library, release mode, making sure it's compiled as __cdecl.
I found that I had to turn off link time optimisation options for the lib to import correctly in PB.

Then I had to edit the library in the hex editor as I described.

PB code

Code: Select all

ImportC "mylib.lib"
    getString.l(string.s)
    returnString.l(struct.l)
EndImport

Structure lib_struct
    type.l
    f.l
EndStructure

*mystruct.lib_struct = getString("foo")
result$ = PeekS(returnString(*mystruct))
Debug result$
And that worked when I ran it. No debug errors. I never checked the value of *mystruct\type though. And of course that code is very simple, there's no calls to any memory allocation/free functionsm, etc.

Also, I downloaded the PellesC compiler. Perharps your problem is that during link the polink.exe cannot find the relevant MSVC runtime .lib file. You should have them somewhere already if you have MSVC but I struggled to figure out how to pass options to the linker. Every time I tried I got an error complaining about my linker options command file.

The other thing to worry about is I don't know how the system determines the version of the MSVC runtime DLL to load. That manifestdependancy linker option looks like it would add something to your application's manifest saying what version of the MSVC runtime it should try to load, as it would get loaded from the side by side DLL cache. If you are trying to link against one version but remove the manifestdependancy line and have a later version of the DLL on the system, what happens then? Is there any more information about what version to use or does it go for the one installed in c:\windows\system32 (i.e. not the versioned side by side DLLs) - which could point to anything.
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
Lazarus404
User
User
Posts: 74
Joined: Fri Dec 02, 2005 3:11 pm
Location: England
Contact:

Post by Lazarus404 »

Thanks for that tinman. I'll have a go and let you know how I get on.
Laz

Registered PureBasic user since Nov 2005
Check out FlashML at www.designrealm.co.uk... The ultimate Flash Component
Lazarus404
User
User
Posts: 74
Joined: Fri Dec 02, 2005 3:11 pm
Location: England
Contact:

Post by Lazarus404 »

Hi guys, tinman,

I've reached another halt in my attempts to create a DLL using a C lib in PB. I've sorted the whole "using a C lib" issue, but I can't find a way around passing structures into or out of ProcedureCDLL's.

Here's what I want...

Code: Select all

ImportC "mylib.lib"
    getString.l(string.s)
    returnString.l(struct.l)
EndImport

Structure lib_struct
    type.l
    f.l
EndStructure

ProcedureCDLL.lib_struct parseString( *foo.lib_struct )
str$ = returnString(*foo)
ProcedureReturn getString(str$)
EndProcedure
Or something to this effect. Obviously, normally, some sort of processing would go on, here. However, any values returned from the DLL need to be understood by the calling application, which is why the returned values need to be structs. I can cope with being able to pass pointers only, as I can always pass the values back into a generic C dll for conversion, but I don't know how to do this, either.

Any help would be great.

Regards,
Laz

Registered PureBasic user since Nov 2005
Check out FlashML at www.designrealm.co.uk... The ultimate Flash Component
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Post by tinman »

You've got two choices. Either return a pointer to a structure, or have the application pass the address of a structure into your procedure and fill it in.

Code: Select all

Structure mystruct
    a.l
    b.l
EndStructure

ProcedureCDLL.l blah(*str.mystruct)
    ProcedureReturn *str
EndProcedure

Define.mystruct a_struct
a_struct\a = 23
a_struct\b = 69

*aaa.mystruct = blah(@a_struct)
Debug Str(*aaa\a)
Debug Str(*aaa\b)
You have to make it a .l for the return type. You can't specify a pointer type as a return.
be structs. I can cope with being able to pass pointers only, as I can always pass the values back into a generic C dll for conversion, but I don't know how to do this, either.
See above - you return a .l but just use it as a pointer to the type in question. If you're calling this DLL from e.g. C then you just define the return type in the header file as a pointer to the type you need e.g.:

Code: Select all

struct mystruct
{
    long a;
    long b;
};

/* Or some variant of this, I can never remeber the ordering of declspecs */
__declspec(dllimport) struct mystruct* __cdecl blah(struct mystruct* str);
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
Lazarus404
User
User
Posts: 74
Joined: Fri Dec 02, 2005 3:11 pm
Location: England
Contact:

Post by Lazarus404 »

Tsk* I can't do it. The language I wish to consume the dll, although capable of handling pointers, can only do so by wrapping the pointer in a struct before handling it. This means I can't wrap it in PB, because PB doesn't like to handle the structs themselves but will the pointer. It's like the chicken and egg issue. :(

As for the example you gave, tinman. Thanks, but unless I can have this

Code: Select all

ProcedureCDLL.l blah(str.mystruct)
    ProcedureReturn str
EndProcedure 
instead of this

Code: Select all

ProcedureCDLL.l blah(*str.mystruct)
    ProcedureReturn *str
EndProcedure 
then it's all for nothing :cry:

Oh well
Laz

Registered PureBasic user since Nov 2005
Check out FlashML at www.designrealm.co.uk... The ultimate Flash Component
Post Reply