把握命运,追逐梦想

对自己所做的事要有兴趣,同时还要能够坚持不懈

统计

留言簿(1)

阅读排行榜

评论排行榜

2011年4月22日 #

VC 2008 sp1 中 deque的erase函数的问题

该函数在erase一个元素的时候,先复制最近端,例如该元素靠近前端,那么该元素之前的所有元素被复制,并后移拷贝,达到覆盖该元素的效果,导致最后Destroy的是第一个元素,析构函数也是第一个元素的,由于第一个元素被复制了,所以第一个元素如果没有拷贝复制函数来处理指针变量的话,那么之后第一个元素的副本中的指针将是错误的,而且同时有一个问题,我们想要destroy的那个元素的析构函数没被调用。

posted @ 2011-04-22 09:02 把握命运 阅读(602) | 评论 (2)编辑 收藏

2009年8月24日 #

def文件一个比较详细的例子

先看看EXPORTS语法规则:
entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]

对上面语法的解释:
1、

entryname 是要导出的函数名或变量名。这是必选项。如果导出的名称与 DLL 中的名称不同,则通过 internalname 指定 DLL 中导出的名称。例如,如果 DLL 导出函数 func1(),要将它用作 func2(),则应指定:

EXPORTS
func2=func1

2、

@ordinal 允许指定是序号而不是函数名将进入 DLL 的导出表。这有助于最小化 DLL 的大小。.LIB 文件将包含序号与函数之间的映射,这使您得以像通常在使用 DLL 的项目中那样使用函数名。

可选的 NONAME 关键字允许只按序号导出,并减小结果 DLL 中导出表的大小。但是,如果要在 DLL 上使用 GetProcAddress,则必须知道序号,因为名称将无效。

可选的 PRIVATE 关键字禁止将 entryname 放到由 LINK 生成的导入库中。它对同样是由 LINK 生成的图像中的导出无效。

可选的 DATA 关键字指定导出的是数据,而不是代码。例如,可以导出数据变量:

EXPORTS
i DATA

当对同一导出使用 PRIVATEDATA 时,PRIVATE 必须位于 DATA 的前面。

3、

有三种导出定义的方法,按照建议的使用顺序依次为:

  1. 源代码中的 __declspec(dllexport) 关键字

  2. .def 文件中的 EXPORTS 语句

  3. LINK 命令中的 /EXPORT 规范

所有这三种方法可以用在同一个程序中。LINK 在生成包含导出的程序时还创建导入库,除非生成中使用了 .exp 文件。


4、一个详细的
EXPORTS
DllCanUnloadNow      @1     PRIVATE   DATA
DllWindowName = Name        DATA
DllGetClassObject    @4 NONAME   PRIVATE
DllRegisterServer    @7
DllUnregisterServer
注意,使用 .def 文件从 DLL 中导出变量时,不需要在变量上指定 __declspec(dllexport)。但是,在任何使用 DLL 的文件中,仍必须在数据声明上使用 __declspec(dllimport)
 
下面的是一个例子,可以看到def文件实际上的作用。











Node_t node;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    node.x 
= 5;
    node.y 
= 6;
    
return TRUE;
}



int Max(int x, int y)
{
    
if(x>=y)
        
return x;
    
else
        
return y;
}


int Min(int x, int y)
{
    
if(x>=y)
        
return y;
    
else
        
return x;
}


Node_t 
* func1()
{
    
return &node;
}


Node_t 
* func2()
{
    
return &node;
}

下面是def文件


EXPORTS
Max            
=Max    @2
MinChange    
=Min    @1
func1        
=func1    @3    NONAME 
func2        
=func2    @5    PRIVATE 
node        
=node    @8    PRIVATE        

下面是对应的lib的导出

 2    ?Max@@YAHHH@Z (int __cdecl Max(int,int))
 
1    ?MinChange@@YAHHH@Z (int __cdecl MinChange(int,int))
 
3    ?func1@@YAPAUNode_t@@XZ (struct Node_t * __cdecl func1(void))

下面是对应的dll文件的导出

    ordinal hint RVA      name

          
2    0 00001020 Max = ?Max@@YAHHH@Z (int __cdecl Max(int,int))
          
1    1 00001030 MinChange = ?Min@@YAHHH@Z (int __cdecl Min(int,int))
          
5    2 00001040 func2 = ?func1@@YAPAUNode_t@@XZ (struct Node_t * __cdecl func1(void))
          
8    3 00003348 node = ?node@@3UNode_t@@A (struct Node_t node)
          
3      00001040 [NONAME] ?func1@@YAPAUNode_t@@XZ (struct Node_t * __cdecl func1(void))

从上面可以看出来,def文件的符号在lib中的作用并不大,但是函数名称,比如?MinChange@@YAHHH@Z中的MinChange是因为def中把Min改成了MinChange,所以lib中也进行了修改,但是这个MinChange符号实际上出现在dll文件的name列中。其实这也看出来了,def文件只是在loadlibrary这种运行时加载有效。
由于lib中的函数名变成了?MinChange@@YAHHH@Z,导致使用__declspec(dllimport)进行导入的启动时加载,生成的?Min@@YAHHH@Z无法与?MinChange@@YAHHH@Z对应,而出现链接时的错误。所以不应该改变函数名,而应该在def文件中直接使用函数名,这样启动时加载和运行时加载都能够顺利进行。
同时从上面也可以看出NONAME和PRIVATE的作用的。
问题:试验中使用DATA总是出错,不知道怎么弄。














posted @ 2009-08-24 10:29 把握命运 阅读(15619) | 评论 (1)编辑 收藏

WSAStartup简单解释

int WSAStartup (
  WORD
wVersionRequested
  LPWSADATA lpWSAData 
);
第一个参数是调用者能够使用的最高版本号。
第二个参数中的前两个成员中,第一个成员是sock dll返回的版本号,第二个参数是dll支持的最高版本号。

这个函数成功返回的条件是,第一个参数的版本号高于sock dll能够支持的最低版本,那么就表示dll肯定支持调用者能够使用的一个版本。在第二个参数中的第一个变量种返回第一个参数和dll支持的最高版本中的那个小的版本。
示例图,有重叠,说明存在可以使用的版本。

第一行是调用者能够使用的所有版本,第二行是dll支持的所有版本,而这个函数中的第一个参数是第一行中的最大版本。第二个参数中的第一个成员是重叠部分的最大的那个。如果没有重叠部分,那么函数失败。

posted @ 2009-08-24 09:51 把握命运 阅读(289) | 评论 (0)编辑 收藏

2009年8月23日 #

线程同步的几种方法

1.CreateMutex
   WaitForSingleObject
   RealseMutex

2.CreateThread中的临界区

posted @ 2009-08-23 20:30 把握命运 阅读(228) | 评论 (0)编辑 收藏

2009年8月20日 #

istream_iterator的自增

 

  // TEMPLATE CLASS istream_iterator
template<class _Ty,
 class _Elem = char,
 class _Traits = char_traits<_Elem>,
 class _Diff = ptrdiff_t>
 class istream_iterator
  : public iterator<input_iterator_tag, _Ty, _Diff,
   const _Ty *, const _Ty&>
 { // wrap _Ty extracts from input stream as input iterator
 typedef istream_iterator<_Ty, _Elem, _Traits, _Diff> _Myt;
public:
 typedef _Elem char_type;
 typedef _Traits traits_type;
 typedef basic_istream<_Elem, _Traits> istream_type;

#if _SECURE_SCL
 typedef _Range_checked_iterator_tag _Checked_iterator_category;
#endif

 istream_iterator()
  : _Myistr(0)
  { // construct singular iterator
  }

 istream_iterator(istream_type& _Istr)
  : _Myistr(&_Istr)
  { // construct with input stream
  _Getval();
  }

 const _Ty& operator*() const
  { // return designated value

 #if _HAS_ITERATOR_DEBUGGING
  if (_Myistr == 0)
   {
   _DEBUG_ERROR("istream_iterator is not dereferencable");
   _SCL_SECURE_OUT_OF_RANGE;
   }
 #else
  _SCL_SECURE_VALIDATE_RANGE(_Myistr != 0);
 #endif /* _HAS_ITERATOR_DEBUGGING */

  return (_Myval);
  }

 const _Ty *operator->() const
  { // return pointer to class object
  return (&**this);
  }

 _Myt& operator++()
  { // preincrement

 #if _HAS_ITERATOR_DEBUGGING
  if (_Myistr == 0)
   {
   _DEBUG_ERROR("istream_iterator is not incrementable");
   _SCL_SECURE_OUT_OF_RANGE;
   }
 #else
  _SCL_SECURE_VALIDATE_RANGE(_Myistr != 0);
 #endif /* _HAS_ITERATOR_DEBUGGING */

  _Getval();
  return (*this);
  }

 _Myt operator++(int)
  { // postincrement
  _Myt _Tmp = *this;
  ++*this;
  return (_Tmp);
  }

 bool _Equal(const _Myt& _Right) const
  { // test for iterator equality
  return (_Myistr == _Right._Myistr);
  }

protected:
 void _Getval()
  { // get a _Ty value if possible
  if (_Myistr != 0 && !(*_Myistr >> _Myval))
   _Myistr = 0;
  }

 static void _Xran()
  { // report an out_of_range error
  _THROW(out_of_range, "invalid istream_iterator");
  }

 istream_type *_Myistr; // pointer to input stream
 _Ty _Myval; // lookahead value (valid if _Myistr is not null)
 };

  // istream_iterator TEMPLATE OPERATORS
template<class _Ty,
 class _Elem,
 class _Traits,
 class _Diff> inline
 bool operator==(
  const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Left,
  const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Right)
 { // test for istream_iterator equality
 return (_Left._Equal(_Right));
 }

template<class _Ty,
 class _Elem,
 class _Traits,
 class _Diff> inline
 bool operator!=(
  const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Left,
  const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Right)
 { // test for istream_iterator inequality
 return (!(_Left == _Right));
 }

红色部分就是重点了,其实这种迭代器不能自增,只是不断把流中的元素放到自己所存的值里,当到达流末尾时,直接将判断指针设为0。

posted @ 2009-08-20 12:45 把握命运 阅读(951) | 评论 (0)编辑 收藏

C++练习5作业

     摘要: //train.h#pragma once#include"stdafx.h"class Train{public:    Train(int seatNum);    virtual ~Train(void);    bool ...  阅读全文

posted @ 2009-08-20 12:05 把握命运 阅读(241) | 评论 (0)编辑 收藏

2009年8月19日 #

关于私有成员

以前一直理解错误,一直以为私有成员是对象的,不是类的,现在想想,自己真笨,编译器怎么可能检查到运行时的对象的私有成员是否被别的代码使用了呢?编译器能做的只能是检查类的声明和定义,所以私有成员是类的,也就是同类所有对象的,而不是某一个对象的。只要在同一个类声明和成员函数定义体内,私有成员是可以随便使用的。

posted @ 2009-08-19 22:57 把握命运 阅读(135) | 评论 (0)编辑 收藏

2009年8月18日 #

__cdecl、__stdcall、__fastcall

     摘要: 1.这三个修饰符的基本意思   __cdecl:C调用方式,VC默认使用该方式,参数从右向左传递,参数个数可变,栈的初始和清理由调用者完成   __stdcall:标准调用方式,多种语言使用这种调用方式,参数从右向左传递,参数个数不可变,栈的初始和清理由被调用者完成   __fastcall:参数尽量使用寄存...  阅读全文

posted @ 2009-08-18 23:05 把握命运 阅读(1363) | 评论 (0)编辑 收藏

exe、dll的进入点,以及main、winmain、dllmain的关系

静态链接的情况不考虑,因为这种情况就是把所有代码合并到exe中,不需要进入点。

进入点就是系统在加载一个可执行代码块(主要是exe和dll)到内存的时候,系统将要调用的起始代码的位置。

加载分为启动时加载和运行时加载,这两种说法主要是针对dll的,因为exe加载必然会创建一个新的进程,所以exe加载都是启动时加载,就算是createprocess也应该说是启动时加载。而dll分为两种情况,第一种就是随着exe的加载一起加载到内存的同一进程地址空间中,另一种则是exe中的代码loadlibrary在运行时加载dll到当前exe的进程地址空间中。
无论上面哪种情况,只要加载,系统就会一定在加载的时候调用进入点代码,所以加载方式与进入点完全不影响。

win sdk文档中exe的进入点有两个,一个是main,另一个是winmain,这个进入点是可以改的,但是在c运行环境下,连接器一般把进入点默认设置为mainCRTStartupWinMainCRTStartup,因为c运行时需要在代码执行前进行一些别的工作,所以就修改为前面两个c入口点,然后这两个函数再分别调用main和winmain。c运行时需要作的特别工作就是初始化c运行时环境,包括静态、全局变量和对象初始化。当main或者winmain返回时就又回到了前两个函数中,这两个函数的后半部分就是负责清理之前的初始化工作。

win sdk文档中的dll的进入店是dllmain,同样在c运行时下,改为_DllMainCRTStartup,系统加载dll时调用这个函数,然后这个函数做些初始化工作,再调用dllmain,然后返回_DllMainCRTStartup结束执行。此时,dll已经在进程的地址空间中了,该进程的exe可以使用dll中的代码了。如果该dll是启动时加载,那么在程序结束时会再次调用_DllMainCRTStartup进行清理之前dll初始化的工作,如果是通过loadlibrary来运行时加载dll,那么需要exe自己卸载dll,卸载的时候会再次调用_DllMainCRTStartup

 

posted @ 2009-08-18 18:50 把握命运 阅读(1711) | 评论 (0)编辑 收藏

2009年8月12日 #

CreateFile和WriteFile

#include"windows.h"
#include
"tchar.h"

LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);

HANDLE g_hFile;
HANDLE g_hFile1;
struct sMsg
{
    DWORD time;
    DWORD message;
}
;

    

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE ,LPTSTR lpCmdLine,int nCmdShow)
{
    
if(!hInstance) return 0;
    WNDCLASSEX wcex;
    wcex.style 
= CS_HREDRAW |    CS_OWNDC|CS_VREDRAW ;          //常用设置,这个设置定义类在遇到各种情况时的行为,不过都是些可有可无的东西
    wcex.lpszClassName = TEXT("FIRSTCLASS");                         //类名,必须存在,这是引用类的差不多唯一的标志,另一个是class atom
    wcex.hInstance = hInstance;                                                    //类所属的模块句柄,如果style中有CS_OWNDC,相反,如果是CS_CLASSDC的话,这个类就属于这个进程
    wcex.lpszMenuName = NULL;                                               //这是个指向菜单资源的指针,如果是NULL的话,则没有菜单
    wcex.hCursor = LoadCursor(NULL,IDC_ARROW);           //加载鼠标图标,如果是NULL的话,系统没有默认的鼠标图标,因此图标会出现未定义情况
    wcex.hIcon  = NULL;                                                               //系统会加载默认图标
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpfnWndProc 
= WindowProc;
    wcex.cbClsExtra 
=0;                                                               //分配给类的额外内存,根本用不上,设为0
    wcex.cbWndExtra = 0;                                                        //分配给由这个类产生的所有窗口的每一个内存大小,用不上,0
    wcex.cbSize = sizeof(WNDCLASSEX);                             //类的大小,这个估计是以后扩展的时候用的吧,总共两种,难道是用来区分普通类和扩展类???
    wcex.hIconSm = NULL;                                                          //小型图标,NULL,系统知道如何处理,影响不了程序的正常运行

    
if(!RegisterClassEx(&wcex))                                //函数失败,返回0,否则返回一个atom,这个atom是用来标记类的,但是用的不多,能用类名的地方,也能用这东西
    {
        
return 0;
    }


    g_hFile   
=   CreateFile(L"d:\\pe\\messagefile.txt",         //   file   to   open   
    GENERIC_WRITE,                     //   open   for   reading   
    FILE_SHARE_WRITE,               //   share   for   reading   
    NULL,                                     //   default   security   
    OPEN_ALWAYS,                   //   existing   file   only   
    FILE_ATTRIBUTE_NORMAL,   //   normal   file   
    NULL);   

    g_hFile1 
= CreateFile(L"messagefile1.txt",
        GENERIC_WRITE,
        FILE_SHARE_WRITE,
        NULL,
        OPEN_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    
//下面的这个函数和CreateWindow是同一个,只是define了几个参数而以,所以现在使用的CreateWindow就是CreateWindowEx
    HWND hWnd = CreateWindowEx(0L,_T("FIRSTCLASS"),_T("name"),WS_OVERLAPPEDWINDOW ,CW_USEDEFAULT,CW_USEDEFAULT,640,480,NULL,NULL,hInstance,NULL);
    
if(!hWnd)
    
{
        
return 0;
    }

        
    ShowWindow(hWnd,nCmdShow  );
    

    MSG msg 
= {0};
    DWORD nbuffer;
    
while(GetMessage(&msg,NULL,0,0))
    
{
        TranslateMessage(
&msg);

        sMsg smsg 
= {0};
        smsg.time 
= msg.time;
        smsg.message 
= msg.message;
        WriteFile(  g_hFile1,   
&smsg,   sizeof(smsg),   &nbuffer,   NULL  );  
        
        DispatchMessage(
&msg);
    }


    CloseHandle(g_hFile); 
    CloseHandle(g_hFile1);

    
return (int)msg.wParam;


}



LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    DWORD nbuffer;
    WriteFile( g_hFile,   
&uMsg,   sizeof(uMsg),   &nbuffer,   NULL  );   



    PAINTSTRUCT ps;
    HDC hdc;

    
switch(uMsg)
    
{
    
case WM_PAINT:
        hdc 
= BeginPaint(hWnd,&ps);
        EndPaint(hWnd,
&ps);
        
break;
    
case WM_DESTROY:
        PostQuitMessage(
0);
        
break;
    
default:
        
return DefWindowProc(hWnd,uMsg,wParam,lParam);
    }

    
return 0;
}

posted @ 2009-08-12 19:46 把握命运 阅读(559) | 评论 (0)编辑 收藏

仅列出标题  下一页