How do I call C++ functions from a Lua script? - c++

I'm using Visual Studio 2005.
------------------------[ luapassing.cpp ]--------------------
#include "lua.h"
static int myCfunc (Lua_State *L){
double trouble = lua_tonumber(L,1);
lua_pushnumber(L,16.0 -trouble);
return 1;
}
int luaopen_luapassing (Lua_State *L){
static const lua_reg Map [] = {{"dothis",myCfunc},{NULL,NULL}};
luaL_register(L,"cstuff",Map);
return;
}
-------------------------[ csample.lua ]-------------------------
package.cpath = "./CLua2.dll"
require "luapassing"
print("hola")
print(seth.doThis(120))

I see several issues. I'll describe them, and provide a code fragment that should work as I believe you intended this sample to work.
Your first problem is that the C++ compiler mangled the name of the only function exported from your DLL whose name matters to Lua: luaopen_luapassing(). The stock binary distribution for Windows was compiled as a C program, and assumes a C style name for the DLL module entry point.
Also, you have the protocol for the luaopen_x function slightly wrong. The function returns an integer which tells Lua how many items on the top of Lua's stack are return values for use by Lua. The protocol assumed by require would prefer that you leave the new module's table object on the top of the stack and return it to Lua. To do this, the luaopen_x function would ordinarily use luaL_register() as you did, then return 1.
There is also the issue of naming. Modules written in pure Lua have the opportunity to be less aware of their names. But modules written in C have to export a function from the DLL that includes the module name in its name. They also have to provide that module name to luaL_register() so that the right table is created and updated in the global environment. Finally, the client Lua script will see the loaded module in a global table named like the name passed to require, which is also returned from require so that it may be cached in a local in that script.
A couple of other nits with the C code are that the numeric type really should be spelled lua_Number for portability, and that it would be conventional to use luaL_checknumber() rather than lua_tonumber() to enforce the required argument to the function. Personally, I would name the C implementation of a public function with a name related to its name that will be known publicly by Lua, but that is just a matter of taste.
This version of the C side should fix these issues:
#include "lua.h"
static int my_dothis (Lua_State *L){
lua_Number trouble = luaL_checknumber(L,1);
lua_pushnumber(L,16.0 -trouble);
return 1;
}
extern "C" int luaopen_luapassing (Lua_State *L){
static const lua_reg Map [] = {
{"dothis", my_dothis},
{NULL,NULL}
};
luaL_register(L,"luapassing",Map);
return 1;
}
The sample script then needs to refer to the loaded module by its proper name, and to the functions defined by that module by their proper names. Lua is case sensitive, so if the module creates a function named dothis(), then the script must use that same name, and cannot find it named doThis(), for example.
require "luapassing"
print("hola")
print(luapassing.dothis(120))
I should add that I haven't actually compiled and run the above, so there might be a typo or two left as an exercise ;-)

If you're going to be doing a lot of C++ to lua binding, you might want to take a look at luabind.

If you are compiling as C++ and want to match a 'C' interface, you should declare the externally visible functions as extern "C" to avoid name mangling.

Related

Calling static C functions externally

This might seem like an odd question, but I was wondering if it were possible with any sort of hack to call static functions from another file without explicitly using extern or anything like that. Perhaps by calling the memory address of the function directly or something.
Basically what I want to do is create a test framework which can call into any function by specifying the function, file and function parameters.
So something like this structure:
component/
component.c
static int foo(int a){return a/2;}
int bar(){ return 4;}
unit_tests/
main.c
int val = component.c::foo(4) * bar();
Even better would be if I could do this at runtime by injecting into the memory address of the function or something. I'm not entirely sure about if this would be executable on linux though, or if I'd hit security issues.
Perhaps something similar to this, and have a block of code in my component process to interpret runtime calls and translate to the correct function address: Calling a function through its address in memory in c / c++
You can use function pointers to static functions.
For test frameworks, note that some existing test frameworks in C use the trick to force you to use STATIC instead of the static specifier and STATIC is a macro defined (by the framework) to either nothing or static if you are in test mode or not to specify the correct linkage.

exporting C++ dll to Delphi program

I have a dll with exporting function
extern "C" __declspec(dllexport) IDriver * __stdcall GetDriver()
There is a programm which is written on Delphi. It can't see the function GetDriver().
It's double awful because I can not get and modify sources of this program.
What may be the reason of successful loading my dll (according log file) and failed call exporting function? Thank you.
Window 7 x64, Visual Studio 2010, C++ project for x86 target
The most likely explanation is that the function will have been exported with a decorated name. I'd expect it to have been exported with the name GetDriver#0. So you could import it like this:
function GetDriver: IDriver; stdcall; external 'DllName.dll' name 'GetDriver#0';
Use a tool like Dependency Walker to check the exact name used to export the function.
If you cannot modify the Delphi code, then you'll need to make your C++ DLL match. Do that by using a .def file which allows you control over the exported name.
The other problem you will face is that Delphi's ABI for return values differs from that used by most other tools on the Windows platform. Specifically a return value is semantically a var parameter. On the other hand, your C++ compiler will regard the return value as an out parameter. My question on Delphi WideString return values covers exactly this issue.
Because of this, I'd expect the function declaration above to lead to access violations. Instead you should declare the return value to be a Pointer and cast it to an interface reference in your Delphi code. You'll need to double check and make sure that the reference counting is handled appropriately.
Again, if you cannot modify the Delphi code, you need to make the C++ code match. A Delphi interface return value is implemented as an additional var parameter following the other parameters. So, to make your C++ function match, declare it like this:
void __stdcall GetDriver(IDriver* &retVal);

How to call a C++ function that takes a reference from C# code

HI,
I have a C++ function like the following:
int ShowJob(const JobData& data);
How does this translate to a DLLImport statement which I can use to call the function from C#?
I'd guess it behaves like a pointer under the hood, so treat it as such. Ironically, this is done by declaring it as a reference parameter.
[DLLImport(DLLName)]
public static extern int ShowJob(ref JobData data);
This could only work if JobData is a structure. You're dead in the water if it is a class, you cannot create a C++ class instance in C#. You don't have access to the constructor and destructor.
The "const" keyword is an attribute checked by the C++ compiler, it has no relevance to C# code. A C++ reference is a pointer under the hood, you'll get one by declaring the argument with "ref". You're likely to have a problem getting the "ShowJob" export name right, it is normally decorated by the C++ compiler. You'd suppress that decoration by prefixing the function with extern "C" in the C++ code. If you cannot change the C++ code then you can find the exported name by running Dumpbin.exe /exports on the DLL.
Putting this all together, the declarations ought to resemble something like this:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct JobData {
// members...
}
[DllImport("something.dll", EntryPoint = "?ShowJob##YAHABUJobData###Z", CallingConvention = CallingConvention.Cdecl)]
private static extern int ShowJob(ref JobData data);
Lot's of guess work going on here, you'll need to verify this with your actual C++ code. If the JobData argument is in fact a class then you'll need to write a ref class wrapper in the C++/CLI language.

How do interpreters written in C and C++ bind identifiers to C(++) functions

I'm talking about C and/or C++ here as this are the only languages I know used for interpreters where the following could be a problem:
If we have an interpreted language X how can a library written for it add functions to the language which can then be called from within programs written in the language?
PHP example:
substr( $str, 5, 10 );
How is the function substr added to the "function pool" of PHP so it can be called from within scripts?
It is easy for PHP storing all registered function names in an array and searching through it as a function is called in a script. However, as there obviously is no eval in C(++), how can the function then be called? I assume PHP doesn't have 100MB of code like:
if( identifier == "substr" )
{
return PHP_SUBSTR(...);
} else if( ... ) {
...
}
Ha ha, that would be pretty funny. I hope you have understood my question so far.
How do interpreters written in C/C++ solve this problem?
How can I solve this for my own experimental toy interpreter written in C++?
Actually scripting languages do something like what you mentioned.
They wrap functions and they register that functions to the interpreter engine.
Lua sample:
static int io_read (lua_State *L) {
return g_read(L, getiofile(L, IO_INPUT), 1);
}
static int f_read (lua_State *L) {
return g_read(L, tofile(L), 2);
}
...
static const luaL_Reg flib[] = {
{"close", io_close},
{"flush", f_flush},
{"lines", f_lines},
{"read", f_read},
{"seek", f_seek},
{"setvbuf", f_setvbuf},
{"write", f_write},
{"__gc", io_gc},
{"__tostring", io_tostring},
{NULL, NULL}
};
...
luaL_register(L, NULL, flib); /* file methods */
Interpreters probably just keep a hashmap of function names to the function definition (which will include parameter information, return type, function location/definition etc.) That way, you can just do a search on the hashmap for a function name (when your interpreter encounters one). If it exists, use the function info in the hashtable to evaluate it.
You obviously need to add provisions for different levels of scope, etc. but that's the gist of it.
Pretty much all compilers have a "symbol table" that they use to look up what an identifier represents. The symbol table will hold function name, variable names, type names, etc... Anything that has a name goes in a symbol table, which is basically a map of names to everything the compiler knows about that name (I'm simplifying here). Then when the compiler encounters an identifier, it look it up in the symbol table, and finds out that it's a function. If you're using an interpreter, then the symbol table will have information on where to find the function and continue interpretation. If this is a compiler, the symbol table will have an address of where that function will be in the compiled code (or a placeholder to fill in the address later). Assembly can then be produced that essentially says: put the arguments on the stack, and resume execution at some address.
So, for you're example an interpreter would look at
substr( $str, 5, 10 );
and find "substr" in it's symbol table:
symbolTableEntry entry = symbolTable["substr"];
from there, it will gather up $str, 5 and 10 as arguments, and look at entry to see that the arguments are valid for the function. Then it will look in entry to find out where to jump to with the marshalled arguments.
In C++ you'd probably use a similar mechanism as Nick D did, but taking advantage of its OO capabilities:
typedef luaFunction boost::function<void(*)(lua_State&)>
std::map<std::string, luaFunction > symbolTable;
symbolTable["read"] = f_read;
symbolTable["close"] = f_close; // etc.
// ...
luaFunction& f = symbolTable[*symbolIterator++];
f(currentLuaState);

Can't use DLL (written in C++) in Delphi: The procedure entry point could not be located

I've compiled a DLL in Visual Studio (the source code is in C++, which I barely understand). Here's a piece of Scraper.h:
struct SWin
{
char title[512];
HWND hwnd;
};
SCRAPER_API bool ScraperGetWinList(SWin winList[100]);
Now I'm trying to use the above function in my Delphi application:
type
tWin = record
title: String;
hwnd: HWND;
end;
function ScraperGetWinList(var WinList: Array of tWin): Boolean; external 'Scraper.dll';
var
myWinList: Array [1..100] of tWin;
procedure TMainForm.GetWinListButtonClick(Sender: TObject);
begin
ScraperGetWinList(myWinList);
...
The project doesn't compile, and I get the following message: The procedure entry point ScraperGetWinList could not be located in the dynamic link library: Scraper.dll.
What am I doing wrong?
From my Linux experience, I'd say that you've encountered so-called "name-mangling" issue. The entry point of your procedure is not called "ScraperGetWinList", but something like "_ZN18ScraperGetWinListEpN4SWin".
The thing is that, Unlike in C, in C++ language the name of entry point is not the same as the function name. No wonder: assume, you have a set of overloaded functions; they should have different entry points in your DLL. That's where name mangling comes into play.
The most common solution to this problem is to define interface of your library in such a way that it will use C calling convention. No name mangling will happen with the interface functions then.
Note that you don't have to write the whole library in C, you only should declare functions for them to emit C-like entry points.
Usually it's written like this:
extern "C" {
SCRAPER_API bool ScraperGetWinList(SWin winList[100]);
// More functions
}
Recompile your library and use it in Delphi without problems.
Note, that you should also adjust calling conventions (stdcall or cdecl) for them to match in your C++ header and Delphi code. However, that's best explained in another question.
Name mangling is most likely the problem. Name mangling is usually done is C++ code,
and when writing a DLL in C++ that should be used by code in an other langauge,
you should use the Extern "C" construction as Pavel Shved already suggested.
When using DLLs, especially when writtin in other languages, you should also keep
an eye on calling conventions. I suggest that you specify in both delphi and c++ to use the stdcall calling convenstion. This is the calling convention also used by the windows api, so it guarantees the best interoperatability between different compilers.
This would mean
extern "C" {
SCRAPER_API __stdcall bool ScraperGetWinList(SWin winList[100]);
}
and
function ScraperGetWinList(var WinList: Array of tWin): Boolean; external 'Scraper.dll';
But that's not all, the stdcall calling convention has an impact on the name mangling, and it would turn out to be something like _ScraperGetWinList#4 (Where 4 is the size of the parameter, where an array would have a pointer to the first element, so 4 bytes)
To confirm the correct symbols to use, I suggest Dependency Walker
( http://www.dependencywalker.com/ ) this program shows that exactly the function names are exported by the dll. Having confirmed the name to be '_ScraperGetWinList#4' then you add this in delpgi like this:
function ScraperGetWinList(var WinList: Array of tWin): Boolean; external 'Scraper.dll' name '_ScraperGetWinList#4';
Have you actually exported the entry point function in the c++ code? This really stumped me the first time I compiled a C++ dll in Visual Studio for use in a dotnet app.
For example, I needed to expose a print driver in unmanaged code so some other developers could access it in VB.net. This is what I did.
In foo.cpp:
extern "c" {
___declspec(dllexport) bool FooBar()
{
// Call some code on my cpp objects to implement foobar
}
}
Then in a file called foo.def:
LIBRARY "mylib"
EXPORTS
FooBar
AnyOtherFunctionsItExports
This is how I got it to work. I might not be doing things the best possiable way. I am a little light on C++ experience and also mainly don't work on windows.