dlutyuanhongl(乱石铺街)的BLOG

VC知识库BLOG 首页 新随笔 联系 聚合 登录
  11 Posts :: 1 Stories :: 65 Comments :: 2 Trackbacks

留言簿(8)

随笔分类

随笔档案

文章分类

文章档案

相册

搜索

最新评论

阅读排行榜

评论排行榜

2005年5月1日 #

《易经》第一卦 乾 乾为天 乾上乾下

  乾:元,亨,利,贞。

  初九:潜龙,勿用。

  九二:见龙再田,利见大人。

  九三:君子终日乾乾,夕惕若,厉无咎。

  九四:或跃在渊,无咎。

  九五:飞龙在天,利见大人。

  上九:亢龙有悔。

  用九:见群龙无首,吉。

彖曰:大哉乾元,万物资始,乃统天。云行雨施,品物流形。大明始终,六位时成,时乘六龙以御天。乾道变化,各正性命,保合大和,乃利贞。首出庶物,万国咸宁。

象曰:天行健,君子以自强不息。

潜龙勿用,阳在下也。 见龙再田,德施普也。 终日乾乾,反复道也。 或跃在渊,进无咎也。飞龙在天,大人造也。 亢龙有悔,盈不可久也。 用九,天德不可为首也。

文言曰:「元者,善之长也,亨者,嘉之会也,利者,义之和也,贞者,事之干也。 君子体仁,足以长人;嘉会,足以合礼;利物,足以和义;贞固,足以干事。 君子行此四者,故曰:乾:元亨利贞。」

初九曰:「潜龙勿用。」 何谓也?

子曰: 「龙德而隐者也。不易乎世,不成乎名;世而无闷,不见是而无闷;乐则行之,忧则违之;确乎其不可拔,乾龙也。」

九二曰:「见龙在田,利见大人。」 何谓也?

子曰: 「龙德而正中者也。 庸言之信,庸行之谨,闲邪存其诚,善世而不伐,德博而化。 易曰:「见龙在田,利见大人。」 君德也。」

九三曰:「君子终日乾乾,夕惕若,厉无咎。」 何谓也?

子曰: 「君子进德修业,忠信,所以进德也。修辞立其诚,所以居业也。知至至之,可与几也。 知终终之,可与存义也。 是故,居上位而不骄,在下位而不忧。故乾乾,因其时而惕,虽危而无咎矣。」

九四:「或跃在渊,无咎。」 何谓也?

子曰: 「上下无常,非为邪也。 进退无恒,非离群也。 君子进德修业,欲及时也,故无咎。」

九五曰:「飞龙在天,利见大人。」 何谓也?

子曰: 「同声相应,同气相求;水流湿,火就燥;云从龙,风从虎。 圣人作,而万物睹,本乎天者亲上,本乎地者亲下,则各从其类也。

上九曰:「亢龙有悔。」 何谓也?

子曰: 「贵而无位,高而无民,贤人在下而无辅,是以动而有悔也。」

乾龙勿用,下也。 见龙在田,时舍也。 终日乾乾,行事也。或跃在渊,自试也。飞龙在天,上治也。 亢龙有悔,穷之灾也。乾元用九,天下治也。

乾龙勿用,阳气潜藏。见龙在田,天下文明。终日乾乾,与时偕行。 或跃在渊,乾道乃革。飞龙在天,乃位乎天德。亢龙有悔,与时偕极。 乾元用九,乃见天则。

乾元者,始而亨者也。 利贞者,性情也。 乾始能以美利利天下,不言所利。 大矣哉!大哉乾乎?刚健中正,纯粹精也。 六爻发挥,旁通情也。 时乘六龙,以御天也。 云行雨施,天下平也。君子以成德为行,日可见之行也。潜之为言也,隐而未见,行而未成,是以君子弗用也。
   君子学以聚之,问以辩之,宽以居之,仁以行之。易曰:「见龙在田,利见大人。」 君德也。

九三, 重刚而不中,上不在天,下不在田。 故乾乾,因其时而惕,虽危无咎矣。

九四, 重刚而不中,上不在天, 下不在田,中不在人,故或之。或之者,疑之也,故无咎。

夫大人者,与天地合其德,与日月合其明,与四时合其序,与鬼神合其吉凶。 先天下而天弗违,后天而奉天时。 天且弗违,而况於人乎? 况於鬼神乎?

亢之为言也,知进而不知退,知存而不知亡,知得而不知丧。

其唯圣人乎? 知进退存亡,而不失其正者,其为圣人乎?

发表于 2005-05-01 18:37 乱石铺街 阅读(3287) | 评论 (7)编辑 收藏

2005年4月25日 #

        连续闭门写了十几天代码,亦没有任何进展。索性就不弄了,看了一晚上央视版《水浒》。我怎么越看宋江越恶心,不像个N多人的头领。
发表于 2005-04-25 20:09 乱石铺街 阅读(2776) | 评论 (10)编辑 收藏

2005年4月19日 #

    最近要做一个网络方面的小东东,基于C/S模式的。都说IOCP可以使系统达到最佳的性能,因此我就比划了两下,献丑了。抄书开始。
    从本质上说,完成端口模型要求创建一个windows完成端口对象,该对象通过指定数量的线程,对重叠I/O请求进行管理,以便为已经完成的重叠I/O请求提供服务。
    首先要创建一个I/O完成端口对象,用它面向任意数量的套接字句柄,管理多个I/O请求。调用以下函数创建完成端口对象:

HANDLE CreateIoCompletionPort(
  HANDLE FileHandle,// 同IOCP关联在一起的套接字句柄
  HANDLE ExistingCompletionPort,// IOCP句柄
  ULONG_PTR CompletionKey,        // 完成健
  DWORD NumberOfConcurrentThreads // 在IOCP上,同时允许执行的线程数量
);

    该函数有两个作用:
    (1)创建一个完成端口对象
    (2)将一个句柄同完成端口关联到一起
    
    然后就要创建一定数量的工作者线程,以便在套接字的I/O请求投递给完成端口后,为完成端口提供服务。写文字描述很烦,还是看代码吧:

// NetServer3.cpp : Defines the entry point for the console application.
//

#include 
"stdafx.h"
#include 
"NetServer3.h"

#include 
<winsock2.h>
#pragma comment(lib, 
"ws2_32.lib")

#include 
<iostream>
using namespace std;

//////////////////////////////////////////////////////////////////////////

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//////////////////////////////////////////////////////////////////////////

// 单句柄数据
typedef struct tagPER_HANDLE_DATA
{
    SOCKET Socket;
    SOCKADDR_STORAGE ClientAddr;
    
// 将和这个句柄关联的其他有用信息,尽管放在这里面吧
}
PER_HANDLE_DATA, *LPPER_HANDLE_DATA;

// 但I/O操作数据
typedef struct tagPER_IO_DATA
{
    OVERLAPPED Overlapped;
    WSABUF DataBuf;
    
char buffer[1024];
    
int BufferLen;
    
int OperationType;   // 可以作为读写的标志,为简单,我忽略了
}
PER_IO_DATA, *LPPER_IO_DATA;

DWORD WINAPI ServerWorkerThread(LPVOID lpParam);

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    
int nRetCode = 0;

    
// initialize MFC and print and error on failure
    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    
{
        
// TODO: change error code to suit your needs
        cerr << _T("Fatal Error: MFC initialization failed"<< endl;
        nRetCode 
= 1;
    }

    
else
    
{
        
// TODO: code your application's behavior here.
        CString strHello;
        strHello.LoadString(IDS_HELLO);
        cout 
<< (LPCTSTR)strHello << endl;
    }


//////////////////////////////////////////////////////////////////////////

    HANDLE CompletionPort;
    WSADATA wsd;
    SYSTEM_INFO SystemInfo;
    SOCKADDR_IN InternetAddr;
    SOCKET Listen;

    
// 加载WinSock2.2
    WSAStartup(MAKEWORD(22), &wsd);

    
// 1.创建一个I/O完成端口
    CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
                                            NULL,
                                            
0,
                                            
0);

    
// 2.确定系统中有多少个处理器
    GetSystemInfo(&SystemInfo);

    
// 3.基于系统中可用的处理器数量创建工作器线程
    for (int i = 0; i < SystemInfo.dwNumberOfProcessors; ++i)
    
{
        HANDLE ThreadHandle;

        
// 创建一个服务器的工作器线程,并将完成端口传递到该线程
        ThreadHandle = CreateThread(NULL,
                                    
0,
                                    ServerWorkerThread,
                                    CompletionPort,
                                    
0,
                                    NULL);

        CloseHandle(ThreadHandle);
    }


    
// 4.创建一个监听套接字,以下的套路都是固定的。
    Listen = WSASocket(AF_INET,
                       SOCK_STREAM,
                       
0,
                       NULL,
                       
0,
                       WSA_FLAG_OVERLAPPED);

    InternetAddr.sin_family 
= PF_INET;
    InternetAddr.sin_port 
= htons(5000);
    InternetAddr.sin_addr.s_addr 
= htonl(INADDR_ANY);

    bind(Listen, (SOCKADDR
*)&InternetAddr, sizeof(InternetAddr));

    listen(Listen, 
5);

    BOOL b 
= TRUE;

    
while (b)
    
{
        PER_HANDLE_DATA 
* PerHandleData = NULL;
        SOCKADDR_IN saRemote;
        SOCKET Accept;
        
int RemoteLen;

        
// 5.接收连接,并分配完成端口,这儿可以用AcceptEx来代替,以创
         // 建可伸缩的Winsock应用程序。

        RemoteLen = sizeof(saRemote);
        Accept 
= accept(Listen, (SOCKADDR*)&saRemote, &RemoteLen);

        
// 6.创建用来和套接字关联的单句柄数据信息结构
        PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, 
                                                       
sizeof(PER_HANDLE_DATA));

        cout 
<< "Socket number " << Accept << " connected" << endl;

        PerHandleData
->Socket = Accept;
        memcpy(
&PerHandleData->ClientAddr, &saRemote, RemoteLen);

        
// 7.将接受套接字和完成端口关联起来
        CreateIoCompletionPort((HANDLE)Accept,
                               CompletionPort,
                               (DWORD)PerHandleData,
                               
0);

        
// 开始在接受套接字上处理I/O
        
// 使用重叠I/O机制,在新建的套接字上投递一个或多个异步
         // WSARecv 或 WSASend请求。这些I/O请求完成后,工作者线程
         // 会为I/O请求提供服务,之后就可以坐享其成了

        static int const DATA_BUFSIZE = 4096; //

        DWORD RecvBytes 
= 0;
        DWORD Flags 
= 0;

        
// 单I/O操作数据
        LPPER_IO_DATA PerIoData = NULL;
        PerIoData 
= (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
        ZeroMemory(
&(PerIoData->Overlapped), sizeof(OVERLAPPED));        

        PerIoData
->DataBuf.len = 1024;
        PerIoData
->DataBuf.buf = PerIoData->buffer;
        PerIoData
->OperationType = 0// read
        WSARecv(PerHandleData->Socket,
                
&(PerIoData->DataBuf),
                
1,
                
&RecvBytes,
                
&Flags,
                
&(PerIoData->Overlapped),
                NULL);
    }


//////////////////////////////////////////////////////////////////////////

    
return nRetCode;
}


//////////////////////////////////////////////////////////////////////////

DWORD WINAPI ServerWorkerThread(LPVOID lpParam)
{
    HANDLE CompletionPort 
= (HANDLE)lpParam;
    DWORD BytesTransferred;
    LPOVERLAPPED lpOverlapped;
    LPPER_HANDLE_DATA PerHandleData 
= NULL;
    LPPER_IO_DATA PerIoData 
= NULL;
    DWORD SendBytes;
    DWORD RecvBytes;
    DWORD Flags;
    BOOL bRet 
= FALSE;

    
while (TRUE)
    
{
        bRet 
= GetQueuedCompletionStatus(CompletionPort,
                                         
&BytesTransferred,
                                         (PULONG_PTR)
  
                                           &
PerHandleData,
                                         (LPOVERLAPPED
*)
                                           &lpOverlapped,
                                         INFINITE);

        
// 检查成功的返回,这儿要注意使用这个宏CONTAINING_RECORD
        PerIoData = (LPPER_IO_DATA)CONTAINING_RECORD(lpOverlapped, 
                                                     PER_IO_DATA, 
                                                     Overlapped);

        
// 先检查一下,看看是否在套接字上已有错误发生
        if (0 == BytesTransferred) 
        
{
            closesocket(PerHandleData
->Socket);
            GlobalFree(PerHandleData);
            GlobalFree(PerIoData);

            
continue;
        }


        
// 数据处理
        
// 成功了!!!这儿就收到了来自客户端的数据
        cout << PerIoData->DataBuf.buf << endl;

        Flags 
= 0;

        
// 为下一个重叠调用建立单I/O操作数据
        ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));

        PerIoData
->DataBuf.len = 1024;
        PerIoData
->DataBuf.buf = PerIoData->buffer;
        PerIoData
->OperationType = 0// read
        WSARecv(PerHandleData->Socket,
                
&(PerIoData->DataBuf),
                
1,
                
&RecvBytes,
                
&Flags,
                
&(PerIoData->Overlapped),
                NULL);
    }


    
return 0;
}


//////////////////////////////////////////////////////////////////////////




   当然为了测试,各种异常处理都没有写,大家不要学我哦。
                                                                     
发表于 2005-04-19 13:26 乱石铺街 阅读(9073) | 评论 (11)编辑 收藏

2005年4月15日 #

        近一个月来,论坛上发生了不少大事,牛人们纷纷告别了论坛,偶也附庸一把。不过偶的告别方式多少有点悲壮。本来我是想找个斑竹帮我封几个月的,不过没能如愿。没方法,只得退而求其次,在VC版玩起散分的游戏,一不小心成了“万人景仰”的对象,呵呵,在VC版一抬头就能看到偶的大名。不过也连累了不少好兄弟,在此向他们表示深深的歉意!屈指算来,偶在论坛上混了也差不多半年了,从坛子的高手上学到了不少东西,真是牛人遍地都是阿。当然了,有得必有失,失去的永远留在记忆中。接下来将会进入一个忙碌的夏天,也许秋天就会收获,冬天就会开始漫长的另一种生活方式......

 
发表于 2005-04-15 18:32 乱石铺街 阅读(2879) | 评论 (6)编辑 收藏

2005年4月8日 #

    前两天有个网友问这个问题,我把我的源代码都给他了,他就是调试不明白,费了我好多口舌,他还是没搞定。获取IP协议统计信息
主要有4个API函数,GetIpStatistics,GetIcmpStatistics,GetTcpStatistics,GetUdpStatistics。这些函数产生的
信息和带上-s选项执行Netstat.exe程序时返回的信息一样。看源码吧,都有详细的文字注释。
我决定把源码删掉,贴这种代码太没意思了。
发表于 2005-04-08 13:23 乱石铺街 阅读(1626) | 评论 (2)编辑 收藏

2005年3月26日 #

    大家请勿见笑,我以前使用dynamic_cast这个C++转换操作符从未成功过.我还一直纳闷那,亦不知是何原因.今天一个偶然的机会终于让我找到原因了.
    原因真是很低级阿.只要在Project->Settings中选C/C++那个Tab,然后再Project options中填入/GR即可。我很晕阿!

发表于 2005-03-26 21:40 乱石铺街 阅读(3728) | 评论 (7)编辑 收藏

2005年3月20日 #

    相传文革期间,北京有“四大不要脸”,其中之一就有郭沫若。大家看一看郭沫若写的拍斯大林马屁的诗,要多肉麻就有多肉麻。据郭沫若考证王羲之的《兰亭序》有后人伪造的嫌疑,姑且不论这些,我这次向大家介绍的是天下第二行书---唐朝颜真卿的《祭侄文稿》,这次来个链接,让大家一睹天下第二行书的风采。http://www.wenyi.com/art/shufa/suitang/32.htm 再来一个
http://www.116.com.cn/col/old/like/picture/shufa/files/109437.shtml
    

     颜真卿系行草墨迹,原迹藏台湾故宫博物院。

    《祭侄稿》全称《祭侄季明文稿》,书于唐乾元元年(公元七百五十八年)。麻纸本,行书 纵28.2厘米 横75.5厘米,二十三行,每行十一二字不等,共二百三十四字。铃有“赵氏子昴氏”、“大雅”、“鲜于”、“枢”、“鲜于枢伯几父”、“鲜于”等印。曾经宋宣和内府、元张晏、鲜于枢、明吴廷、清徐乾学、王鸿绪、清内府等收藏,现藏台北故宫博物院。
   《祭侄稿》是颜真卿为祭奠就义于安史之乱的侄子颜季明所作。 唐天宝十四年(775),安禄山谋反,平原太守颜真卿联络其从兄常山太守颜杲卿起兵讨伐叛军。次年正月,叛军史思明部攻陷常山,颜杲卿及其少子季明被捕,并先后遇害,颜氏一门被害30余口。唐肃宗乾元元年(公元七五八年),颜真卿命人到河北寻访季明的首骨携归,挥泪写下这篇留芳千古的祭文。
    元鲜于枢跋语谓:“《祭侄季明文稿》,天下行书第二、” 元陈深日:“《祭侄季明文稿》,纵笔浩放,一泻千里;时出遒劲, 杂以流丽: 或若篆籀, 或若镌刻, 其妙解处,殆若天造 岂非当时注思为文,而于字画无意于工, 而反极工耶?”
    《祭侄稿》作为颜书著名的“三稿(另二稿《争坐位稿》,《告伯父文稿》)之一,曾收入宋、明、清诸代从刻本中,历代效仿者不绝,褒赞不断。 

     《兰亭序》乃王羲之借着游兰亭的雅兴泼墨挥毫而成,《祭侄稿》的创作环境与其截然相反,颜真卿在极其悲痛的心情下一挥而就。读《祭侄稿》,我们仿佛能隐隐感觉到作者的心情。

        


发表于 2005-03-20 11:20 乱石铺街 阅读(2446) | 评论 (2)编辑 收藏

    时常在论坛上看到有人问这个VC操作Word或者Excel有没有书系统地介绍如何去做,有这个必要吗?其实捅破这层窗户纸,你就会恍然大悟,原来是这么回事啊!在此我觉得有必要把我工作中操纵Excel的一点小体会拿出来和大家共享,也许对初学者能有所帮助,高手就不要看了。操作Word请看牛人yingkou的BLOG(http://blog.vckbase.com/yingkou) .基本步骤如下

        一、Excel的层次结构   
        Application

               Workbooks

                   Workbook

                    ......

               Worksheets

                   Worksheet

                    ......

               Range

                   Font

                   Borders

                    ......

            .......


        二、插入类型库

        1、在一个已有的MFC工程按Ctrl + W 弹出ClassWizard对话框。
        2、Add Class...\From a type Library... 在 Office 目录中,找到你想使用的Excel类型库(Offce2000下,此目录在C:\Program Files\Microsoft Office\Office\EXCEL9.OLB)。选择EXCEL9.OLB此类型文件。
        3、在弹出的对话框中选择要添加的类,具体选那些类要根据实际情况而定。当然你也可以全选。

          三、基本操作

           当你要选用Excel生成报表时,表的结构可能有固定的部分,这时做一个模板,这样可以减少编码的负担。加载Excel模板的代码如下。
        

    _Application  ExcelApp;           // 定义Excel应用程序
       Workbooks          wbsBooks;
      _Workbook          wbBook;
      Worksheets         wssSheets;
      _Worksheet         wsSheet;
      Range        rngXls;
      FontXls            font;               // 字体
      BordersXls         border;         // 边框
      // 初始化Com
    if (::CoInitialize( NULL ) == E_INVALIDARG)
  
{
              AfxMessageBox(_T(
"初始化Com失败!"));
    }


    
// 创建Excel2000服务器(启动Excel)
    if ( !ExcelApp.CreateDispatch(_T("Excel.Application"), NULL))
  
{
        AfxMessageBox(_T(
"创建Excel2000服务失败!"));
        ::CoUninitialize();

    }
   
       ExcelApp.SetVisible(FALSE);  // 隐藏
       
     CString strPath;
    strPath 
+= "C:\\template.xlt"//    模板的路径    
    CFileFind filefind;
    
if!filefind.FindFile( strPath ) )
  
{
        AfxMessageBox( 
"没有找到模版文档,请其查找" );
        
        CFileDialog dlg (TRUE,
                                    NULL,                                  
                                    NULL,
                                    OFN_HIDEREADONLY
|OFN_OVERWRITEPROMPT,
                                   "模版||*.xlt||",
                                   NULL );
        
        
if (IDOK == dlg.DoModal())
     
{
            strPath 
= dlg.GetPathName(); 
        }

    }


    COleVariant vOptional( (
long)DISP_E_PARAMNOTFOUND, VT_ERROR );

    
try
  
{
        wbsBooks.AttachDispatch(ExcelApp.GetWorkbooks(), TRUE);
        wbBook.AttachDispatch(wbsBooks.Add(COleVariant(strPath)), TRUE );

        wssSheets 
= wbBook.GetWorksheets();
        wsSheet 
= wssSheets.GetItem(_variant_t("Sheet1")); // Get Sheet1
          wsSheet.SetName( "Your Sheet" );    // 改名
          // 得到全部Cells,此时,rngXls 是cells的集合
          rngXls = wsSheetAcc.GetCells();      
    }

    
catch (CException e)
  
{
        AfxMessageBox( 
"" )
    }
       
        我们知道在Excel中每个单元格可以用A1,A2,C3的形式来表示。譬如获得A1到C5之间单元格集可以这样实现,rngXls = rngXls.GetRange( COleVariant(_T(“A1“)),COleVariant(_T(“C5“)) );但是我们习惯用坐标形式如(1,1),(2,1)来表示每个单元格,在上述操作中,就没有办法用我们习惯的坐标的形式实现。它们之间如何转换那?这个用如下函数实现.
       
// Converts (row,col) indices to an Excel-style A1:C1 string in Excel
void CPrintInExcel::IndexToString( int row, int col, char* strResult )
{
    
if( col > 26 )
  
{
         sprintf( strResult,
"%c%c%d",'A' + (col-1)/26-1,'A' + (col-1)%26,row );
    }

    
else
  
{
         sprintf( strResult,
"%c%d"'A' + (col-1)%26,row );
    }

}

         有了这个函数,操作Excel就方便多了。今天就写到这儿了,有空再继续。
发表于 2005-03-20 10:30 乱石铺街 阅读(11335) | 评论 (29)编辑 收藏

2005年3月16日 #

  哈哈,标题当然是吹嘘了,這一點和我的偶像有點相似。天下第一行书,当仁不让,就是王羲之的兰亭序了,虽然我们现在已无福看到其真迹了,只能怨李世民这小子拿它当陪葬品了。其全文如下
    永和九年,岁在癸丑,暮春之初,会于会稽山阴之兰亭,修禊事也。群贤毕至,少长咸集。此地有
崇山峻岭,茂林修竹;又有清流激湍,映带左右,引以为流觞曲水,列坐其次。虽无丝竹管弦之盛,一觞一咏,亦足以畅叙幽情。是日也,天朗气清,惠风和畅,仰观宇宙之大,俯察品类之盛,所以游目骋怀,足以极视听之娱,信可乐也。夫人之相与,俯仰一世,或取诸怀抱,晤言一室之内;或因寄所托,放浪形骸之外。虽取舍万殊,静躁不同,当其欣于所遇,暂得于己,快然自足,不知老之将至。及其所之既倦,情随事迁,感慨系之矣。向之所欣,俯仰之间,已为陈迹,犹不能不以之兴怀。况修短随化,终期于尽。古人云:“死生亦大矣。”岂不痛哉!每览昔人兴感之由,若合一契,未尝不临文嗟悼,不能喻之于怀。固知一死生为虚诞,齐彭殇为妄作。后之视今,亦犹今之视昔。悲夫!故列叙时人,录其所述,虽世殊事
异,所以兴怀,其致一也。后之览者,亦将有感于斯文。
    《兰亭序》表现了王羲之书法艺术的最高境界。作者的气度、凤神、襟怀、
情愫,在这件作品中得到了充分表现。古人称王羲之的行草如“清风出袖,明月入怀”,堪称绝妙的比喻

    《兰亭序》可以說是我的至愛,每天閒暇時都要拿出來細細把玩,興之所至,拿出鋼筆臨摹一番,徜徉其中,可以使你忘記所有的苦惱與不快;可以充分體會到孤獨的愉悅的真諦;心中不免生氣一股獨與天地相往來的豪邁氣勢。------自己吹噓。 

发表于 2005-03-16 21:44 乱石铺街 阅读(2472) | 评论 (0)编辑 收藏

    延迟加载的D L L是个隐含链接的D L L,它实际上要等到你的代码试图引用
D L L中包含的一个符号时才进行加载。延迟加载的D L L在下列情况下是非常有用的:
    • 如果你的应用程序使用若干个D L L,那么它的初始化时间就比较长,因为加载程序要将所有需要的D L L映射到进程的地址空间中。解决这个问题的方法之一是在进程运行的时候分开加载各个D L L。延迟加载的D L L能够更容易地完成这样的加载。
    • 如果调用代码中的一个新函数,然后试图在老版本的系统上运行你的应用程序,而该系统中没有该函数,那么加载程序就会报告一个错误,并且不允许该应用程序运行。你需要一种方法让你的应用程序运行,然后,如果(在运行时)发现该应用程序在老的系统上运行,那么你将不调用遗漏的函数。例如,一个应用程序在Windows 2000上运行时想要使用P S A P I函数,而在Windows 98上运行想要使用To o l H e l p函数(比如P r o c e s s 3 2 N e x t)。当该应用程序初始化时,它调用G e t Ve r s i o n E x函数来确定主操作系统,并正确地调用相应的其他函数。如果试图在Windows 98上运行该应用程序,就会导致加载程序显示一条错误消息,因为Windows 98上并不存在P S A P I . d l l模块。同样,延迟加载的D L L能够使你非常容易地解决这个问题。
                                  ------摘自<<Windows核心编程>>
    下面我以简单的代码来展示延迟加载DLL的实现.
  

#include <TlHelp32.h>
#include 
<shlwapi.h>
#pragma comment(lib, 
"shlwapi.lib")

#include 
<delayimp.h>
 // 这个链接开关告诉链接程序将一个特殊的函数--delayLoadHelper嵌入到
 // 你的可执行模块。
#pragma comment(lib, 
"delayimp.lib")

// 延迟加载
#pragma comment(linker, "/Delayload:"shlwapi.dll"")

// 允许卸载DLL
 // __FUnloadDelayLoadedDLL(_T("shlwapi.dll"));可以用此函数将你加载
 // 的DLL卸载掉
 // D e l a y : u n l o a d链接程序开关告诉链接程序将另一个节放入文
 // 件中。该节包含了你清除已经调用的函数时需要的信息,这样它们就可以
 // 再次调用- - d e l a y L o a d H e l p e r函数。当调用
 // - -F U n l o a d D e l a y L o a d e d D l l时,你将想要卸载的延
 // 迟加载的D L L的名字传递给它。该函数进入文件中的未卸载节,并清除
 // D L L的所有函数地址,然后
 // - - F U n l o a d D e l a y L o a d e d D l l调用
 // F r e e L i b r a r y,以便卸载该D L L。
#pragma comment(linker, "/Delay:unload")

void IsModuleLoaded(TCHAR * pszModuleName)
{
    HMODULE hModule 
= GetModuleHandle(pszModuleName);

    TCHAR szName[MAX_PATH] 
= {0};
    _stprintf(szName,
              _T(
"Module "%s" is %sloaded."),
              pszModuleName,
              (hModule 
== NULL) ? _T("not ") : _T(""));
    ::MessageBox(NULL,
                 szName,
                 _T(
"提示"),
                 MB_OK);
}


void GetProcessID(LPTSTR pszProcessName, DWORD& th32ProcessID)
{
    HANDLE hSnapshot 
= NULL;
                       
    __try
    
{
        hSnapshot 
= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        
if (INVALID_HANDLE_VALUE == hSnapshot)
       
{
            __leave;
        }


        PROCESSENTRY32 pe;
        ZeroMemory(
&pe, sizeof(PROCESSENTRY32));
        pe.dwSize 
= sizeof(PROCESSENTRY32);

        BOOL bProcess 
= Process32First(hSnapshot, &pe);
        
while (bProcess)
        
{
            
if (pe.szExeFile == StrStrI   
                  (pe.szExeFile, pszProcessName))
            
{
                th32ProcessID 
= pe.th32ProcessID;
                
break;
            }


            bProcess 
= Process32Next(hSnapshot, &pe);
        }


        
if (!bProcess)
        
{
            __leave;
        }

    }

    __finally
    
{
        
if (INVALID_HANDLE_VALUE != hSnapshot)
        
{
            CloseHandle(hSnapshot);
        }

    }

}

用如下代码测试即可
  
    IsModuleLoaded(_T("shlwapi"));
    DWORD dwProcessID;
    GetProcessID(_T(
"csrss.exe"
), dwProcessID);
    std::cout 
<< dwProcessID <<
 std::endl;
    IsModuleLoaded(_T(
"shlwapi"));
 
当程序初始化时并未将DLL映射到进程的地址空间,直到调用函数GetProcessID时,由于其中要导出shlwapi.dll的函数StrStrI,此时该DLL被加载,并且一直存在于进程的地址空间中。
发表于 2005-03-16 21:04 乱石铺街 阅读(3633) | 评论 (2)编辑 收藏