[Solved] LCB Error in file ... unable to load foreign library

LiveCode Builder is a language for extending LiveCode's capabilities, creating new object types as Widgets, and libraries that access lower-level APIs in OSes, applications, and DLLs.

Moderators: LCMark, LCfraser

Post Reply
Cairoo
Posts: 107
Joined: Wed Dec 05, 2012 5:54 pm

[Solved] LCB Error in file ... unable to load foreign library

Post by Cairoo » Tue Feb 08, 2022 10:30 am

Dear LiveCoders,

I've been trying to call a foreign function in a 64-bit .dll library I wrote in c++ on Windows, and I keep getting the following error:

Code: Select all

LCB Error in file <folder with my lcb file>/cairoomdbodbc.lcb at line 13: unable to load foreign library
Hint: runtime
I placed the .dll file in the following directory:

Code: Select all

<folder with my lcb file>/code/x86-win32
I'm suspecting the LiveCode engine can't find my .dll file. Are there other possible reasons for the error?

I'm not a seasoned c++ developer, so I'm hoping someone here *is* and may shed some light on this.

Here's the source code of my LCB library:

cairoomdbodbc.lcb

Code: Select all

library co.za.cairoo.cairoomdbodbc

metadata title is "CAIROO MDB ODBC Data Source Library"
metadata author is "Gerrie van Tonder"
metadata version is "1.0.0"
metadata os is "windows"

use com.livecode.foreign

private foreign handler _createCairooOdbcDataSource ( in pDbFilePath as ZStringNative ) returns ZStringNative binds to "c:cairoomdbodbc>createCairooOdbcDataSource"

public unsafe handler createCairooOdbcDataSource ( in pDbFilePath as String ) returns String
   return _createCairooOdbcDataSource ( pDbFilePath )
end handler

end library
And here's the source code of my .dll file:

cairoomdbodbc.h

Code: Select all

_declspec(dllexport) const char * __cdecl createCairooOdbcDataSource(char *DbFilePath);
cairoomdbodbc.cpp

Code: Select all

#include <windows.h>
#include <odbcinst.h>
#include "cairoomdbodbc.h"

const char * createCairooOdbcDataSource(char *DbFilePath)
{
	...redacted...

	BOOL theResult = ...redacted...

	...redacted...

	if (theResult == 1)
	{
		return "true";
	}
	else
	{
		return "false";
	}
}
Last edited by Cairoo on Wed Feb 09, 2022 9:03 am, edited 1 time in total.

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 1206
Joined: Thu Apr 11, 2013 11:27 am

Re: LCB Error in file ... unable to load foreign library

Post by LCMark » Tue Feb 08, 2022 11:03 am

@Carioo: The code folder for 64-bit windows inside extensions is `x86_64-win32` not `x86-win32` that's most likely the issue :)

(Obvious things to also check - you are running the 64-bit Windows version of LiveCode, and you are compiling your DLL for 64-bit, and not 32-bit).

Cairoo
Posts: 107
Joined: Wed Dec 05, 2012 5:54 pm

Re: LCB Error in file ... unable to load foreign library

Post by Cairoo » Tue Feb 08, 2022 11:34 am

LCMark wrote:
Tue Feb 08, 2022 11:03 am
@Carioo: The code folder for 64-bit windows inside extensions is `x86_64-win32` not `x86-win32` that's most likely the issue :)
Thank you, Mark, that was indeed the issue. I changed the name of the folder to `x86_64-win32` and it doesn't throw the error anymore.
LCMark wrote:
Tue Feb 08, 2022 11:03 am
(Obvious things to also check - you are running the 64-bit Windows version of LiveCode, and you are compiling your DLL for 64-bit, and not 32-bit).
Yes, I'm running the 64-bit Windows version of LiveCode, and I'm compiling my DLL for 64-bit.

But now it throws a new error:

Code: Select all

LCB Error in file <folder containing my lcb file>/cairoomdbodbc.lcb at line 13: Unable to bind foreign handler co.za.cairoo.cairoomdbodbc._createCairooOdbcDataSource
Hint: runtime
I suppose I'm not correctly defining the foreign handler. Any suggestions?

LCMark
Livecode Staff Member
Livecode Staff Member
Posts: 1206
Joined: Thu Apr 11, 2013 11:27 am

Re: LCB Error in file ... unable to load foreign library

Post by LCMark » Tue Feb 08, 2022 2:04 pm

@Carioo: Your foreign handler declaration looks fine - the issue is that your foreign function:

Code: Select all

_declspec(dllexport) const char * __cdecl createCairooOdbcDataSource(char *DbFilePath);
Will be compiled by the C++ compiler using C++ name mangling (i.e. the name will be munged to include the types of its arguments). The easiest way to fix this is to declare the function `extern "C"`:

Code: Select all

extern "C" _declspec(dllexport) const char * __cdecl createCairooOdbcDataSource(char *DbFilePath);
This causes the name to be precisely as expected (createCairooOdbcDataSource).

Cairoo
Posts: 107
Joined: Wed Dec 05, 2012 5:54 pm

Re: LCB Error in file ... unable to load foreign library

Post by Cairoo » Wed Feb 09, 2022 9:01 am

Thank you, Mark! :D

I modified the C++ code as you suggested and the LCB extension was able to call the function. However, I also had to change the return type in my DLL because using "const char *" as a return type crashed the LiveCode engine. After changing the return type to bool and mapping it to CBool in the LCB file, it worked perfectly.

So just for everyone reading this topic, this is the code that worked:

cairoomdbodbc.h

Code: Select all

extern "C" _declspec(dllexport) BOOL __cdecl createCairooOdbcDataSource(char *DbFilePath);
cairoomdbodbc.cpp

Code: Select all

#include <windows.h>
#include <odbcinst.h>
#include "cairoomdbodbc.h"

extern "C" _declspec(dllexport) BOOL __cdecl createCairooOdbcDataSource(char *DbFilePath)
{
	...redacted...

	BOOL theResult = ...redacted...

	...redacted...
	
	return theResult;
}
cairoomdbodbc.lcb

Code: Select all

library co.za.cairoo.cairoomdbodbc

metadata title is "CAIROO MDB ODBC Data Source Library"
metadata author is "Gerrie van Tonder"
metadata version is "1.0.0"
metadata os is "windows"

use com.livecode.foreign

private foreign handler _createCairooOdbcDataSource ( in pDbFilePath as ZStringNative ) returns CBool binds to "c:cairoomdbodbc>createCairooOdbcDataSource"

public unsafe handler createCairooOdbcDataSource ( in pDbFilePath as String ) returns String
   variable tResult as Boolean
   put _createCairooOdbcDataSource ( pDbFilePath ) into tResult
   if tResult is true then
      return "true"
   else
      return "false"
   end if
   return tResult
end handler

end library

Post Reply

Return to “LiveCode Builder”