2009-02-03 125 views
10

Sooooo我正在编写脚本解释器。基本上,我想存储在一个DLL一些类和函数,但我想的DLL来寻找那些被链接到它,就像节目中的函数,使用gcc编译DLL

 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 

基本上,我是想知道,我怎么编译一个使用gcc的DLL?那么,我正在使用gcc的windows端口。一旦我编译了一个包含我的类和函数的.dll,我该如何链接到我的程序?我如何使用DLL中的类和函数? DLL可以调用链接到它的程序的函数吗?如果我创建一个类{...}对象;在DLL中,然后当程序加载DLL时,程序是否可以使用对象?在此之前感谢,我真的需要知道如何在C++中使用DLL,然后才能继续此项目。

“你可以添加更多的细节,你为什么要DLL调用主程序中的函数吗?”

我以为这个图解释了它......使用DLL的程序将一段代码传递给解析代码的DLL,并且如果在所述代码中找到函数调用,那么DLL中的相应函数是调用...例如,如果我传递“a = sqrt(100)”,那么DLL解析器函数将查找对sqrt()的函数调用,并且在该DLL内将会有一个相应的sqrt()函数,传递给它的参数的根,然后它将从该函数获取返回值并将其放入变量a中,就像其他程序一样,但是如果没有在sqrt()函数中找到相应的处理函数该DLL(将有一个本地支持的函数列表),那么它会调用一个类似的函数,它将驻留在使用该DLL的程序中,以查看是否有该名称的用户定义函数。

因此,假设您将DLL加载到程序中,让您的程序能够解释此特定语言的脚本,程序可以调用DLL来处理单行代码或将脚本的文件名处理为...但是如果你想添加一个命令到适合程序目的的脚本中,你可以说在DLL中设置一个布尔值,告诉它你正在为它的语言添加函数,然后在你的代码中创建一个函数,你要添加的函数(DLL会用它想要的函数的名字来调用它,如果这个函数是你的代码中包含的用户定义的函数的话,函数会调用相应的函数,并使用由DLL传递给它的参数,将用户定义函数的返回值返回给DLL,如果它不存在,它将返回错误代码或NULL或s omething)。我开始看到,我必须找到解决这个另一种方式让函数调用走一条路只有

+0

哇,我甚至不知道有一个海湾合作委员会的胜利端口。我会尝试使用gcc与windows作为平台目标。 – cbrulak 2009-02-03 00:22:03

+0

你应该指定你正在使用的确切编译器。该编译器的文档可能会告诉你如何制作DLL。 – SoapBox 2009-02-03 00:23:01

+0

它被称为mingw或mingw32我猜...我会尝试找到gcc文档,但我对C和C++相当陌生,所以它的某些方面仍然很难理解 – user61721 2009-02-03 00:35:36

回答

8

This link解释如何做到这一点在一个基本的方式。

在大图中,当你制作一个dll时,你正在制作一个在运行时加载的库。它包含一些导出的符号。这些符号通常是对方法或函数的引用,加上编译器/链接器goo。

当你通常建立一个静态库时,至少有一个粘性链接器,链接器将它需要的代码拉入并在你的可执行文件中重新包装它。

在一个dll中,实际上你会得到两个最终产品(三个真的只是等待):一个dll和一个存根库。该存根是一个静态库,看起来完全像常规静态库,不同之处在于不是执行代码,而是每个存根通常是对常规例程的跳转指令。常见的例程加载你的dll,获取你想调用的例程的地址,然后修补原始跳转指令到那里,所以当你再次调用它时,你最终会进入你的dll。

第三个最终产品通常是一个头文件,告诉你所有关于库中数据类型的信息。

所以你的步骤是:创建你的头和代码,建立一个DLL,从头/代码/一些导出函数列表建立一个存根库。结束代码将链接到存根库,它将加载dll并修复跳转表。

编译器/连接咕包括像确保运行时库需要它们的地方,确保静态构造函数执行,确保静态析构函数注册了以后执行,等,等,等

现在就你的主要问题:如何在dll中编写可扩展代码?有许多可能的方法 - 一种典型的方法是定义一个纯粹的抽象类(aka接口),它定义了一个行为并将其传递给一个处理例程或创建一个例程来注册接口来完成工作,然后处理常规要求注册服务机构处理一件工作。

2

关于你计划解决的细节,也许你应该看看像lua这样的可扩展解析器,而不是构建自己的解析器。

给你更具体的焦点。
一个DLL(通常是?)本身就是完整的,或者明确知道要使用其他库来完成自己。

我的意思是说,你不能让调用应用程序隐式提供一个方法来完成DLL功能。

然而,您可以使API的一部分从调用应用程序中提供方法,从而使DLL完全包含并显式传递知识。

如何在DLL中使用类和函数?
在链接模块(exe或其他dll)时,在代码中包含标题,检查dll的完整性。

DLL可以调用链接到它的程序的函数吗?
是的,但必须在运行时告诉他们。

如果我创建一个类{...}对象;在DLL中,然后当程序加载DLL时,程序是否可以使用对象?
是的,它将可用,但有一些限制,你需要注意。如在存储器管理领域,重要的是无论是:

  • 链接所有的模块具有相同的存储器管理DLL(通常是c运行时)
  • 确保内存分配,只在dealloccated共享存储器相同的模块。
  • 分配在堆栈上

例子!
下面是将函数传递给dll的一个基本思想,然而在你的情况下可能不是最有用的,因为你需要知道你想要提供的其他函数。

// parser.h 
struct functions { 
    void *fred (int); 
}; 

parse(string, functions); 

// program.cpp 
parse("a = sqrt(); fred(a);", functions); 

你需要的是注册函数的方法(和它们的细节与DLL) 这里的更大的问题是细节位。但跳过你可能会做类似wxWidgets的类注册。当method_fred被你的应用程序构造时,它将调用构造函数并通过用法off methodInfo注册到dll。解析器可以查找methodInfo的可用方法。

// 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); 
0

这听起来像是一个数据结构的工作。

创建一个包含关键字和与每个关联的函数的结构体。

struct keyword { 
    const char *keyword; 
    int (*f)(int arg); 
}; 

struct keyword keywords[max_keywords] = { 
    "db_connect", &db_connect, 
} 

然后写在你的DLL中的函数,你通过这个数组的地址:

plugin_register(keywords); 

然后DLL里面可以做:

keywords[0].f = &plugin_db_connect; 

使用这种方法,处理脚本关键字的代码保留在主程序中,而DLL操作数据结构以获取其自己的函数。

把它带到C++,使结构变成一个类,而不是包含一个std :: vector或std :: map或任何关键字和一些函数来操纵它们。