简体   繁体   English

在C / C ++中编译DLL,然后从另一个程序调用它

[英]Compile a DLL in C/C++, then call it from another program

I want to make a simple, simple DLL which exports one or two functions, then try to call it from another program... Everywhere I've looked so far, is for complicated matters, different ways of linking things together, weird problems that I haven't even begun to realize exist yet... I just want to get started, by doing something like so: 我想制作一个简单的,简单的DLL,该DLL导出一个或两个函数,然后尝试从另一个程序中调用它...到目前为止,我到过的所有地方都涉及复杂的问题,将事物链接在一起的不同方法,奇怪的问题我什至还没有开始意识到存在……我只是想开始做某事,就像这样:

Make a DLL which exports some functions, like, 创建一个可以导出某些功能的DLL,例如,

int add2(int num){
   return num + 2;
}

int mult(int num1, int num2){
   int product;
   product = num1 * num2;
   return product;
}

I'm compiling with MinGW, I'd like to do this in C, but if there's any real differences doing it in C++, I'd like to know those also. 我正在使用MinGW进行编译,我想在C中执行此操作,但是如果在C ++中有任何真正的区别,我也想知道。 I want to know how to load that DLL into another C (and C++) program, and then call those functions from it. 我想知道如何将DLL加载到另一个C(和C ++)程序中,然后从中调用那些函数。 My goal here, after playing around with DLLs for a bit, is to make a VB front-end for C(++) code, by loading DLLs into visual basic (I have visual studio 6, I just want to make some forms and events for the objects on those forms, which call the DLL). 我的目标是,在玩完DLL之后,通过将DLL加载到Visual Basic中来制作C(++)代码的VB前端(我有Visual Studio 6,我只想做一些形式,这些表单(调用DLL)上的对象的事件。

I need to know how to call gcc (/g++) to make it create a DLL, but also how to write (/generate) an exports file... and what I can/cannot do in a DLL (like, can I take arguments by pointer/reference from the VB front-end? Can the DLL call a theoretical function in the front-end? Or have a function take a "function pointer" (I don't even know if that's possible) from VB and call it?) I'm fairly certain I can't pass a variant to the DLL...but that's all I know really. 我需要知道如何调用gcc(/ g ++)使其创建DLL,还需要知道如何编写(/生成)导出文件...以及我可以/不能在DLL中执行的操作(例如,我可以接受)通过VB前端的指针/引用来传递参数吗?DLL可以在前端调用理论函数吗?或者让函数从VB中获取“函数指针”(我什至不知道是否可行)并调用它吗?)我相当确定我无法将变体传递给DLL ...但这就是我所知道的全部。

update again 再次更新

Okay, I figured out how to compile it with gcc, to make the dll I ran 好的,我想出了如何使用gcc进行编译,以使我运行的dll

gcc -c -DBUILD_DLL dll.c
gcc -shared -o mydll.dll dll.o -Wl,--out-implib,libmessage.a

and then I had another program load it and test the functions, and it worked great, thanks so much for the advice, but I tried loading it with VB6, like this 然后我有另一个程序加载它并测试功能,并且效果很好,非常感谢您的建议,但是我尝试像这样用VB6加载它

Public Declare Function add2 Lib "C:\c\dll\mydll.dll" (num As Integer) As Integer

then I just called add2(text1.text) from a form, but it gave me a runtime error: 然后我只是从表单中调用了add2(text1.text),但这给了我一个运行时错误:

"Can't find DLL entry point add2 in C:\\c\\dll\\mydll.dll" “在C:\\ c \\ dll \\ mydll.dll中找不到DLL入口点add2”

this is the code I compiled for the DLL: 这是我为DLL编译的代码:

#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif

EXPORT int __stdcall add2(int num){
  return num + 2;
}

EXPORT int __stdcall mul(int num1, int num2){
  return num1 * num2;
}

calling it from the C program like this worked, though: 从C程序调用它的方式如下:

#include<stdio.h>
#include<windows.h>

int main(){

  HANDLE ldll;
  int (*add2)(int);
  int (*mul)(int,int);

  ldll = LoadLibrary("mydll.dll");
  if(ldll>(void*)HINSTANCE_ERROR){
    add2 = GetProcAddress(ldll, "add2");
    mul = GetProcAddress(ldll, "mul");
    printf("add2(3): %d\nmul(4,5): %d", add2(3), mul(4,5));
  } else {
    printf("ERROR.");
  }

}

any ideas? 有任何想法吗?

solved it 解决了

To solve the previous problem, I just had to compile it like so: 为了解决前面的问题,我只需要像这样编译它:

gcc -c -DBUILD_DLL dll.c
gcc -shared -o mydll.dll dll.o -Wl,--add-stdcall-alias

and use this API call in VB6 并在VB6中使用此API调用

Public Declare Function add2 Lib "C:\c\dll\mydll" _
    (ByVal num As Integer) As Integer

I learned not to forget to specify ByVal or ByRef explicitly--I was just getting back the address of the argument I passed, it looked like, -3048. 我学会了不要忘记明确指定ByVal或ByRef-我只是找回我传递的参数的地址,它看起来像是-3048。

Regarding building a DLL using MinGW, here are some very brief instructions. 关于使用MinGW构建DLL,以下是一些非常简短的说明。

First, you need to mark your functions for export, so they can be used by callers of the DLL. 首先,您需要标记要导出的函数,以便DLL的调用者可以使用它们。 To do this, modify them so they look like (for example) 为此,请修改它们,使它们看起来像(例如)

__declspec( dllexport ) int add2(int num){
   return num + 2;
}

then, assuming your functions are in a file called funcs.c, you can compile them: 然后,假设您的函数位于一个名为funcs.c的文件中,则可以对其进行编译:

gcc -shared -o mylib.dll funcs.c

The -shared flag tells gcc to create a DLL. -shared标志告诉gcc创建DLL。

To check if the DLL has actually exported the functions, get hold of the free Dependency Walker tool and use it to examine the DLL. 若要检查DLL是否实际上已导出函数,请抓住免费的Dependency Walker工具,并使用它检查DLL。

For a free IDE which will automate all the flags etc. needed to build DLLs, take a look at the excellent Code::Blocks , which works very well with MinGW. 对于免费的IDE,它将自动构建DLL所需的所有标志等,请看一下出色的Code :: Blocks ,它与MinGW配合得很好。

Edit: For more details on this subject, see the article Creating a MinGW DLL for Use with Visual Basic on the MinGW Wiki. 编辑:有关此主题的更多详细信息,请参阅MinGW Wiki上的文章“ 创建与Visual Basic一起使用的MinGW DLL”

Here is how you do it: 这是您的操作方式:

In .h 在.h中

#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif

extern "C" // Only if you are using C++ rather than C
{    
  EXPORT int __stdcall add2(int num);
  EXPORT int __stdcall mult(int num1, int num2);
}

in .cpp 在.cpp中

extern "C" // Only if you are using C++ rather than C
{    
EXPORT int __stdcall add2(int num)
{
  return num + 2;
}


EXPORT int __stdcall mult(int num1, int num2)
{
  int product;
  product = num1 * num2;
  return product;
}
}

The macro tells your module (ie your .cpp files) that they are providing the dll stuff to the outside world. 该宏告诉您的模块(即您的.cpp文件)它们正在将dll内容提供给外界。 People who incude your .h file want to import the same functions, so they sell EXPORT as telling the linker to import. 包含您的.h文件的人希望导入相同的功能,因此他们将EXPORT出售为告诉链接器导入。 You need to add BUILD_DLL to the project compile options, and you might want to rename it to something obviously specific to your project (in case a dll uses your dll). 您需要将BUILD_DLL添加到项目的编译选项中,并且您可能希望将其重命名为显然是您的项目特有的名称(以防dll使用您的dll)。

You might also need to create a .def file to rename the functions and de-obfuscate the names (C/C++ mangles those names). 您可能还需要创建一个.def文件来重命名功能并取消混淆名称(C / C ++会破坏这些名称)。 This blog entry might be an interesting launching off point about that. 这篇博客文章可能是一个有趣的起点。

Loading your own custom dlls is just like loading system dlls. 加载自己的自定义dll就像加载系统dll。 Just ensure that the DLL is on your system path. 只要确保DLL在您的系统路径上即可。 C:\\windows\\ or the working dir of your application are an easy place to put your dll. C:\\ windows \\或应用程序的工作目录是放置dll的简便位置。

There is but one difference. 只有一处不同。 You have to take care or name mangling win C++. 您必须保重或命名C ++ Win。 But on windows you have to take care about 1) decrating the functions to be exported from the DLL 2) write a so called .def file which lists all the exported symbols. 但是在Windows上,您必须注意1)降低要从DLL导出的功能2)编写一个所谓的.def文件,其中列出了所有导出的符号。

In Windows while compiling a DLL have have to use 在Windows中编译DLL时必须使用

__declspec(dllexport) __declspec(dllexport)

but while using it you have to write __declspec(dllimport) 但是在使用它时,您必须编写__declspec(dllimport)

So the usual way of doing that is something like 所以通常的做法是

#ifdef BUILD_DLL
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif

The naming is a bit confusing, because it is often named EXPORT.. But that's what you'll find in most of the headers somwhere. 命名有点混乱,因为它通常被命名为EXPORT。但这就是您在大多数头文件中发现的东西。 So in your case you'd write (with the above #define) 因此,根据您的情况,您可以编写(使用上面的#define)

int DLL_EXPORT add.... int DLL_EXPORT mult... int DLL_EXPORT添加...。int DLL_EXPORT多个...

Remember that you have to add the Preprocessor directive BUILD_DLL during building the shared library. 请记住,在构建共享库时必须添加Preprocessor指令BUILD_DLL。

Regards Friedrich 问候弗里德里希

The thing to watch out for when writing C++ dlls is name mangling. 编写C ++ dll时要注意的是名称修改。 If you want interoperability between C and C++, you'd be better off by exporting non-mangled C-style functions from within the dll. 如果要在C和C ++之间实现互操作性,最好通过从dll中导出无错的C样式函数来实现。

You have two options to use a dll 您有两种选择来使用dll

  • Either use a lib file to link the symbols -- compile time dynamic linking 使用lib文件链接符号-编译时动态链接
  • Use LoadLibrary() or some suitable function to load the library, retrieve a function pointer ( GetProcAddress ) and call it -- runtime dynamic linking 使用LoadLibrary()或一些合适的函数来加载库,检索函数指针( GetProcAddress )并调用它-运行时动态链接

Exporting classes will not work if you follow the second method though. 如果您遵循第二种方法,则导出类将无法工作。

For VB6: 对于VB6:

You need to declare your C functions as __stdcall, otherwise you get "invalid calling convention" type errors. 您需要将C函数声明为__stdcall,否则会出现“无效的调用约定”类型错误。 About other your questions: 关于其他问题:

can I take arguments by pointer/reference from the VB front-end? 我可以从VB前端通过指针/引用获取参数吗?

Yes, use ByRef/ByVal modifiers. 是的,使用ByRef / ByVal修饰符。

Can the DLL call a theoretical function in the front-end? DLL可以在前端调用理论函数吗?

Yes, use AddressOf statement. 是的,使用AddressOf语句。 You need to pass function pointer to dll before. 您需要先将函数指针传递给dll。

Or have a function take a "function pointer" (I don't even know if that's possible) from VB and call it?) 还是让函数从VB中获取“函数指针”(我什至不知道是否可行)并调用它?)

Yes, use AddressOf statement. 是的,使用AddressOf语句。

update (more questions appeared :)): 更新(出现了更多问题:)):

to load it into VB, do I just do the usual method (what I would do to load winsock.ocx or some other runtime, but find my DLL instead) or do I put an API call into a module? 要将其加载到VB中,我是否只需执行通常的方法(如何加载winsock.ocx或其他运行时,但要找到我的DLL)或将API调用放入模块中?

You need to decaler API function in VB6 code, like next: 您需要在VB6代码中对API函数进行贴花处理,如下所示:

Private Declare Function SHGetSpecialFolderLocation Lib "shell32" _
   (ByVal hwndOwner As Long, _
    ByVal nFolder As Long, _
    ByRef pidl As Long) As Long

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM