Programatically determine shared libraries in use by running application - c++

Is it possible to (and, if so, how does one) determine the shared libraries of an application that are used by an application at runtime? Basically, can I programmatically obtain the the output of ldd? Preferred C/C++ solution does not just jump to execute ldd on the command-line.
Consider the following:
I have a driver application that calls doAction() from a shared library libfoo. I compile the application once and then set LD_LIBRARY_PATH to an appropriate directory containing a libfoo with the doAction() symbol defined. This way, I can have multiple implementations of doAction() in different libfoos but only ever compile an application once.
A real world example would be a professor having a class of students implement doAction(). Instead of compiling a test harness against each student's implementation of doAction(), the students submit a shared library and the professor can simply change LD_LIBRARY_PATH to evaluate each student.
My goal in obtaining the library currently being used is to perform an md5sum on the library at runtime to ensure I'm calling the correct library. In the contrived example, all students would submit the md5sum of their library and the professor could match the running executable + shared library (database lookup, log to file, ...) to the student, to prevent an accident in setting LD_LIBRARY_PATH effecting another student's grade (forgot to change LD_LIBRARY_PATH to David's directory and ran again with Bill's libfoo).

Since it looks like you're using something UNIX-y, just use dlopen instead of dynamically linking your driver app against the missing symbol.
Full sequence is:
iterate over all submitted .so library filenames somehow (maybe you have one directory with studentname.so or something)
load each library
get the entry point function
call it
unload library (optional, I guess)
like so:
void *lib = dlopen(filename, RTLD_LOCAL);
void *libfun = dlsym(lib, "doAction");
if (libfun == NULL)
cout << "student failed by not providing doAction() in " << filename << endl;
else {
void (*doAction)(void) = (void (*)(void)) libfun;
// no, I can't remember the correct syntax for casting to function pointer
cout << "calling " << filename << ":doAction()" << endl;
doAction();
// is there some way to tell if it succeeded?
cout << "unloading " << filename << endl;
dlclose(lib);
}
Notes:
if the interface is the same in each case (ie, void (*)()), you could make this configurable by directory name and symbol name, and it'd work for more than one test
in fact, if the interface is NOT what you expect, the function pointer cast will do horrible things, so careful with this
finally, if the student used C++, their function name symbol will be mangled. Tell them to declare the entry-point as extern "C" void doAction() to avoid that.
the RTLD_LOCAL flag should stop anything in one student's library interfering with another (if you don't unload), but there are other flags it may be sensible to add
specifically, RTLD_NOW will cause dlopen to fail if the student lib has an unresolved external reference it can't figure out (so you can handle it gracefully, by failing them): otherwise your program may just crash when you call doAction.
Although I think the above is better than the solution you're directly asking for help with, I did also find a reference to dl_iterate_phdr while double-checking the docs. If you're on Linux specifically, and if the dl_phdr_info.dlpi_name is actually the filename ... you might be able to get it that way.
I still think it's much uglier, though.

If you're using Linux, you can use the dl_iterate_phdr function:
The dl_iterate_phdr() function allows an application to inquire at run time to find out which shared objects it has loaded.
http://linux.die.net/man/3/dl_iterate_phdr

At runtime, it is not an application, it is a process.
If the process has pid 1234, you can get its memory map by reading /proc/1234/maps (or /proc/1234/smaps which is more detailed). That map lists in particular mmap-ed files (notably shared libraries). From inside the application, read /proc/self/maps
Try
grep so /proc/self/maps
to have an idea of what I mean.
By the way, if you have an address, the dladdr function gives information about the nearest symbol and shared object...
addenda
And as Rob Mayoff answered, dl_iterate_phdr is probably the best solution on Linux

If this is Linux (I doubt there's a generic POSIX way to do this but I could be wrong), you may be interested in the contents of /proc/(pid)/maps. This gives the mapped memory ranges for your process and you could search for which of the ranges your md5sum() function's address falls in.

If you're in linux/unix, you could use strace like strace -o strace.log -f students_binary . Strace traces all system calls, including the calls to open a library. Then you could parse strace.log for all openings of any file and perform the md5sum on all open files.

Related

How to check shared library is loaded successfully or not loaded using dlopen?

Im loading a shared library using dlopen() function in C++ program.
Then how to check it is successfully loaded or not?
or Can we check that loading of library using mangled name of any function present in that library?
From the manual page:
If dlopen() fails for any reason, it returns NULL.
The dlsym function can not handle C++ identifiers, unless they have been declared extern "C", or by you using the mangled name.
If it's not successfully loaded, dlopen() returns NULL.
The man page for dlopen() says:
RETURN VALUE
If file cannot be found, cannot be opened for reading, is not of an appropriate object
format for processing by dlopen(), or if an error occurs during the process of loading
file or relocating its symbolic references, dlopen() shall return NULL.
More detailed diagnostic information shall be available through dlerror() .
According to the documentation (http://linux.die.net/man/3/dlopen), dlopen returns NULL on any failure. So you can just check for that and be done. But if for some reason you don't trust that the library is a "good" one, you could define your own convention for your system. For example, you could require that any library loadable by your system define a symbol with a certain name which has some specific properties, up to and including something like an "API key" that you could assign to users who want to write compatible libraries.
If dlopen encounters an error, it returns NULL and dlerror will return a corresponding error message.
As every one mentioned if dlopen() fails you get a null, but if you trying to solve why you getting mysterious null even though library is present at the path you specified, may sure all libraries are present on the system on which that "particular library" depends, otherwise call would fail with a NULL ;)
Go for using extern "C" for the function in your .cpp file so compiler don't mangle it, and you can call it once library is loaded.
You can also add a static block in one of the files of your shared library. When it is loaded successfully, it will print a message. Example :
struct LoadMessage {
init(void){
std::cout << "I am loaded\n";
}
};
LoadMessage message;

How to compile app in C with module?

I want to do application, which can be compiled with external modules, for example like in php. In php you can load modules in runtime, or compile php with modules together, so modules are available without loading in runtime. But i don't understand how this can be done. If i have module in module.c and there is one function, called say_hello, how can i register it to main application, if you understand what i mean?
/* module.c */
#include <stdio.h>
// here register say_hello function, but how, if i can't in global scope
// call another function?
void say_hello()
{
printf("hello!");
}
If i compile all that files(main app + modules) together, there isn't some reference to say_hello function from main app, because it is called only if user call it in its code. So how can i say to my app, hey, there is say_hello function, if someone want to call it, you know it exists.
EDIT1: I need to have something like table at runtime, where i can see if user called function exists (have C equivavent). Header files doesn't help to me.
EDIT2: My app is interpret for my script langugage.
EDIT3: If someone call function in php, php interpret must know that function exists. I know about dynamic linking and if .so or .dll is loaded, then some start routine is called and you can simple register function in that dll, so php interpret can see, if some module registred for example function called "say_hello". But if i want compile php with for example gd support, then how gd functions are registred to some php function list, hashtable or whatever?
I guess what you are looking for is dynamic libraries (we call runtime loadable modules as dynamic/shared libraries in C and in the OS world, in general). Take, for example, Pidgin which supports plugins to extend it's functionalities. It gives a particular interface to it's plugin-makers to abide by, say functions to register, load, unload and use, which the plugins will have to follow.
When the program loads, it looks for such dynamic libraries in it's plugins directory, if present, it'll load and use it, else it'll skip exposing the functionality. The reason why an interface is needed is that since different modules can have different functionalities which are unknown uptil runtime, an app. has to have a common, agreed-upon way of "talking" to it's plugins/modules.
Every C program can be linked to a static or a dynamic library; static will copy the code from the library to the said program, there by leaving no dependencies for the program to run, while linking to a dynamic library expects the dynamic library to be present when the program is launched. A third way of doing it, is not to link to a DLL, but just asking the OS to perform a load operation of the library. If this succeeds, then the dynamic module is used, else ignored. The functionality which the dynamic library should perform is exposed to the user, only if the load call succeeds.
It is to be noted that this is a operating system provided feature and it has nothing to do with the language used (C or C++ or Python doesn't matter here); as far as C is concered, the compiler still links to known code i.e. code which is available # compile time. This is the reason for different operating system, one needs to write different code to load a dynamic module. Even more, the file type/format of syuch libraries vary from system to system. In Linux it's called shared objects (.so), in Mac it's called dynamic libraries (.dylib) and in Windows as Dynamic link libraries (.dll).
C is not interpreted language. So you need linking, you may want static linking or dynamic linking.
Program building consists of 2 major phases: compiling and linking. During compiling all c-files are translated into machine code, leaving called functions unresolved (obj or o files). Then linker merges all these files into one executable, resolving what was unresolved.
This is static linking. Linked module becomes integral part of executable.
Dynamic linking is platform specific. Under windows these are DLLs. You should issue a system call to load DLL after which you will be able to call functions from it.
What you need is dynamic library. Let's first take a look at the example provided in the Linux manpage of dlopen(3):
/* Load the math library, and print the cosine of 2.0: */
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **argv) {
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen("libm.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any existing error */
/* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
would seem more natural, but the C99 standard leaves
casting from "void *" to a function pointer undefined.
The assignment used below is a workaround. */
*(void **) (&cosine) = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
printf("%f\n", (*cosine)(2.0));
dlclose(handle);
exit(EXIT_SUCCESS);
}
There's also a C++ dlopen mini HOWTO.
For more general information about dynamic loading, start from the wikipedia page first.
I think it is impossible, if i understand what you mean. Because it is compiled language.

How to return the name of a variable stored at a particular memory address in C++

first time posting here after having so many of my Google results come up from this wonderful site.
Basically, I'd like to find the name of the variable stored at a particular memory address. I have a memory editing application I wrote that edits a single value, the problem being that every time the application holding this value is patched, I have to hardcode in the new memory address into my application, and recompile, which takes so much time to upkeep that its almost not worthwhile to do.
What I'd like to do is grab the name of the variable stored at a certain memory address, that way I can then find its address at runtime and use that as the memory address to edit.
This is all being written in C++.
Thanks in advance!
Edit:
Well I've decided I'd like to stream the data from a .txt file, but I'm not sure how to convert the string into an LPVOID for use as the memory address in WriteProcessMemory(). This is what I've tried:
string fileContents;
ifstream memFile("mem_address.txt");
getline(memFile, fileContents);
memFile.close();
LPVOID memAddress = (LPVOID)fileContents.c_str();
//Lots of code..
WriteProcessMemory(WindowsProcessHandle, memAddress, &BytesToBeWrote, sizeof(BytesToBeWrote), &NumBytesWrote);
The code is all correct in terms of syntax, it compiles and runs, but the WriteProcessMemory errors and I can only imagine it has to do with my faulty LPVOID variable. I apologize if extending the use of my question is against the rules, I'll remove my edit if it is.
Compile and generate a so called map file. This can be done easily with Visual-C++ (/MAP linker option). There you'll see the symbols (functions, ...) with their starting address. Using this map file (Caution: has to be updated each time you recompile) you can match the addresses to names.
This is actually not so easy because the addresses are relative to the preferred load address, and probably will (randomization) be different from the actual load address.
Some old hints on retrieving the right address can be found here: http://home.hiwaay.net/~georgech/WhitePapers/MapFiles/MapFiles.htm
In general, the names of variables are not kept around when the program is compiled. If you are in control of the compilation process, you can usually configure the linker and compiler to produce a map-file listing the locations in memory of all global variables. However, if this is the case, you can probably acheive your goals more easily by not using direct memory accesses, but rather creating a proper command protocol that your external program can call into.
If you do not have control of the compilation process of the other program, you're probably out of luck, unless the program shipped with a map file or debugging symbols, either of which can be used to derive the names of variables from their addresses.
Note that for stack variables, deriving their names will require full debugging symbols and is a very non-trivial process. Heap variables have no names, so you will have no luck there, naturally. Further, as mentioned in #jdehaan's answer, map files can be a bit tricky to work with in the best of times. All in all, it's best to have a proper control protocol you can use to avoid any dependence on the contents of the other program's memory at all.
Finally, if you have no control over the other program, then I would recommend putting the variable location into a separate datafile. This way you would no longer need to recompile each time, and could even support multiple versions of the program being poked at. You could also have some kind of auto-update service pulling new versions of this datafile from a server of yours if you like.
Unless you actually own the application in question, there is no standard way to do this. If you do own the application, you can follow #jdehaan answer.
In any case, instead of hardcoding the memory address into your application, why not host a simple feed somewhere that you can update at any time with the memory address you need to change for each version of the target application? This way, instead of recompiling your app every time, you can just update that feed when you need to be able to manipulate a new version.
You cannot directly do this; variable names do not actually exist in the compiled binary. You might be able to do that if the program was written, in say, Java or C#, which do store information about variables in the compiled binary.
Further, this wouldn't in general be possible, because it's always possible that the most up to date copy of a value inside the target program is located inside of a CPU register rather than in memory. This is more likely if the program in question is compiled in release mode, with optimizations turned on.
If you can ensure the target program is compiled in debug mode you should be able to use the debugging symbols emitted by the compiler (the .pdb file) in order to map addresses to variables, but in that case you would need to launch the target process as if it were being debugged -- the plain Read Process Memory and Write Process Memory methods would not work.
Finally, your question ignores a very important consideration -- there need not be a variable corresponding to a particular address even if such information is stored.
If you have the source to the app in question and optimal memory usage is not a concern, then you can declare the interesting variables inside a debugging-friendly structure similar to:
typedef struct {
const char head_tag[15] = "VARIABLE_START";
char var_name[32];
int value;
const char tail_tag[13] = "VARIABLE_END";
} debuggable_int;
Now, your app should be able to search through the memory space for the program and look for the head and tail tags. Once it locates one of your debuggable variables, it can use the var_name and value members to identify and modify it.
If you are going to go to this length, however, you'd probably be better off building with debugging symbols enabled and using a regular debugger.
Billy O'Neal started to head in the right direction, but didn't (IMO) quite get to the real target. Assuming your target is Windows, a much simpler way would be to use the Windows Symbol handler functions, particularly SymFromName, which will let you supply the symbol's name, and it will return (among other things) the address for that symbol.
Of course, to do any of this you will have to run under an account that's allowed to do debugging. At least for global variables, however, you don't necessarily have to stop the target process to find symbols, addresses, etc. In fact, it works just fine for a process to use these on itself, if it so chooses (quite a few of my early experiments getting to know these functions did exactly that). Here's a bit of demo code I wrote years ago that gives at least a general idea (though it's old enough that it uses SymGetSymbolFromName, which is a couple of generations behind SymFromName). Compile it with debugging information and stand back -- it produces quite a lot of output.
#define UNICODE
#define _UNICODE
#define DBGHELP_TRANSLATE_TCHAR
#include <windows.h>
#include <imagehlp.h>
#include <iostream>
#include <ctype.h>
#include <iomanip>
#pragma comment(lib, "dbghelp.lib")
int y;
int junk() {
return 0;
}
struct XXX {
int a;
int b;
} xxx;
BOOL CALLBACK
sym_handler(wchar_t const *name, ULONG_PTR address, ULONG size, void *) {
if (name[0] != L'_')
std::wcout << std::setw(40) << name
<< std::setw(15) << std::hex << address
<< std::setw(10) << std::dec << size << L"\n";
return TRUE;
}
int
main() {
char const *names[] = { "y", "xxx"};
IMAGEHLP_SYMBOL info;
SymInitializeW(GetCurrentProcess(), NULL, TRUE);
SymSetOptions(SYMOPT_UNDNAME);
SymEnumerateSymbolsW(GetCurrentProcess(),
(ULONG64)GetModuleHandle(NULL),
sym_handler,
NULL);
info.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
for (int i=0; i<sizeof(names)/sizeof(names[0]); i++) {
if ( !SymGetSymFromName(GetCurrentProcess(), names[i], &info)) {
std::wcerr << L"Couldn't find symbol 'y'";
return 1;
}
std::wcout << names[i] << L" is at: " << std::hex << info.Address << L"\n";
}
SymCleanup(GetCurrentProcess());
return 0;
}
WinDBG has a particularly useful command
ln
here
Given a memory location, it will give the name of the symbol at that location. With right debug information, it is a debugger's (I mean person doing debugging :)) boon!.
Here is a sample output on my system (XP SP3)
0:000> ln 7c90e514 (7c90e514)
ntdll!KiFastSystemCallRet |
(7c90e520) ntdll!KiIntSystemCall
Exact matches:
ntdll!KiFastSystemCallRet ()

Explicit Loading of DLL

I'm trying to explicitly link with a DLL. No other resources is available except the DLL file itself and some documentation about the classes and its member functions.
From the documentation, each class comes with its own
member typedef
example: typedef std::map<std::string,std::string> Server::KeyValueMap, typedef std::vector<std::string> Server::String Array
member enumeration
example: enum Server::Role {NONE,HIGH,LOW}
member function
example: void Server::connect(const StringArray,const KeyValueMap), void Server::disconnect()
Implementing the codes from google search, i manage to load the dll can call the disconnect function..
dir.h
LPCSTR disconnect = "_Java_mas_com_oa_rollings_as_apiJNI_Server_1disconnect#20";
LPCSTR connect =
"_Java_mas_com_oa_rollings_as_apiJNI_Server_1connect#20";
I got the function name above from depends.exe. Is this what is called decorated/mangled function names in C++?
main.cpp
#include <iostream>
#include <windows.h>
#include <tchar.h>
#include "dir.h"
typedef void (*pdisconnect)();
int main()
{
HMODULE DLL = LoadLibrary(_T("server.dll"));
pdisconnect _pdisconnect;`
if(DLL)
{
std::cout<< "DLL loaded!" << std::endl;
_disconnect = (pdisconnect)GetProcAddress(DLL,disconnect);
if(_disconnect)
{
std::cout << "Successful link to function in DLL!" << std::endl;
}
else
{
std::cout<< "Unable to link to function in DLL!" << std::endl;
}
}
else
{
std::cout<< "DLL failed to load!" << std::endl;
}
FreeLibrary (DLL);
return 0;}
How do i call (for example) the connect member function which has the parameter datatype declared in the dll itself?
Edit
more info:
The DLL comes with an example implementation using Java. The Java example contains a Java wrapper generated using SWIG and a source code.
The documentation lists all the class, their member functions and also their datatypes. According to the doc, the list was generated from the C++ source codes.(??)
No other info was given (no info on what compiler was used to generate the DLL)
My colleague is implementing the interface using Java based on the Java example given, while I was asked to implement using C++. The DLL is from a third party company.
I'll ask them about the compiler. Any other info that i should get from them?
I had a quick read through about JNI but i dont understand how it's implemented in this case.
Update
i'm a little confused... (ok, ok... very confused)
Do i call(GetProcAddress) each public member function separately only when i want to use them?
Do i create a dummy class that imitates the class in the dll. Then inside the class definition, i call the equivalent function from the DLL? (Am i making sense here?) fnieto, is this what you're showing me at the end of your post?
Is it possible to instantiate the whole class from the DLL?
I was trying to use the connect function described in my first post. From the Depends.exe DLL output,
std::map // KeyValueMap has the following member functions: del, empty, get, has_1key,set
std::vector // StringArray has the following member functions: add, capacity, clear, get, isEMPTY, reserve, set, size
which is different from the member functions of map and vector in my compiler (VS 2005)...
Any idea? or am i getting the wrong picture here...
Unless you use a disassembler and try to figure out the paramater types from assemly code, you can't. These kind of information is not stored in the DLL but in a header file coming with the DLL. If you don't have it, the DLL is propably not meant to be used by you.
I would be very careful if I were you: the STL library was not designed to be used across compilation boundaries like that.
Not that it cannot be done, but you need to know what you are getting into.
This means that using STL classes across DLL boundaries can safely work only if you compile your EXE with the same exact compiler and version, and the same settings (especially DEBUG vs. RELEASE) as the original DLL. And I do mean "exact" match.
The C++ standard STL library is a specification of behavior, not implementation. Different compilers and even different revisions of the same compiler can, and will, differ on the code and data implementations. When your library returns you an std::map, it's giving you back the bits that work with the DLL's version of the STL, not necessarily the STL code compiled in your EXE.
(and I'm not even touching on the fact that name mangling can also differ from compiler to compiler)
Without more details on your circumstances, I can't be sure; but this can be a can of worms.
In order to link with a DLL, you need:
an import library (.LIB file), this describes the relation between C/C++ names and DLL exports.
the C/C++ signatures of the exported items (usually functions), describing the calling convention, arguments and return value. This usually comes in a header file (.H).
From your question it looks like you can guess the signatures (#2), but you really need the LIB file (#1).
The linker can help you generate a LIB from a DLL using an intermediate DEF.
Refer to this question for more details: How to generate an import library from a DLL?
Then you need to pass the .lib as an "additional library" to the linker. The DLL must be available on the PATH or in the target folder.

Compiling a DLL with gcc

Sooooo I'm writing a script interpreter. And basically, I want some classes and functions stored in a DLL, but I want the DLL to look for functions within the programs that are linking to it, like,
program dll
----------------------------------------------------
send code to dll-----> parse code
|
v
code contains a function,
that isn't contained in the DLL
|
list of functions in <------/
program
|
v
corresponding function,
user-defined in the
program--process the
passed argument here
|
\--------------> return value sent back
to the parsing function
I was wondering basically, how do I compile a DLL with gcc? Well, I'm using a windows port of gcc. Once I compile a .dll containing my classes and functions, how do I link to it with my program? How do I use the classes and functions in the DLL? Can the DLL call functions from the program linking to it? If I make a class { ... } object; in the DLL, then when the DLL is loaded by the program, will object be available to the program? Thanks in advance, I really need to know how to work with DLLs in C++ before I can continue with this project.
"Can you add more detail as to why you want the DLL to call functions in the main program?"
I thought the diagram sort of explained it... the program using the DLL passes a piece of code to the DLL, which parses the code, and if function calls are found in said code then corresponding functions within the DLL are called... for example, if I passed "a = sqrt(100)" then the DLL parser function would find the function call to sqrt(), and within the DLL would be a corresponding sqrt() function which would calculate the square root of the argument passed to it, and then it would take the return value from that function and put it into variable a... just like any other program, but if a corresponding handler for the sqrt() function isn't found within the DLL (there would be a list of natively supported functions) then it would call a similar function which would reside within the program using the DLL to see if there are any user-defined functions by that name.
So, say you loaded the DLL into the program giving your program the ability to interpret scripts of this particular language, the program could call the DLLs to process single lines of code or hand it filenames of scripts to process... but if you want to add a command into the script which suits the purpose of your program, you could say set a boolean value in the DLL telling it that you are adding functions to its language and then create a function in your code which would list the functions you are adding (the DLL would call it with the name of the function it wants, if that function is a user-defined one contained within your code, the function would call the corresponding function with the argument passed to it by the DLL, the return the return value of the user-defined function back to the DLL, and if it didn't exist, it would return an error code or NULL or something). I'm starting to see that I'll have to find another way around this to make the function calls go one way only
This link explains how to do it in a basic way.
In a big picture view, when you make a dll, you are making a library which is loaded at runtime. It contains a number of symbols which are exported. These symbols are typically references to methods or functions, plus compiler/linker goo.
When you normally build a static library, there is a minimum of goo and the linker pulls in the code it needs and repackages it for you in your executable.
In a dll, you actually get two end products (three really- just wait): a dll and a stub library. The stub is a static library that looks exactly like your regular static library, except that instead of executing your code, each stub is typically a jump instruction to a common routine. The common routine loads your dll, gets the address of the routine that you want to call, then patches up the original jump instruction to go there so when you call it again, you end up in your dll.
The third end product is usually a header file that tells you all about the data types in your library.
So your steps are: create your headers and code, build a dll, build a stub library from the headers/code/some list of exported functions. End code will link to the stub library which will load up the dll and fix up the jump table.
Compiler/linker goo includes things like making sure the runtime libraries are where they're needed, making sure that static constructors are executed, making sure that static destructors are registered for later execution, etc, etc, etc.
Now as to your main problem: how do I write extensible code in a dll? There are a number of possible ways - a typical way is to define a pure abstract class (aka interface) that defines a behavior and either pass that in to a processing routine or to create a routine for registering interfaces to do work, then the processing routine asks the registrar for an object to handle a piece of work for it.
On the detail of what you plan to solve, perhaps you should look at an extendible parser like lua instead of building your own.
To your more specific focus.
A DLL is (typically?) meant to be complete in and of itself, or explicitly know what other libraries to use to complete itself.
What I mean by that is, you cannot have a method implicitly provided by the calling application to complete the DLLs functionality.
You could however make part of your API the provision of methods from a calling app, thus making the DLL fully contained and the passing of knowledge explicit.
How do I use the classes and functions in the DLL?
Include the headers in your code, when the module (exe or another dll) is linked the dlls are checked for completness.
Can the DLL call functions from the program linking to it?
Yes, but it has to be told about them at run time.
If I make a class { ... } object; in the DLL, then when the DLL is loaded by the program, will object be available to the program?
Yes it will be available, however there are some restrictions you need to be aware about. Such as in the area of memory management it is important to either:
Link all modules sharing memory with the same memory management dll (typically c runtime)
Ensure that the memory is allocated and dealloccated only in the same module.
allocate on the stack
Examples!
Here is a basic idea of passing functions to the dll, however in your case may not be most helpfull as you need to know up front what other functions you want provided.
// parser.h
struct functions {
void *fred (int );
};
parse( string, functions );
// program.cpp
parse( "a = sqrt(); fred(a);", functions );
What you need is a way of registering functions(and their details with the dll.)
The bigger problem here is the details bit. But skipping over that you might do something like wxWidgets does with class registration. When method_fred is contructed by your app it will call the constructor and register with the dll through usage off methodInfo. Parser can lookup methodInfo for methods available.
// parser.h
class method_base { };
class methodInfo {
static void register(factory);
static map<string,factory> m_methods;
}
// program.cpp
class method_fred : public method_base {
static method* factory(string args);
static methodInfo _methoinfo;
}
methodInfo method_fred::_methoinfo("fred",method_fred::factory);
This sounds like a job for data structures.
Create a struct containing your keywords and the function associated with each one.
struct keyword {
const char *keyword;
int (*f)(int arg);
};
struct keyword keywords[max_keywords] = {
"db_connect", &db_connect,
}
Then write a function in your DLL that you pass the address of this array to:
plugin_register(keywords);
Then inside the DLL it can do:
keywords[0].f = &plugin_db_connect;
With this method, the code to handle script keywords remains in the main program while the DLL manipulates the data structures to get its own functions called.
Taking it to C++, make the struct a class instead that contains a std::vector or std::map or whatever of keywords and some functions to manipulate them.
Winrawr, before you go on, read this first:
Any improvements on the GCC/Windows DLLs/C++ STL front?
Basically, you may run into problems when passing STL strings around your DLLs, and you may also have trouble with exceptions flying across DLL boundaries, although it's not something I have experienced (yet).
You could always load the dll at runtime with load library