DLL动态链接库 ——SOCKET 1 笔记。

  VS2005 ->Win32->DLL.

  1.生成DLL 

   添加.h文件,

  #include "stdafx.h"
  __declspec(dllexport) void Test();

 

  //也可以直接使用extern   "C"  void Test()的方式
 

.CPP文件

void Test()
{
 ::MessageBoxA(NULL,"Test","Test",NULL);
}

 

.def文件

LIBRARY "ServerDll"
EXPORTS
Test @ 1

  2测试DLL

  简单的MFC对话框程序,添加单机按钮消息。

 

 

名词解释:

_declspec(thread)可以降低程序员的负担,又能做到线程局部存储的要求。VC++允许一个变量或结构被声明为“具有线程局部性”。例如,下面的声明,如果放在一个DLL之中,将产生出一个全局变量,对每一个进程而言独一无二:  
  DWORD   gProgressCounter;  
  但是如果这样声明,它就是对每一个线程独一无二:  
  _declspec(thread)     DWORD   gProgressCounter;  
  每一个以这种方式声明对象的EXE和DLL,将在可执行文件中有一个特殊的节区(section),内含所有的线程局部变量。当EXE或DLL被载入时,操作系统会认识这个节区并适当的处理之。这个节区会被操作系统社定为“对每一个线程具有局部性”。  
  当一个EXE被载入时,操作系统扫描可执行文件以及所有静态链接(implicity   linked)的DLLs,以便找出所有的线程局部节区。所有节区的大小被加总在一起以求出每个线程启动时应该配置的内存数量。

 

declspec(dllimport)     是说这个函数是从别的DLL导入。我要用。  
  _declspec(dllexport)   是说这个函数要从本DLL导出。我要给别人用。

 

 //下面摘自http://support.microsoft.com/kb/132044/zh-cn

为函数调用中使用 _declspec(dllimport)

<script type="text/javascript"></script> 在下面的代码示例假定 func1 是驻留在单独从.exe 文件包含 main () 函数的 DLL 中的函数。

_declspec(dllimport),而不给出此代码:

void main(void) {
    func1();
}
				

编译器生成类似下面的代码:

call func1
				

和链接器将翻译成如下所示调用:

call 0x4000000         ; The address of 'func1'.
				

'func1' 存在于另一个 DLL 中,如果链接器不能解决此直接因为它无法知道 'func1 的地址什么。 在 16 位环境中链接器将此代码地址添加到列表中加载程序在运行时用正确的地址修补该.exe。 在 32 位环境中链接器生成一个 thunk,它不会知道地址。 在 thunk 如下所示:

   0x40000000:    jmp DWORD P
 TR __imp_func1
				

__imp_func1 以下是为 func1 的插槽中导入地址表.exe 文件的地址。 链接器因此已知的所有地址。 若要更新在加载时,一切就会正常工作的.exe 文件导入地址表仅有加载程序。

因此,使用 _declspec(dllimport) 是更好的因为它是更好的如果链接器不生成一个 thunk,如果没有到。 thunk 使代码更大 (要 RISC 系统上它可以是几个说明) 并会降低缓存性能。 如果通知编译器函数是 DLL 中,它可以为您生成间接调用。

因此,现在此代码:

__declspec(dllimport) void func1(void);

void main(void) {
    func1();
}
				

生成此指令:

call DWORD PTR __imp_func1

不存在任何 thunk 并没有 jmp 指令使代码是更小、 更快。

手动,对于 DLL 内部的函数调用,您不希望不必使用间接调用。 您已经知道函数的地址。 时间和空间所需加载和存储之前间接调用函数的地址,因此直接调用总是更快和更小。 要从外部调用 DLL 函数时使用 __declspec(dllimport) DLL 本身。 不要使用上一个 DLL 内部的函数的 __declspec(dllimport),构建该 DLL 时。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是我自己编写的 测试好使通过 //======================================================================== //绑定协议栈-TCPServer mode //======================================================================== int dllBindTCPSockServer(SOCKADDR_IN pSockAddr,RECV_DATA_CALLBACK DataCallBack, VOID* pContext) { int res = 0; //Create Socket if(glb_SockTCPServer!=NULL) { OutputDebugString("套接字已存在!"); return -1; } glb_SockTCPServer = socket(AF_INET,SOCK_STREAM,0); //Create Socket res = WSAGetLastError(); if(res) { glb_SockTCPServer = NULL; OutputDebugString("套接字建立失败!"); return res; } pSockAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY); pSockAddr.sin_family=AF_INET; pSockAddr.sin_port = htons(pSockAddr.sin_port); res = bind(glb_SockTCPServer,(SOCKADDR*)&pSockAddr,sizeof(SOCKADDR)); if(res) { OutputDebugString("绑定失败!"); closesocket(glb_SockTCPServer); glb_SockTCPServer = NULL; return res; } OutputDebugString("绑定成功!"); res = listen(glb_SockTCPServer,5); if(res) { OutputDebugString("监听失败!"); closesocket(glb_SockTCPServer); glb_SockTCPServer = NULL; return res; } OutputDebugString("开始网络监听..."); //Register RecvDataCallBackServer glb_lpFunCallBackTCPServer = DataCallBack; glb_pContext = pContext; //Create ListenThread UINT (WINAPI * pFnStartAddr)(LPVOID); pFnStartAddr = WinSockListenThread; glb_WinSockListenThread = (HANDLE)_beginthreadex(NULL, 0, pFnStartAddr, NULL, 0,//0 for running, CREATE_SUSPENDED NULL); if (glb_WinSockListenThread==NULL) { OutputDebugString("创建监听线程失败!"); closesocket(glb_SockTCPServer); glb_SockTCPServer = NULL; glb_WinSockListenThread = NULL; return -2; } return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值