在VC6下,File —> New —> Projects —> Win32 Dynamic-Link Library(一般在倒数第二个)—> 输入名字 —> 选择 An empty DLL project. —> Finish
新建头文件:
File —> New —> Files —> C/C++ Header File
我的头文件是:ErrTest.h
/***************************************************************************
Module: ErrTest.h
***************************************************************************/
#ifndef ERRTEST_H
#define ERRTEST_H
// 该宏定义在(VC6.0下)工程属性--> C/C++ --> project options 中由系统默认定义
// 所以同一个DLL工程引用此头文件时,就不用手工定义 ERRTEST_EXPORTS 了
#ifdef ERRTEST_EXPORTS
#define ERRTESTAPI __declspec(dllexport) // 当此头文件被DLL中的源代码模块引用时定义
#else
#define ERRTESTAPI __declspec(dllimport) // 当此头文件被其他工程中的源代码模块引用时定义
#endif
class ERRTESTAPI ErrTest { // ERRTESTAPI 不是放在 class 左边!
public:
static void printf(const char *fmt, ...);
static HANDLE GetConsole(int nStdHandle = STD_OUTPUT_HANDLE);
static HANDLE hConsole;
};
ERRTESTAPI extern int nErrTest; // 要加 extern
ERRTESTAPI void func(void);
#endif
////////////////////////////// End of File /////////////////////////////////
新建源文件:
File —> New —> Files —> C++ Source File
我的源文件是:ErrTest.cpp
/***************************************************************************
Module: ErrTest.cpp
***************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <exception>
#include <stdarg.h>
#include "ErrTest.h"
HANDLE ErrTest::hConsole = NULL;
int nErrTest = 5;
// 把格式化字符串输出到控制台窗口中
void ErrTest::printf(const char *fmt, ...)
{
const int BUFSIZE = 65535;
int sz;
// const char *p;
char szBuf[BUFSIZE];
GetConsole();
va_list valist;
// p = fmt+strlen(fmt)-1;
va_start(valist, fmt);
// vsprintf(szBuf, fmt, valist);
vsprintf(szBuf, fmt, valist);
va_end(valist);
sz = strlen(szBuf)*sizeof(char);
__try {
WriteConsole(GetConsole(), szBuf, sz, NULL, NULL);
} __except (EXCEPTION_EXECUTE_HANDLER) {
int e = GetLastError();
MessageBox(NULL, TEXT("Error in ErrTest::printf when WriteConsole()!"), 0, 0);
}
}
// 获取控制台句柄,默认返回的是输出用的句柄。
HANDLE ErrTest::GetConsole(int nStdHandle /* = STD_OUTPUT_HANDLE */)
{
if (hConsole == NULL) {
AllocConsole();
hConsole = GetStdHandle(nStdHandle);
// hConsole = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
// FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
}
return hConsole;
}
void func()
{
MessageBox(0, "errtest.cpp 00", 0, 0);
}
生成DLL文件:
Build(或F7)之后,会发现在 Debug 文件夹下有 ErrTest.lib 和 ErrTest.dll 两个文件,加上 ErrTest.h,就是此次工程生成的最主要的三个文件了。
创建示例用的可运行文件:
File —> New —> Win32 Application —> A typical "Hello World!" application —> Finish
按如下代码中中文所示部分,加入适当的内容:
// 1.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
#include "ErrTest.h" // 《《———— 加入头文件
#pragma comment(lib, "ErrTest.lib") // 《《———— 告诉链接器要加载lib文件
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
ErrTest::printf("ErrTest::printf(): %d", nErrTest); // 《《———— 调用DLL中的类静态成员和全局变量
func(); // 《《———— 调用DLL函数
MSG msg;
HACCEL hAccelTable;
然后,将刚才创建DLL之后产生的 ErrTest.h 头文件、ErrTest.lib、ErrTest.dll文件复制到示例工程.dsw所在文件夹中。按Ctrl+F5即可运行得到结果。
注意:
1.必须通知链接器加载 lib 文件,如果链接器无法加载此文件,那么在工程中引用的所有变量、函数都会出现 unresolved external symbol 的错误,如下:
--------------------Configuration: 1 - Win32 Debug--------------------
Compiling...
1.cpp
Linking...
1.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) void __cdecl func(void)" (__imp_?func@@YAXXZ)
1.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: static void __cdecl ErrTest::printf(char const *,...)" (__imp_?printf@ErrTest@@SAXPBDZZ)
1.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) int nErrTest" (__imp_?nErrTest@@3HA)
Debug/1.exe : fatal error LNK1120: 3 unresolved externals
Error executing link.exe.
1.exe - 4 error(s), 0 warning(s)
那么,通知链接器(linker)去加载lib的方法有两种,一种就是如上所示,在源代码中添加 #pragma comment(lib, "ErrTest.lib"),这里要注意,#pragma 不是 #progma!另一种,就是在 Project —> settings —> link选项卡 —> Object/library modules 中加入 ErrTest.lib 。
分享到:
相关推荐
在C++编程中,DLL(Dynamic Link Library)是一种共享库,可以包含函数、类和变量等资源,供其他程序在运行时动态调用。本文将深入探讨如何从DLL中导出接口、类和变量,以及如何实现静态和动态方法。 首先,让我们...
3. **使用导出函数**: 通过函数指针或C++的`extern "C"`来调用DLL中的函数。确保参数类型和调用约定与DLL中定义的一致。 4. **处理错误**: 考虑到可能的错误情况,如DLL未找到、版本不兼容等,需要适当的错误处理...
3. **不能从DLL中调用全局变量**:在DLL中声明的全局变量不能直接被调用程序访问。但是可以在调用程序中声明局部变量作为参数传递给DLL。 4. **被调用的DLL必须存在**:如果指定的DLL不存在或者路径错误,程序运行时...
本示例将详细讲解如何使用`extern "C"`来改善C++程序显式调用DLL中的函数,从而解决C++名字修饰(Name Mangling)问题。 1. **C++名字修饰**:C++为了支持重载和多态性,会对函数和变量的名字进行修饰,生成一个...
为了提高程序启动速度,可以使用延迟加载(Delay Load)DLL,即在调用DLL函数时才真正加载DLL。这可以通过设置链接器选项或使用`_delayimp.lib`和`_delayload.h`实现。 7. **静态链接与动态链接** 静态链接将DLL...
使用Visual C++ 6.0创建一个名为`Count`的DLL项目,并定义一个简单的函数`count`,用于递增一个静态变量: ```cpp extern "C" __declspec(dllexport) int __stdcall count(int init) { static int S = init; ...
为了测试创建的DLL,我们需要编写一个简单的测试程序,该程序将链接到我们创建的DLL,并调用其中的全局变量、函数和类: ```cpp #include "stdafx.h" #include using namespace std; #include "../MathLib/...
调用DLL函数时可能会出现错误,如找不到函数、内存分配失败等,需要适当的错误处理机制,如异常处理或返回错误代码。 6. **跨进程通信**: 如果DLL和宿主程序不在同一个进程中,可能需要更复杂的通信方式,如共享...
在多类之间共享一个回调函数,通常意味着你需要在C++ DLL中定义一个全局变量或静态成员来保存回调函数的引用。当多个类需要使用同一个回调时,它们都可以访问这个全局变量或静态成员。然而,这样做需要注意线程安全...
在IT领域,动态库(Dynamic Link Library,DLL)是Windows操作系统中的一种共享代码库,它包含了一组可执行函数和全局变量,可供多个程序同时使用,以节省内存和提高效率。C/C++语言中,开发人员可以创建动态库来...
3. **调用DLL函数**:在测试项目的主函数中,可以像使用普通库函数一样调用DLL中的函数和类方法: ```cpp int _tmain(int argc, _TCHAR* argv[]) { cout ; cout ; int a = 20, b = 30; cout , " ; cout (a, b...
6. 调用DLL函数:在客户端程序中,像调用本地函数一样调用DLL中的函数,例如: ```cpp void MyDllFunction(); MyDllFunction(); ``` 7. 链接与运行:编译并链接两个项目,确保客户端程序能找到DLL文件,然后...
2. **线程安全**:DLL中的全局变量和静态对象在多线程环境中可能引发问题。确保对共享数据进行适当的同步,或者避免使用全局变量。 3. **版本管理**:DLL的版本控制很重要,因为不同版本的DLL可能不兼容。使用版本...
- 如果你的DLL同时包含了C++类,那么在导出类时,必须导出其构造函数、析构函数以及所有虚函数,否则可能会遇到链接错误或运行时问题。 - 使用`__stdcall`调用约定通常更适合于DLL,因为它确保了参数清理由被调用...
开发者可以创建自己的DLL,定义函数和全局变量,供其他程序使用。 **ActiveX控件** ActiveX是微软提出的一种组件技术,它基于COM(Component Object Model)模型,主要用于构建交互式Web应用程序。ActiveX控件是...
5. 调用DLL:在客户端程序中,通过LoadLibrary和GetProcAddress函数动态加载和调用DLL中的函数。 静态库(.lib文件)则不同,它在编译时与应用程序链接,生成的可执行文件包含了库中的所有代码。这意味着每个使用...
这种类型的DLL可以访问全局变量、消息队列等MFC特性。在DLL_ALL中,这部分内容会教你如何创建和使用MFC扩展DLL,包括类的导出、消息处理等。 4. **EXTERN关键字**:在DLL中,为了指示函数或变量是在外部定义的,...
1. **分析DLL功能**:首先,你需要了解每个DLL提供的功能,包括导出的函数和全局变量。这可以通过工具如 Dependency Walker 来查看DLL的导出表。 2. **源码整合**:如果源代码可用,将各个DLL中的相关代码合并到一...
5. **调用DLL**:在应用程序中,通过`LoadLibrary`和`GetProcAddress`函数来动态加载和访问DLL的函数。或者,如果在编译时知道DLL的接口,可以使用`__declspec(dllimport)`来静态链接。 6. **错误处理和调试**:...
每个线程都有自己的调用堆栈,但DLL的全局变量和静态成员是共享的。因此,必须确保在多线程环境中正确同步访问。同时,DLL有初始化和卸载过程,可以重载`DllMain`函数来处理。 六、延迟加载DLL 延迟加载允许程序在...