??xml version="1.0" encoding="utf-8" standalone="yes"?>99久久er这里只有精品18,亚洲精品tv久久久久久久久,久久久久人妻一区精品色http://www.shnenglu.com/justin-shi/category/6153.html<font>&nbsp;</font> zh-cnSun, 20 Dec 2009 01:20:00 GMTSun, 20 Dec 2009 01:20:00 GMT60技术备忘录http://www.shnenglu.com/justin-shi/archive/2009/12/18/103441.htmlq幽q幽Fri, 18 Dec 2009 01:20:00 GMThttp://www.shnenglu.com/justin-shi/archive/2009/12/18/103441.htmlhttp://www.shnenglu.com/justin-shi/comments/103441.htmlhttp://www.shnenglu.com/justin-shi/archive/2009/12/18/103441.html#Feedback0http://www.shnenglu.com/justin-shi/comments/commentRss/103441.htmlhttp://www.shnenglu.com/justin-shi/services/trackbacks/103441.html转一些从shell32.dll导出的函?br>
外壳对话?br>
外壳对话框的U密

常见的Windows的通用对话框被装在Comdlg32.dllQ这l我们的~程提供了很大的便利。但它还不够完整Q我们在pȝ里经常能看到大量的可重复使用的对话框,但在Windows的文档里你却找不到它们的调用Ҏ(gu)。而如果我们自己去做这L(fng)界面是非常费时费力的而且也是没有必要的,因ؓ(f)q些对话框实际上很容易得到。这里我要介l一些已l众所周知或不知的对话框,它们可以应用在我们的E序中ɽE序昑־非常友好和专业?br>
览文g夹对话框



?.23

大多数DelphiE序员都知道如何使用VCL的TOpenDialog控g来让用户览要打开的文件。然而有时你可能只想让用户选择文g夹而不是特定的文gQwindows已经提供了一个这L(fng)对话框如?.23所C。我们可以通过公开的函数SHBrowseForFolder来调?(q个函数定义在ShlObj单元)Q函数定义如下:(x)

function SHBrowseForFolder(var BrowseInfo: TBrowseInfo): PItemIDList; stdcall;

q个函数只有一个参敎ͼ但这个参数是一个比较复杂的记录cd

    TBrowseInfo = packed record

      hwndOwner: HWND;

      pidlRoot: PItemIDList;

      pszDisplayName: PChar;

      lpszTitle: PChar;

      ulFlags: UINT;

      lpfn: TFNBFFCallBack;

      lParam: LPARAM;

      iImage: Integer;

    end;


hwndOwner数据成员包含对话框的父窗体的H口句柄Q可以把它设?。PIdlRoot数据成员指向一个PIDL的指针对应于对话框初始化时的根目录。指定了PIdlRoot后,只有根目录?qing)它的子目录会(x)出现在对话框中。可以设定它为nilQ这时缺省的根目录是桌面QpszDisplayName 数据成员指向一个缓冲区可以用来储存被用户选中的文件名Q缓冲区的大至ؓ(f)MAX_PATH q个常数那么大,否则遇到特别长的文g名会(x)溢出。lpszTitle 数据对象指向一个以nulll尾的字W串Q字W串作ؓ(f)对话框的标题来显C。注意标题不要太长,否则昄时会(x)被截断。ulFlags 标志数据对象用来限制在对话框中显C的文g夹类型。可以设定它?或下列值的l合Q?br>
    //在对话框中会(x)包含一个状态区Q回调函数可以通过向对话框发送消息来讑֮状?br>
BIF_STATUSTEXT

    //只允?dng)R择标准文gpȝQ若选了非标准的文g夹如打印机,认按钮?x)变?br>
    BIF_RETURNONLYFSDIRS   = $0001;

    //不选择|络文g?br>
    BIF_DONTGOBELOWDOMAIN  = $0002;

    // l状态条留出I白

    BIF_STATUSTEXT         = $0004;

    // 只选择文gpȝ的上U目?br>
    BIF_RETURNFSANCESTORS  = $0008;

    //只选择计算?br>
    BIF_BROWSEFORCOMPUTER  = $1000;

    //只选择打印?br>
    BIF_BROWSEFORPRINTER   = $2000;

    //包括文g也可以?br>
    BIF_BROWSEINCLUDEFILES = $4000;


注意Q如果你惛_话框昄lpszTitle里的用户定制的状态条信息Q必d?BIF_STATUSTEXT标识。Lpfn数据对象是一个回调函数类型的指针Q函数类型如下:(x)

    TFNBFFCallBack = function(DialogHandle: HWND;

      MessageID: UINT; PIDL: PItemIDList; Data: LPARAM):Integer; stdcall;


q是一个回调函敎ͼ可以用来在同用户交互时控制和更新对话框的昄。如果你不想控制对话框,可以把它设成nilQlParam 数据对象允许你在回调函数中以参数l(f)pfn形式q回一个指针(通常我们用它来返回对象)Q当然也可以把它设成?。IImage数据成员不需要设|,因ؓ(f)它是用来接收pȝ中同文g夹相关的图标列表索引的,我们q里讑֮??br>
SHBrowseForFolder函数q回一个唯一的指向被选择的文件夹的PIDL。如果文件夹是一个传l的文g对象的话Q可以用函数SHGetPathFromIDList把PIDL转换为真实的目录。同Ӟ作ؓ(f)调用者,必须负责释放被返回的item identifier listQ用IMalloc COM 接口来释放?br>
注意Q不要用FreeMem或其他方法来释放 PIDL Q这是因为外壳的内存理是独立的Q只能用IMalloc来释放?br>
现在我们已经可以昄对话框了Q那让我们更深入一步看看如何能够控制对用户动作的反应,q就要用C回调函数 TFNBFFCallBack?注意回调函数的意思就是,你只是实C它,pȝq道什么时候去调用它,好比一个守株待兔的例子?br>
DialogHandle参数代表对话框窗口句柄。通常可以用这个句柄给对话框发消息QMessageID 参数q不是一个TMessage l构的记录,它是对话框通过回调函数发给用户消息的,它可以是下面两个|(x)

    BFFM_INITIALIZED = 1;   // 对话框将要显C?br>
    BFFM_SELCHANGED  = 2; // 用户选中了某?


PIDL参数包含其他的额外信息。如果MessageID ?BFFM_INITIALIZEDQPIDL等于nil。如果MessageID是BFFM_SELCHANGEDQPIDL的值将是一个PIDL 对应于用户选择的文件夹。Data 参数包含用户付给TbrowseInfo记录中的Lparam数据成员的|通常可以传递一个对象指针。下面是一个简单的回调函数的例子:(x)

    function BrowseForFolderCallback(DialogHandle: HWND;

      MessageID: UINT; PIDL: PItemIDList; Data: LPARAM):

      Integer;

    begin

      //响应对话框的通知消息

      case (MessageID) of

        BFFM_INITIALIZED:

          DialogInitialized(DialogHandle, Data);

        BFFM_SELCHANGED:

          HandleNewSelection(DialogHandle, PIDL, Data);

      end;

      Result := 0; // 总返?.

    end;


在回调函数里Q可以根据用L(fng)输入发送三个用L(fng)消息l对话框Q下面是消息ID:

    // 改变对话框的状态信?br>
    BFFM_SETSTATUSTEXT = WM_USER + 100;

    //控制定按钮失效与否

    BFFM_ENABLEOK      = WM_USER + 101;

    //改变选择的文件夹

    BFFM_SETSELECTION  = WM_USER + 102;


通常Q这些消息发送给对话框之根据用L(fng)选择更新昄Q当然你也可以发送其他的消息l对话框Q比如可以发送WM_SETTEXT消息来改变对话框的标题?br>
下面是一个发送消息的例子Q见?.11Q:(x)

PostMessage(DialogHandle, BFFM_SETSELECTION, True, LPARAM(PChar (NewPath)));

?.11

Message ID WParam LParam
BFFM_SETSTATUSTEXT 没有使用 一个指向新的状态信息的Pchar
BFFM_ENABLEOK 没有使用 True使得认按钮有效QFalse无效
BFFM_SETSELECTION 如果Lparam是\径则为TrueQ若Lparam是PIDL则ؓ(f)False 指向被选择的文件\径或PIDL的Pchar



另外要提到的是,Delphi也提供了对这个函数的装Q那是SelectDirectory函数?br>
关于对话?/strong>

通常我们都要在自qE序里加上一个关于对话框来显CZ些版本信息等{,W(xu)indows为我们提供了一个标准的对话框如?.24所C,可以在一定范围内对它定制Q不q它只适合昄单的标识和文本(我觉得用处极)。我们可以通过函数ShellAbout来调用它Q声明在ShellAPI单元里)Q函数定义如?

    function ShellAbout(Owner: HWND; ApplicationName: PChar;

      OtherText: PChar; IconHandle: HICON): Integer; stdcall;


Owner参数标识了拥有对话框的父H体句柄Q通常设ؓ(f)0Q表明没有父H体。ApplicationName 参数包含对话框的标题Q字W串中可以包?#8220;#”字符Q它能v到分割符的作用。这U情况下Q函C(x)把分割符前的字符串作为标题栏Q分割符后的部分作ؓ(f) "Microsoft"字符串后的第一行。OtherText参数包含了打显C在Microsoft 版本和版权信息后的字W串。IconHandle 参数标识了打显C在对话框上的图标标识,如果设ؓ(f)0Q函C(x)昄Windows~省的图标?br>


?.24




?.25

格式化对话框

SHFormatDrive函数?x)显CZ个格式化对话框,如图2.25所C,它是一个半公开的函数。但现在它不在微软的SDK里。然而微软承认它的存在ƈ把它从Shell32.dll里用名字公开声明QDelphi中的函数定义如下Q?br>
    function SHFormatDrive(Owner: HWND; Drive: UINT;

      FormatID: UINT; OptionFlags: UINT): DWORD; stdcall;


Owner参数标识拥有对话框的H体句柄Q文档中推荐不要设ؓ(f)0Q但实际上好像没什么媄响。Drive参数是用来标识打格式化的驱动器的数|它是?为底的,从A开?A:=0,B:=1依此cL。FormatID 参数允许我们指定一个格式化的模板,通常情况下,只要赋gؓ(f)SHFMT_ID_DEFAULT可以了。OptionFlags 参数是一个选项掩码Q来定格式化的选项。当前有两个选项Q?br>
    SHFMT_OPT_FULL    = $0001; // 快速格式化

    SHFMT_OPT_SYSONLY = $0002; // 复制pȝ文g


如果函数调用p|Q会(x)q回下列错误中的一U来表明错误原因Q错误常数如下:(x)

    SHFMT_NOFORMAT = $FFFFFFFD;   // 驱动器无法格式化

    SHFMT_CANCEL   = $FFFFFFFE;   //格式化被取消?br>
    SHFMT_ERROR    = $FFFFFFFF; //其他错误


Windows NT ?WideChar

在进一步研I未公开的函数前, 我们必须清楚一点,对于未公开的函数来说以nulll尾的字W串cd参数大多数被声明为类型指针而不是PChar。这有点像陷阱,但必L认这是事实。在Win 9X上所有的字符串类型参数声明ؓ(f)PAnsiCharQ而在Windows NT上被声明为PWideChar。如果你想你的应用程序适应所有^収ͼ你必考虑两种情况Q在q行时要判断q_cdQ这是很讨厌的,但这也是使用未公开的API的代仗?br>
选择图标对话?/strong>



?.26

我们要讨论的W一个完全未公开的函数是PickIconDlg。如?.26所C个函C(x)昄一个对话框Q用户可以用来从文g中选择一个图标资源。它通常是用文gcd~辑器来兌图标和某一文gcd的,也会(x)在快h式对话框中被调用来修改快h式的图标。这个函CShell32.dll 用?2来公开出来Q函数定义如下:(x)

    function PickIconDlg(Owner: HWND; FileName: Pointer;

      MaxFileNameChars: DWORD; var IconIndex: DWORD):LongBool; stdcall;


Owner参数和上面的意义cM。FileName 参数指向一个缓冲区Q包含了被浏览图标的文g名,~冲不小于MAX_PATHQ?。MaxFileNameChars 指定字符数量大小。IconIndex 常数是以0为底的图标烦引,当对话框打开时会(x)把焦点定在IconIndex对应的图标上Q函数返回后QIconIndex指向最后被选的图标索引。如果用L(fng)了取消按钮,函数q回False?br>
q行E序对话?/strong>




?.27

RunFileDlg函数是相当灵zȝQ如?.27所C就是调用开始菜单的q行子菜单后?x)显C的对话框,我们通过?1把它从Shell32.dll暴露出来。下面是函数声明Q?br>
    procedure RunFileDlg(Owner: HWND; IconHandle: HICON;

      WorkPath: Pointer; Caption: Pointer; Description: Pointer; Flags: UINT); stdcall;


Owner参数׃用再说了。IconHandle参数是显C在对话框上的图标句柄,如果为nilQ缺省的icon会(x)使用。WorkPath 参数指向一个字W串来指定应用程序运行的工作路径?Title 参数指向作ؓ(f)对话框标题的字符Ԍ如果为nilQ就使用~省的标题。Description 参数指向一个描q字W串Q主要是告诉用户如何dQ可以设为nilQ这时用缺省的描述?Flags参数用一l位掩码来设定对话框的属性。下面是定义Q?br>
    RFF_NOBROWSE      = $01;   // Ud览按钮

    RFF_NODEFAULT     = $02;   // 无缺省的选项

    RFF_CALCDIRECTORY = $04;   // 由文件名定工作路径

    RFF_NOLABEL       = $08;   // L~辑框标{?br>
    RFF_NOSEPARATEMEM = $20; // L在单独的内存I间q行的复选框 (只对NT有效)


q个对话框一个很好的Ҏ(gu)是允许你控制用户可以运行的应用E序。当用户选择了确认按钮,对话框的父窗体会(x)发送一个通知消息来传递将要运行的E序信息。通知消息是一?WM_NOTIFY消息Q它的通知代码讑֮为RFN_VALIDATE (-510)Q然后lParam指向一?TNM_RunFileDlg记录。定义如下:(x)

    TNM_RunFileDlg = packed record

      hdr: TNMHdr;

      lpFile: Pointer;

      lpDirectory: Pointer;

      nShow: LongBool;

    end;


hdr数据对象是TNMHdrcdQ它是一U标准的Windows数据cdQ每个WM_NOTIFY消息的lParam参数都会(x)指向q个数据成分。同时根据不同的消息cdQ可能一些额外的数据跟在记录后面Q标准的TNMHdr记录定义如下Q?br>
    TNMHdr = packed record

      hwndFrom: HWND;

      idFrom: UINT;

      code: UINT;

    end;


记录中的hwndFrom包含发送消息的H口句柄QidFrom则包含发送消息的控g标示W,code 中包含标识被发送的消息的通知代码?br>
在TNMHdr记录后被打包的额外数据包含三个数据成分:(x)LpFile指向一个包含将要运行的文g的\径字W串QLpDirectory指向正在q行E序的工作目录字W串Q最后,nShow 用来指定要q行的应用程序是否可见?br>
对于本文中特定的消息Q只对TNMHdr记录中的Code感兴,通过验Code可以保我们收到一个运行文件校验消息,同时使我们可以存取额外的TNM_RunFileDlg数据成员。当TNMHdr记录中的code{于RFN_VALIDATE(-510)Ӟ可以获得一个TNM_RunFileDlg记录。下面是校验消息的代码:(x)

    var

      FileToRun: String;

      ...

      if TheMessage.Msg = WM_NOTIFY then

        if PNMHdr(TheMessage.LParam).code = RFN_VALIDATE then

          WideCharToStrVar(PNM_RUNFILEDLG(

          TheMessage.LParam).lpFile, FileToRun);

    ...


注意只有当我们已l检验TNMHdr的Code为RFN_VALIDATE后,才映LParam 参数为PNM_RunFileDlgcd?br>
通知消息的返回值决定了应用E序是否能够q行Q下面是可能的|(x)

    RF_OK     = $00; //允许E序q行

    RF_CANCEL = $01;   //取消操作Q关闭对话框

    RF_RETRY  = $02; //取消操作Q对话框仍然打开


查找文g对话?/strong>




?.28

调用查找文g对话框的函数是SHFindFilesQ对话框如图2.28所C。它是从Shell32.dll按烦引?0公开出来?

    function SHFindFiles(SearchRoot: PItemIDList;

      SavedSearchFile: PItemIDList): LongBool; stdcall;


SearchRoot 参数允许从一个特定的文g夹开始查找,同在资源理器中在文件夹上用右键点击查找菜单的效果是一L(fng)。如果设为nilQ那么查找是从桌面开始的?SavedSearchFile 参数让你指定一个以前查询保存的查找{略文gQ?.fnd文gQ,Ҏ(gu)以前的设定来查找Q若不需要的话可以设定ؓ(f)nil。如果你指定了一个非I值的SearchRoot PIDLQ那么在调用完SHFindFiles后必负责释放掉。但是有点奇怪的是,如果你指定了一个非I的SavedSearchFile PIDL参数Q函数成功调用的话,你不能去释放q个 PIDLQ否则会(x)出错Q但如果调用p|了的话,你必释攑֮?br>
同大多数对话框函C一Pq个函数是非模态的Q也是pȝ在另外一个独立的U程中启动对话框Q然后立卌回,对话框会(x)在你的程序结束后自动关闭。也是说你没有M直接的方法来告诉用户如何使用查找到的l果Q所以要想知道用h到的文g的话Q最好是让你的程序支持文件拖放,以便让用h扑ֈ的文件拖攄你?br>
查找?sh)脑对话?/strong>

同SHFindFiles比较接近的一个函数是SHFindComputerQ这个函数调用的l果同开始菜单上查找?sh)脑菜单调用的结果是一L(fng)。它的参数同SHFindFiles完全一P不同之处在于它完全忽略传递给它的参数Q很昄是保留v来ؓ(f)了将来扩展的需要。这里我们只要把参数都设成nil可以了Q另外注意这个对话框也是非模态的?SHFindComputer 是从Shell32.dll 以烦引号91公开出来的:(x)

    function SHFindComputer(Reserved1: PItemIDList;

      Reserved2: PItemIDList): LongBool; stdcall;



查找文g对话?/strong>

通过调用GetFileNameFromBrowse函数可以调出q个对话框,不过说实在的Q它实际上只是GetOpenFileName 函数的简单封装。而我们常用的TOpenDialog控g也是对GetOpenFileName 函数装Q这个函数我们很会(x)ȝ接用它。不q还是写出来吧,它是从Shell32.dll里按索引?3公开出来的:(x)

    function GetFileNameFromBrowse(Owner: HWND;

      FileName: Pointer; MaxFileNameChars: DWORD;

      InitialDirectory: Pointer; DefaultExtension: Pointer;

      Filter: Pointer; Caption: Pointer): LongBool; stdcall;




?.29

大多数参数对应于OPENFILENAME l构的成员。Owner参数我想׃用再重复了, FileName 参数指向一个初始化对话框编辑控制文件名的缓冲区Q函数返回后FileName包含被选择的文件\径,它的大小一般设成MAX_PATHQ?那么大。MaxFileNameChars 参数用来指定FileName~冲区的大小?InitialDirectory参数指向对话框初始化的目录名Q但如果FileName参数被指定了QInitialDirectory׃(x)被忽略而用FileName参数中的路径。DefaultExtension参数指向一个包含要搜烦的缺省扩展名的字W串。Filter参数指向一个以nulll尾的可以用来在下拉列表中限定文件类型的qo(h)字符丌ӀCaption参数指向对话框标题字W串?br>
如果用户选择了一个要打开的文Ӟ函数q回TrueQ当有错误发生,用户选择取消按钮或关闭对话框的话?x)返回False?br>
外壳对象属性对话框

另一个未公开的对话框函数是SHObjectPropertiesQ它可以用来昄外壳对象的属性,比如驱动器、文件夹或文件等Q运行效果如?.29所C。函数可以从Shell32.dll中按索引?78公开出来Q定义如下:(x)

    function SHObjectProperties(Owner: HWND; Flags: UINT;

      ObjectName: Pointer; InitialTabName: Pointer):LongBool; stdcall;


Flags参数用来指定ObjectName参数对应对象的类型,它可以是下列标识Q?br>
    //打印?br>
    OPF_PRINTERNAME = $01;

    //路径

    OPF_PATHNAME    = $02;


ObjectName参数指向一个包含\径名的字W串或是要显C属性的打印机名。如果打印机是本地的Q可以用实际的打印机名Q如果是|络打印机,需要用完整的UNC样式名称Q比如\\COMPUTERNAME\PRINTERNAME。InitialTabName参数指向一个属性对话框中页面名U字W串Q用来指定要昄的缺省页面。如果InitialTabName参数为nilQ或不匹配Q何页面的名称Q第一个属性页面将?x)被昄?br>
如果函数调用成功?x)返回TrueQ如果失败会(x)q回False。要惌得扩展的错误信息Q可以调用API函数GetLastError。要注意的是q个对话框是非模态的Q类g查找文g对话框,所以函C被调用,p定会(x)昄一个对话框Q同时我们没有办法知道用户什么时候关闭了对话框?br>
映射|络驱动对话?/strong>





?.30

?.30昄了映网l驱动器的对话框Q我们通过SHNetConnectionDialog函数调用它(win 9x和W(xu)in NT上都支持Q,它可以按索引?60从Shell32.dll暴露出来Q函数定义如下:(x)

    function SHNetConnectionDialog(Owner: HWND;

      ResourceName: Pointer; ResourceType: DWORD): DWORD; stdcall;


SHStartNetConnectionDialog函数也会(x)昄同样的对话框Q但它显C的对话框是非模态的Q同时只在NT上才支持。它可以按烦引?15从Shell32.dll中公开出来Q函数定义如下:(x)

    function SHStartNetConnectionDialog(Owner: HWND;

      ResourceName: PWideChar; ResourceType: DWORD):DWORD; stdcall;


上面两个函数的参数完全相同。其中ResourceName参数指向一个要q接的网l资源UNC路径名。指定了q个参数的话Q显C的对话框中被预讄q接资源׃可改变了。如果这个参Cؓ(f)nilQ则在对话框中用户可以指定要q接的资源。ResourceType参数可以是下面的g一QRESOURCETYPE_DISK或RESOURCETYPE_PRINT。它的不同将?x)生成不同的对话框。参Cؓ(f)RESOURCETYPE_DISK允许我们为网l驱动资源指定一个盘W,另一个参数允许我们映一个ƈ行口名比如LPT2Z个网l打印机。然而,不知道ؓ(f)什么RESOURCETYPE_PRINT参数在NT上无效?br>



?.31

如果函数调用成功的话Q返回值是NO_ERRORQ如果用户取消的对话框,则返?-1($FFFFFFFF)Q如果调用失败则q回其他的错误代码,具体错误信息可以用GetLastError API调用获得?br>
关闭pȝ对话?/strong>

ExitWindowsDialog和RestartDialog函数可以用来昄关闭和重启系l对话框Q如?.31Q,它们同公开的ExitWindowsEx API函数没有什么太大的不同Q但在其q程中都?x)生一个对话框。ExitWindowsDialog函数可以按烦引?0从Shell32.dll中公开出来QRestartDialog函数的在Shell32.dll中的索引值则?9Q两个函数的定义如下Q?br>
    procedure ExitWindowsDialog(Owner: HWND); stdcall;

    function RestartDialog(Owner: HWND; Reason: Pointer; ExitType: UINT): DWORD; stdcall;


对ExitWindowsDialog函数来说Q对话框好像q不使用Owner参数作ؓ(f)父窗口,在Windows 95上,当操作成功的话ownerH口?x)收C个WM_QUIT消息。在Windows NT上,owner H口Ҏ(gu)不被使用。同时这个函数没有返回|所以没有办法知道用户选择了什么操作以?qing)操作是否被取消了?br>
RestartDialog函数更有用一些,当我们修改了pȝ的设|,q希望重新启动系l修改生效的时候可以用这个函数。Reason参数指向一个要昄在对话框中的字符Ԍ用来解释关闭pȝ的原因。ExitType参数指定关闭cdQ可以用ExitWindowsEX函数使用值的一个子集及(qing)额外的几个新|下面是它们的完全列表Q?br>
    EWX_LOGOFF        = $00;

    EWX_SHUTDOWN      = $01;

    EWX_REBOOT        = $02;

    EW_RESTARTWINDOWS = $42;

    EW_REBOOTSYSTEM   = $43;

    EW_EXITANDEXECAPP = $44;


如果用户选择执行关闭操作Q函数返回IDYESQ否则返回IDNO?br>
要注意的是显C在对话框中的原因字W串后M(x)跟着一个系l缺省提供的字符串用来显C确认信息,所以应该在我们的Reason字符串后附上I格或回车换行字W。另外返回g能用于确定操作的成功性,它只表明用户的选择Q如果重启操作由于某些原因失败了Q返回g然是IDYES。同时要注意的是要想调用成功Q用戯必须有SE_SHUTDOWN_NAME权限Q在NT上)?br>
~少内存对话?/strong>

SHOutOfMemoryMessageBox是一个未公开的函敎ͼ当系l内存不x可以用来昄标准的外壳信息对话框Q它在Shell32.dll中的索引值是126Q函数定义如下:(x)

    function SHOutOfMemoryMessageBox(Owner: HWND;

      Caption: Pointer; Style: UINT): Integer; stdcall;


它会(x)调用MessageBox APIQ同时传?个标准的参数和ERROR_OUTOFMEMORY错误消息。Caption参数指向对话框标题字W串。如果Caption为nilQ父H口的标题就?x)被使用。Style参数可以被设|ؓ(f)LMessageBox函数使用的MB_XXX常数的组合,通常讄它ؓ(f)MB_OK或MB_ICONHAND。函数调用返回值参见SDK中MessageBox函数说明?br>
当MessageBox函数被调用时QMB_SETFOREGROUND标识?x)被d到Style参数中,但如果第一ơ调用失败了的话QMessageBox函数?x)被再次调用Q这ơMB_SYSTEMMODAL 标识?x)被d到Style参数中。MB_SYSTEMMODAL同MB_ICONHAND标识l合后会(x)忽略内存状况来显C消息对话框。当内存实不Ӟ函数不会(x)昄M东西Q然而它仍然?x)返回MessageBox函数调用l果。所以我们可以根据返回值判断函数是否调用成功了?br>
I间不对话?/strong>




?.32

另一个资源相关的函数是SHHandleDiskFullQ它?x)显C磁盘不的信息对话框(如图2.32Q。我们可以在׃没有_盘I间时导致程序无法运行的条g下调用这个函敎ͼ调用后,如果回收站中有什么东西没有删除的话,对话框允许用hI回收站来释攄盘空间。它在Shell32.dll中的索引gؓ(f)185Q函数的定义如下Q?br>
    procedure SHHandleDiskFull(Owner: HWND; Drive: UINT); stdcall;


Drive参数用于指定?为底的驱动器盘符?代表A:\Q?代表B:\Q依此类推。这个函数的应用比较困难Q因为当回收站中没有M东西时对话框不会(x)昄Q同时也没有Mq回DC对话框是否昄Q还无法知道用户的操作,比如它是否真的清IZ。看h比较可行的应用只能是E序自行监视盘剩余I间Q只是用这个对话框作ؓ(f)一个快速修复的工具?br>
一般外x息对话框

ShellMessageBox函数仅仅是一个对MessageBox函数的简单封装函敎ͼ它允怋用字W串资源标识W或标准的以nulll尾的字W串Q同时还允许加入支持格式化ForamtMessage函数的控制符。ShellMessageBox函数在Shell32.dll中的索引gؓ(f)183Q?br>
    function ShellMessageBoxA(Module: THandle; Owner: HWND;

      Text: PChar; Caption: PChar; Style: UINT;

      Parameters: array of Pointer): Integer; cdecl;


更确切地说这个函数应该叫ShellMessageBoxA因ؓ(f)它只支持ANSI字符Ԍq有一个UNICODE的版本的函数ShellMessageBoxWQ它的烦引gؓ(f)182Q但它只在Windows NT上才有,函数定义如下Q?br>
    function ShellMessageBoxW(Module: THandle; Owner: HWND;

      Text: PWideChar; Caption: PWideChar; Style: UINT;

      Parameters: array of Pointer): Integer; cdecl;


Module参数是提供字W串资源的模块句柄,句柄可以用GetModuleHandle函数获得。顾名思义Text 参数指向一个要昄在对话框中的文本Q它也可以是资源字符串IDQ文本中可以包括格式控制序列Q它?yu)?x)被在Parameters中提供的额外字符串替代。控制符格式?#8220;%#”Q其?#8220;#”是额外字W串在参C的位|,比如“%1”被W一个Parameters数组中的字符串元素替代,“%3”会(x)被第三个元素替代Q依此类推。Caption参数指向对话框标题文本,同样它也可以是资源IDQ如果参Cؓ(f)nilQOwner指定的窗口标题将被用于对话框标题。Style参数是由位掩码标识组成的Q可以设|成MessageBox函数支持的MB_XXX常数的组合。返回值同MessageBox完全一栗?br>
对于q个函数很重要的一Ҏ(gu)微Y公司使用cdecl来输个函数而不是通常?stdcall。此外,Parameters参数使用了C语言中的可变参数列表Q这意味着q个函数不是语言无关的,q得调用v来非帔R烦,因ؓ(f)Delphiq不直接支持cdecl和可变参数列表。ؓ(f)了解册个问题,Parameters参数被映ؓ(f)一个动态指针列表。同时我们还需要用嵌入式汇编来徏立cdecl样式的堆栈。由于动态指针列表的性质Q我们必至指定一个指针倹{如果不x定要替代的字W串Q简单设|ؓ(f)nil可以了?/font>

q幽 2009-12-18 09:20 发表评论
]]>
struct DCBhttp://www.shnenglu.com/justin-shi/archive/2009/05/05/81909.htmlq幽q幽Mon, 04 May 2009 18:35:00 GMThttp://www.shnenglu.com/justin-shi/archive/2009/05/05/81909.htmlhttp://www.shnenglu.com/justin-shi/comments/81909.htmlhttp://www.shnenglu.com/justin-shi/archive/2009/05/05/81909.html#Feedback0http://www.shnenglu.com/justin-shi/comments/commentRss/81909.htmlhttp://www.shnenglu.com/justin-shi/services/trackbacks/81909.html

串口通讯中的DCBl构

typedef struct _DCB {// dcb

DWORD DCBlength; // sizeof(DCB)

DORD BaudRate; // current baud rate 指定当前的L特率

DWORD fBinary: 1; // binary mode, no EOF check 指定是否允许二进制模式WIN95中须为TRUE
       

DWORD fParity: 1; // enable parity checking 指定奇偶校验是否允许

DWORD fOutxCtsFlow:1; // CTS output flow control 指定CTS是否用于发送控制。当为TRUE是CTS为OFFQ发送将被挂赗?/font>


DWORD fOutxDsrFlow:1; // DSR output flow control   指定CTS是否用于发送控制。当为TRUE是CTS为OFFQ发送将被挂赗?/font>


DWORD fDtrControl:2; // DTR flow control type

DTR_CONTROL_DISABLE 值将DTR|ؓ(f)OFF,DTR_CONTROL_ENABLE值将DTR|ؓ(f)ON, 

DTR_CONTROL_HANDSHAKE 允许DTR"握手",

 

DWORD fDsrSensitivity:1;// DSR sensitivity 当该gؓ(f)TRUE时DSR为OFF时接收的字节被忽?/font>

 

DWORD fTXContinueOnXoff:1; // XOFF continues Tx
    指定当接收缓冲区已满,q且驱动E序已经发送出XoffChar字符时发送是否停止?/font>

    TRUEӞ在接收缓冲区接收到缓冲区已满的字节XoffLim且驱动程序已l发送出XoffChar?nbsp;     W中止接收字节之后,发送l进行?br>    FALSEӞ在接收缓冲区接收C表缓冲区已空的字节XonChar且驱动程序已l发送出恢复发送的XonChar之后Q发送l进行?/font>


DWORD fOutX: 1; // XON/XOFF out flow control    TRUEӞ接收到XoffChar之后便停止发送接收到XonChar之后重新开?/font>

 

DWORD fInX: 1; // XON/XOFF in flow control
             TRUEӞ接收~冲区接收到代表~冲区满的XoffLim之后QXoffChar发送出L收缓冲区接收C表缓冲区I的XonLim之后QXonChar发送出?/font>


DWORD fErrorChar: 1; // enable error replacement
         该gؓ(f)TRUE且fParity为TRUEӞ用ErrorChar 成员指定的字W代替奇偶校验错误的接收字符


DWORD fNull: 1; // enable null stripping  TRUEӞ接收时去掉空Q?|字节

 

DWORD fRtsControl:2; // RTS flow control


DWORD fAbortOnError:1; // abort reads/writes on error  TRUE?有错误发生时中止d写操作RTS_CONTROL_DISABLE?RTS|ؓ(f)OFFRTS_CONTROL_ENABLE? RTS|ؓ(f)ON

 

RTS_CONTROL_HANDSHAKE?当接收缓冲区于半满时RTS为ON当接收缓冲区过四分之三满时RTS为OFF


RTS_CONTROL_TOGGLE?当接收缓冲区仍有剩余字节时RTS为ON ,否则~省为OFF


DWORD fDummy2:17; // reserved  未?/font>

 

WORD wReserved; // not currently used  未?必须?

 

WORD XonLim; // transmit XON threshold   指定在XON字符发送这前接收缓冲区中可允许的最字节数


WORD XoffLim; // transmit XOFF threshold  指定在XOFF字符发送这前接收缓冲区中可允许的最字节数


BYTE ByteSize; // number of bits/byte, 4-8  指定端口当前使用的数据位

 

BYTE Parity; // 0-4=no,odd,even,mark,space 指定端口当前使用的奇偶校验方?可能?
                            EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY BYTE

 

StopBits;      0,1,2 = 1, 1.5, 2   指定端口当前使用的停止位?可能?
                          ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS


char XonChar; // Tx and Rx XON character  指定用于发送和接收字符XON的?/font>

 

char XoffChar; // Tx and Rx XOFF character  指定用于发送和接收字符XOFF?/font>

 

char ErrorChar; // error replacement character本字W用来代替接收到的奇偶校验发生错误时的?/font>

 

char EofChar; // end of input character 当没有用二q制模式?本字W可用来指示数据的结?/font>

 

char EvtChar; // received event character 当接收到此字W时,?x)生一个事?/font>

 

WORD wReserved1; // reserved; do not use 未?/font>

} DCB;



q幽 2009-05-05 02:35 发表评论
]]>
技术备?/title><link>http://www.shnenglu.com/justin-shi/archive/2009/03/13/76505.html</link><dc:creator>q幽</dc:creator><author>q幽</author><pubDate>Fri, 13 Mar 2009 11:56:00 GMT</pubDate><guid>http://www.shnenglu.com/justin-shi/archive/2009/03/13/76505.html</guid><wfw:comment>http://www.shnenglu.com/justin-shi/comments/76505.html</wfw:comment><comments>http://www.shnenglu.com/justin-shi/archive/2009/03/13/76505.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/justin-shi/comments/commentRss/76505.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/justin-shi/services/trackbacks/76505.html</trackback:ping><description><![CDATA[DLL注入E序的一般步骤:(x)<br><br>Q?Q取得宿主进E(卌注入木马的进E)的进EID dwRemoteProcessIdQ?br><br>Q?Q取得DLL的完全\径,q将其{换ؓ(f)宽字W模式pszLibFileNameQ?br><br>Q?Q利用Windows API OpenProcess打开宿主q程Q应该开启下列选项Q?br><br><span>a.PROCESS_CREATE_THREADQ允许在宿主q程中创建线E;</span><br><br>b.PROCESS_VM_OPERATIONQ允许对宿主q程中进行VM操作Q?br><br>c.PROCESS_VM_WRITEQ允许对宿主q程q行VM写?br><br><span>Q?Q利用Windows API VirtualAllocEx函数在远E线E的VM中分配DLL完整路径宽字W所需的存储空_(d)q利用Windows API WriteProcessMemory函数完整\径写入该存储I间Q?/span><br><br>Q?Q利用Windows API GetProcAddress取得Kernel32模块中LoadLibraryW函数的地址Q这个函数将作ؓ(f)随后启动的q程U程的入口函敎ͼ<br><br><span>Q?Q利用Windows API CreateRemoteThread启动q程U程Q将LoadLibraryW的地址作ؓ(f)q程U程的入口函数地址Q将宿主q程里被分配I间中存储的完整DLL路径作ؓ(f)U程入口函数的参C另其启动指定的DLLQ?/span><br><br><span>Q?Q清理现场?/span> <img src ="http://www.shnenglu.com/justin-shi/aggbug/76505.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/justin-shi/" target="_blank">q幽</a> 2009-03-13 19:56 <a href="http://www.shnenglu.com/justin-shi/archive/2009/03/13/76505.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>卸蝲其它q程的DLLhttp://www.shnenglu.com/justin-shi/archive/2009/02/21/74536.htmlq幽q幽Sat, 21 Feb 2009 14:32:00 GMThttp://www.shnenglu.com/justin-shi/archive/2009/02/21/74536.htmlhttp://www.shnenglu.com/justin-shi/comments/74536.htmlhttp://www.shnenglu.com/justin-shi/archive/2009/02/21/74536.html#Feedback0http://www.shnenglu.com/justin-shi/comments/commentRss/74536.htmlhttp://www.shnenglu.com/justin-shi/services/trackbacks/74536.html 1typedef ULONG (WINAPI *PFNNtUnmapViewOfSection)( IN HANDLE ProcessHandle,IN PVOID BaseAddress );
 2
 3BOOL UnmapViewOfModule ( DWORD dwProcessId, LPVOID lpBaseAddr )
 4{
 5    HMODULE hModule = GetModuleHandle ( L"ntdll.dll" ) ;
 6    if ( hModule == NULL )
 7        hModule = LoadLibrary ( L"ntdll.dll" ) ;
 8
 9    PFNNtUnmapViewOfSection pfnNtUnmapViewOfSection = (PFNNtUnmapViewOfSection)GetProcAddress ( hModule, "NtUnmapViewOfSection" ) ;
10    
11    HANDLE hProcess = OpenProcess ( PROCESS_ALL_ACCESS, TRUE, dwProcessId ) ;
12    ULONG    ret = pfnNtUnmapViewOfSection ( hProcess, lpBaseAddr ) ;
13    CloseHandle ( hProcess ) ;
14    return ret ? FALSE : TRUE;
15}

16
17

q幽 2009-02-21 22:32 发表评论
]]>
Heap: Pleasures and Painshttp://www.shnenglu.com/justin-shi/archive/2009/02/03/72832.htmlq幽q幽Tue, 03 Feb 2009 00:49:00 GMThttp://www.shnenglu.com/justin-shi/archive/2009/02/03/72832.htmlhttp://www.shnenglu.com/justin-shi/comments/72832.htmlhttp://www.shnenglu.com/justin-shi/archive/2009/02/03/72832.html#Feedback0http://www.shnenglu.com/justin-shi/comments/commentRss/72832.htmlhttp://www.shnenglu.com/justin-shi/services/trackbacks/72832.htmlhttp://hi.baidu.com/csuhkx/blog/item/267418d3614cf9013bf3cf55.html

q篇文章是翻译MSDN上一叫《Heap: Pleasures and Pains》的文章?

Murali R. Krishnan
Microsoft Corporation

1999 q?2 ?/p>

摘要Q?/strong> 讨论常见的堆性能问题以及(qing)如何防范它们。(?9 )

前言

(zhn)是否是动态分配的 C/C++ 对象忠实且幸q的用户Q?zhn)是否在模块间的往q通信中频J地使用?#8220;自动?#8221;Q?zhn)的程序是否因堆分配而运行v来很慢?不仅仅?zhn)遇到q样的问题。几乎所有项目迟早都?x)遇到堆问题。大安惌Q?#8220;我的代码真正好,只是堆太?#8221;。那只是部分正确。更深入理解堆及(qing)其用法、以?qing)?x)发生什么问题,是很有用的?/p>

什么是堆?

Q如果?zhn)已经知道什么是堆,可以跛_“什么是常见的堆性能问题Q?#8221;部分Q?/p>

在程序中Q用堆来动态分配和释放对象。在下列情况下,调用堆操作:(x)

  1. 事先不知道程序所需对象的数量和大小?br>
  2. 对象太大而不适合堆栈分配E序?

堆用了在运行时分配l代码和堆栈的内存之外的部分内存。下囄Z堆分配程序的不同层?/p>

GlobalAlloc/GlobalFreeQ?/strong>Microsoft Win32 堆调用,q些调用直接与每个进E的默认堆进行对话?/p>

LocalAlloc/LocalFreeQ?/strong>Win32 堆调用(Z?Microsoft Windows NT 兼容Q,q些调用直接与每个进E的默认堆进行对话?/p>

COM ?IMalloc 分配E序Q或 CoTaskMemAlloc / CoTaskMemFreeQ:(x)函数使用每个q程的默认堆。自动化E序使用“lg对象模型 (COM)”的分配程序,而申L(fng)E序使用每个q程堆?/p>

C/C++ q行?(CRT) 分配E序Q?/strong>提供?malloc() ?free() 以及(qing) new ?delete 操作W。如 Microsoft Visual Basic ?Java {语a也提供了新的操作Wƈ使用垃圾攉来代替堆。CRT 创徏自己的私有堆Q驻留在 Win32 堆的剙?/p>

Windows NT 中,W(xu)in32 堆是 Windows NT q行时分配程序周围的薄层。所?API 转发它们的请求给 NTDLL?/p>

Windows NT q行时分配程序提?Windows NT 内的核心堆分配程序。它由具?128 个大从 8 ?1,024 字节的空闲列表的前端分配E序l成。后端分配程序用虚拟内存来保留和提交页?/p>

在图表的底部?#8220;虚拟内存分配E序”Q操作系l用它来保留和提交c(din)所有分配程序用虚拟内存进行数据的存取?/p>

分配和释攑֝不就那么单吗Qؓ(f)何花费这么长旉Q?/p>

堆实现的注意事项

传统上,操作pȝ和运行时库是与堆的实现共存的。在一个进E的开始,操作pȝ创徏一个默认堆Q叫?#8220;q程?#8221;。如果没有其他堆可用,则块的分配?#8220;q程?#8221;。语aq行时也能在q程内创建单独的堆。(例如QC q行时创建它自己的堆。)除这些专用的堆外Q应用程序或许多已蝲入的动态链接库 (DLL) 之一可以创徏和用单独的堆。Win32 提供一整套 API 来创建和使用U有堆。有?a >堆函敎ͼ英文Q?/u>的详指|请参?MSDN?/p>

当应用程序或 DLL 创徏U有堆时Q这些堆存在于进E空_(d)q且在进E内是可讉K的。从l定堆分配的数据在同一个堆上释放。(不能从一个堆分配而在另一个堆释放。)

在所有虚拟内存系l中Q堆ȝ在操作系l的“虚拟内存理?#8221;的顶部。语aq行时堆也驻留在虚拟内存剙。某些情况下Q这些堆是操作系l堆中的层,而语aq行时堆则通过大块的分配来执行自己的内存管理。不使用操作pȝ堆,而用虚拟内存函数更利于堆的分配和块的用?/p>

典型的堆实现由前、后端分配程序组成。前端分配程序维持固定大块的空闲列表。对于一ơ分配调用,堆尝试从前端列表扑ֈ一个自由块。如果失败,堆被q从后端Q保留和提交虚拟内存Q分配一个大块来满h。通用的实现有每块分配的开销Q这耗费执行周期Q也减少了可使用的存储空间?/p>

Knowledge Base 文章 Q10758Q?#8220;?calloc() ?malloc() 理内存” Q搜索文章编P, 包含了有兌些主题的更多背景知识。另外,有关堆实现和设计的详l讨Z可在下列著作中找刎ͼ(x)“Dynamic Storage Allocation: A Survey and Critical Review”Q作?Paul R. Wilson、Mark S. Johnstone、Michael Neely ?David BolesQ?#8220;International Workshop on Memory Management”, 作?Kinross, Scotland, UK, 1995 q?9 ?http://www.cs.utexas.edu/users/oops/papers.html)Q英文)?/p>

Windows NT 的实玎ͼWindows NT 版本 4.0 和更新版本) 使用?127 个大从 8 ?1,024 字节?8 字节寚w块空闲列表和一?#8220;大块”列表?#8220;大块”列表Q空闲列表[0]Q?保存大于 1,024 字节的块。空闲列表容U了用双向链表链接在一L(fng)对象。默认情况下Q?#8220;q程?#8221;执行攉操作。(攉是将盔RI闲块合q成一个大块的操作。)攉耗费了额外的周期Q但减少了堆块的内部片?/p>

单一全局锁保护堆Q防止多U程式的使用。(请参?#8220;Server Performance and Scalability Killers”中的W一个注意事? George Reilly 所著,?“MSDN Online Web Workshop”上(站点Q?a >http://msdn.microsoft.com/workshop/server/iis/tencom.aspQ英文)。)单一全局锁本质上是用来保护堆数据l构Q防止跨多线E的随机存取。若堆操作太频繁Q单一全局锁会(x)Ҏ(gu)能有不利的影响?/p>

什么是常见的堆性能问题Q?/h2>

以下是?zhn)使用堆时会(x)遇到的最常见问题Q?

  • 分配操作造成的速度减慢?/strong>光分配就耗费很长旉。最可能Dq行速度减慢原因是空闲列表没有块Q所以运行时分配E序代码?x)耗费周期L较大的空闲块Q或从后端分配程序分配新块?br>
  • 释放操作造成的速度减慢?/strong>释放操作耗费较多周期Q主要是启用了收集操作。收集期_(d)每个释放操作“查找”它的盔R块,取出它们q构造成较大块,然后再把此较大块插入I闲列表。在查找期间Q内存可能会(x)随机到Q从而导致高速缓存不能命中,性能降低?br>
  • 堆竞争造成的速度减慢?/strong>当两个或多个U程同时讉K数据Q而且一个线El进行之前必ȝ待另一个线E完成时发生竞争。竞争LDȝQ这也是目前多处理器pȝ遇到的最大问题。当大量使用内存块的应用E序?DLL 以多U程方式q行Q或q行于多处理器系l上Q时导致速度减慢。单一锁定的用—常用的解决Ҏ(gu)—意味着使用堆的所有操作是序列化的。当{待锁定时序列化?x)引L(fng)E切换上下文。可以想象交叉\口闪烁的U灯处走走停停导致的速度减慢?

    竞争通常?x)导致线E和q程的上下文切换。上下文切换的开销是很大的Q但开销更大的是数据从处理器高速缓存中丢失Q以?qing)后来线E复zL的数据重建?/p>

  • 堆破坏造成的速度减慢?/strong>造成堆破坏的原因是应用程序对堆块的不正确使用。通常情Ş包括释放已释攄堆块或用已释放的堆块,以及(qing)块的界重写{明N题。(破坏不在本文讨论范围之内。有兛_存重写和泄漏{其他细节,请参?Microsoft Visual C++(R) 调试文档 。)

  • 频繁的分配和重分配造成的速度减慢?/strong>q是使用脚本语言旉常普遍的现象。如字符串被反复分配Q随重分配增长和释放。不要这样做Q如果可能,量分配大字W串和用缓冲区。另一U方法就是尽量少用连接操作?

竞争是在分配和释放操作中D速度减慢的问题。理x况下Q希望用没有竞争和快速分?释放的堆。可惜,现在q没有这L(fng)通用堆,也许来?x)有?/p>

在所有的服务器系l中Q如 IIS、MSProxy、DatabaseStacks、网l服务器?Exchange 和其他), 堆锁定实在是个大瓉。处理器数越多,竞争p?x)恶化?/p>

量减少堆的使用

现在(zhn)明白用堆时存在的问题了,N(zhn)不x有能解决q些问题的超U魔吗Q我可希望有。但没有法能堆运行加快—因此不要期望在产品之前的最后一星期能够大ؓ(f)改观。如果提前规划堆{略Q情况将?x)大大好转。调整用堆的方法,减少对堆的操作是提高性能的良斏V?/p>

如何减少使用堆操作?通过利用数据l构内的位置可减堆操作的次数。请考虑下列实例Q?/p>

struct ObjectA {
    // objectA 的数?
}
struct ObjectB {
    // objectB 的数?
}
// 同时使用 objectA ?objectB
//
// 使用指针
//
struct ObjectB {
    struct ObjectA * pObjA;
    // objectB 的数?
}
//
// 使用嵌入
//
struct ObjectB {
    struct ObjectA pObjA;
    // objectB 的数?
}
//
// 集合 – 在另一对象内?objectA ?objectB
//
struct ObjectX {
    struct ObjectA   objA;
    struct ObjectB   objB;
}
  1. 避免使用指针兌两个数据l构?/strong>如果使用指针兌两个数据l构Q前面实例中的对?A ?B 被分别分配和释放。这?x)增加额外开销—我们要避免q种做法?br>
  2. 把带指针的子对象嵌入父对象?/strong>当对象中有指针时Q则意味着对象中有动态元素(癑ֈ之八十)和没有引用的C|。嵌入增加了位置从而减了q一步分?释放的需求。这提高应用程序的性能?br>
  3. 合ƈ对象Ş成大对象Q聚合)?/strong>聚合减少分配和释攄块的数量。如果有几个开发者,各自开发设计的不同部分Q则最l会(x)有许多小对象需要合q。集成的挑战是要找到正的聚合边界?br>
  4. 内联~冲够满百分之八十的需要(aka 80-20 规则Q?/strong>个别情况下,需要内存缓冲区来保存字W串/二进制数据,但事先不知道d节数。估计ƈ内联一个大能满癑ֈ之八十需要的~冲区。对剩余的百分之二十Q可以分配一个新的缓冲区和指向这个缓冲区的指针。这P减分配和释放调用q增加数据的位置I间Q从Ҏ(gu)上提高代码的性能?br>
  5. 在块中分配对象(块化Q?/strong>块化是以l的方式一ơ分配多个对象的Ҏ(gu)。如果对列表的项q箋跟踪Q例如对一?{名称Q值} 对的列表Q有两种选择Q选择一是ؓ(f)每一?#8220;名称-?#8221;对分配一个节点;选择二是分配一个能容纳Q如五个Q?#8220;名称-?#8221;对的l构。例如,一般情况下Q如果存储四对,可减少节点的数量,如果需要额外的I间数量Q则使用附加的链表指针?

    块化是友好的处理器高速缓存,特别是对?L1-高速缓存,因ؓ(f)它提供了增加的位|?—不用说对于块分配,很多数据块会(x)在同一个虚拟页中?/p>

  6. 正确使用 _amblksiz?/strong>C q行?(CRT) 有它的自定义前端分配E序Q该分配E序从后端(Win32 堆)分配大小?_amblksiz 的块。将 _amblksiz 讄高的D潜在地减对后端的调用次数。这只对q泛使用 CRT 的程序适用?

使用上述技术将获得的好处会(x)因对象类型、大及(qing)工作量而有所不同。但总能在性能和可升羃性方面有所收获。另一斚wQ代码会(x)有点Ҏ(gu)Q但如果l过深思熟虑,代码q是很容易管理的?/p>

其他提高性能的技?/h3>

下面是一些提高速度的技术:(x)

  1. 使用 Windows NT5 ?/strong>

    ׃几个同事的努力和辛勤工作Q?998 q初 Microsoft Windows(R) 2000 中有了几个重大改q:(x)

    • 改进了堆代码内的锁定?/strong>堆代码对每堆一个锁。全局锁保护堆数据l构Q防止多U程式的使用。但不幸的是Q在高通信量的情况下,堆仍受困于全局锁,D高竞争和低性能。Windows 2000 中,锁内代码的(f)界区竞争的可能性减到最?从而提高了可׾~性?br>
    • 使用 “Lookaside”列表?/strong>堆数据结构对块的所有空闲项使用了大在 8 ?1,024 字节Q以 8-字节递增Q的快速高速缓存。快速高速缓存最初保护在全局锁内。现在,使用 lookaside 列表来访问这些快速高速缓存空闲列表。这些列表不要求锁定Q而是使用 64 位的互锁操作Q因此提高了性能?br>
    • 内部数据l构法也得到改q?

    q些改进避免了对分配高速缓存的需求,但不排除其他的优化。?Windows NT5 堆评估?zhn)的代码;它对?1,024 字节 (1 KB) 的块Q来自前端分配程序的块)是最佳的?strong>GlobalAlloc() ?LocalAlloc() 建立在同一堆上Q是存取每个q程堆的通用机制。如果希望获得高的局部性能Q则使用 Heap(R) API 来存取每个进E堆Q或为分配操作创q堆。如果需要对大块操作Q也可以直接使用 VirtualAlloc() / VirtualFree() 操作?/p>

    上述改进已在 Windows 2000 beta 2 ?Windows NT 4.0 SP4 中用。改q后Q堆锁的竞争率显著降低。这使所?Win32 堆的直接用户受益。CRT 堆徏立于 Win32 堆的剙Q但它用自q块堆,因而不能从 Windows NT 改进中受益。(Visual C++ 版本 6.0 也有改进的堆分配E序。)

  2. 使用分配高速缓?/strong>

    分配高速缓存允?dng)R速缓存分配的块,以便来重用。这能够减少对进E堆Q或全局堆)的分?释放调用的次敎ͼ也允许最大限度的重用曄分配的块。另外,分配高速缓存允许收集统计信?以便较好地理解对象在较高层次上的使用?/p>

    典型圎ͼ自定义堆分配E序在进E堆的顶部实现。自定义堆分配程序与pȝ堆的行ؓ(f)很相伹{主要的差别是它在进E堆的顶部ؓ(f)分配的对象提供高速缓存。高速缓存设计成一套固定大(?32 字节?4 字节?28 字节{)。这一个很好的{略Q但q种自定义堆分配E序丢失与分配和释放的对象相关的“语义信息”?

    与自定义堆分配程序相反,“分配高速缓?#8221;作ؓ(f)每类分配高速缓存来实现。除能够提供自定义堆分配E序的所有好处之外,它们q能够保留大量语义信息。每个分配高速缓存处理程序与一个目标二q制对象兌。它能够使用一套参数进行初始化Q这些参数表Cƈ发别、对象大和保持在空闲列表中的元素的数量{。分配高速缓存处理程序对象维持自qU有I闲实体池(不超q指定的阀|q用私有保护锁。合在一P分配高速缓存和U有锁减了与主pȝ堆的通信量,因而提供了增加的ƈ发、最大限度的重用和较高的可׾~性?/p>

    需要用清理程序来定期查所有分配高速缓存处理程序的zd情况q回收未用的资源。如果发现没有活动,释攑ֈ配对象的池,从而提高性能?/p>

    可以审核每个分配/释放zd。第一U信息包括对象、分配和释放调用的L。通过查看它们的统计信息可以得出各个对象之间的语义关系。利用以上介l的许多技术之一Q这U关pd以用来减内存分配?/p>

    分配高速缓存也起到了调试助手的作用Q帮助?zhn)跟踪没有完全清除的对象数量。通过查看动态堆栈返回踪q和除没有清除的对象之外的签名,甚至能够扑ֈ切的失败的调用者?/p>

  3. MP ?/strong>

    MP 堆是对多处理器友好的分布式分配的E序包,?Win32 SDKQWindows NT 4.0 和更新版本)中可以得到。最初由 JVert 实现Q此处堆抽象建立?Win32 堆程序包的顶部。MP 堆创建多?Win32 堆,q试囑ְ分配调用分布C同堆Q以减少在所有单一锁上的竞争?/p>

    本程序包是好的步?—一U改q的 MP-友好的自定义堆分配程序。但是,它不提供语义信息和缺乏统计功能。通常?MP 堆作?SDK 库来使用。如果用这?SDK 创徏可重用组Ӟ(zhn)将大大受益。但是,如果在每?DLL 中徏立这?SDK 库,增加工作设|?/p>

  4. 重新思考算法和数据l构

    要在多处理器机器上׾~,则算法、实现、数据结构和g必须动态׾~。请看最l常分配和释攄数据l构。试问,“我能用不同的数据l构完成此工作吗Q?#8221;例如Q如果在应用E序初始化时加蝲了只读项的列表,q个列表不必是线性链接的列表。如果是动态分配的数组非常好。动态分配的数组减内存中的堆块和片Q从而增强性能?/p>

    减少需要的对象的数量减少堆分配程序的负蝲。例如,我们在服务器的关键处理\径上使用五个不同的对象,每个对象单独分配和释放。一起高速缓存这些对象,把堆调用从五个减到一个,显著减少了堆的负载,特别当每U钟处理 1,000 个以上的h时?/p>

    如果大量使用“Automation”l构Q请考虑从主U代码中删除“Automation BSTR”Q或臛_避免重复?BSTR 操作。(BSTR q接Dq多的重分配和分?释放操作。)

摘要

Ҏ(gu)有^台往往都存在堆实现Q因此有巨大的开销。每个单独代码都有特定的要求Q但设计能采用本文讨论的基本理论来减堆之间的相互作用?

  1. 评h(hun)(zhn)的代码中堆的用?br>
  2. 改进(zhn)的代码Q以使用较少的堆调用Q分析关键\径和固定数据l构?br>
  3. 在实现自定义的包装程序之前用量化堆调用成本的方法?br>
  4. 如果Ҏ(gu)能不满意,误?OS l改q堆。更多这c请求意味着Ҏ(gu)q堆的更多关注?br>
  5. 要求 C q行时组针对 OS 所提供的堆制作y的分配包装程序。随着 OS 堆的改进QC q行时堆调用的成本将减小?br>
  6. 操作pȝQWindows NT 家族Q正在不断改q堆。请随时x和利用这些改q?

Murali Krishnan ?Internet Information Server (IIS) l的首席软g设计工程师。从 1.0 版本开始他p?IISQƈ成功发行?1.0 版本?4.0 版本。Murali l织q?IIS 性能l三q?(1995-1998), 从一开始就影响 IIS 性能。他拥有威斯h?Madison 大学?M.S.和印?Anna 大学?B.S.。工作之外,他喜Ƣ阅诅R打排球和家庭烹饪?/p>


q幽 2009-02-03 08:49 发表评论
]]>WindowFeaturesQWIN32开发必看)http://www.shnenglu.com/justin-shi/archive/2008/08/16/59052.htmlq幽q幽Sat, 16 Aug 2008 05:38:00 GMThttp://www.shnenglu.com/justin-shi/archive/2008/08/16/59052.htmlhttp://www.shnenglu.com/justin-shi/comments/59052.htmlhttp://www.shnenglu.com/justin-shi/archive/2008/08/16/59052.html#Feedback0http://www.shnenglu.com/justin-shi/comments/commentRss/59052.htmlhttp://www.shnenglu.com/justin-shi/services/trackbacks/59052.htmlq篇文章译至MSDN2005Q给自己学习(fn)Q也l所有觉得它有用的hQ文中难免有译不到位或者错误的地方Q望高手指正。译者:(x)Ƨ昊川(转蝲ȝ注明出处?qing)译者)

2008q???wbr>

q个概述讨论了窗口的一些特性,如窗口类型、状态、大及(qing)位置?wbr>

1、窗口类型(WindowStylesQ?/strong>
q一节描q层叠窗口、弹出窗口、子H口、分层窗口、仅处理消息的窗口这五种cd?/strong>

1.1层叠H口QOverlappedWindowsQ?wbr>
层叠H口是一个具有标题栏、边框和客户区的层H口Q也是说它适合做ؓ(f)应用E序ȝ口。它也可以具有一个系l菜单,最和最大化按钮Q以?qing)滚动条。一个层叠窗口被典型地用于包含所有上q组件的应用E序ȝ口?wbr>

通过在CreateWindowEx中指定WS_OVERLAPPED或者WS_OVERLAPPEDWINDOW样式Q一个应用程序就能创Z个层叠窗口。假如你使用W一个样式,那么创徏的窗口就h一个标题栏和边框;假如你用第二个Q那么窗口就h一个标题栏Q可以调整大的Ҏ(gu)Q系l菜单,以及(qing)最大最化按钮?wbr>

1.2弹出H口QPop-upWindowsQ?wbr>
弹出H口是一个非凡的层叠H口Q它被用于显C在应用E序ȝ口之外的对话框,消息框以?qing)其他?f)时窗口。标题栏对弹出窗口来说是可选的Q除此之外,弹出H口跟具有WS_OVERLAPPED样式的层叠窗口一栗?wbr>

你可以通过在CreateWindowEx中指定WS_POPUP样式来创Z个弹出窗口。假如要使用标题栏,加入WS_CAPTION样式。用WS_POPUPWINDOW样式来创Z个含有边框和pȝ菜单的弹出窗口。WS_CAPTION样式必须与WS_POPUPWINDOW样式一起用才能ɾpȝ菜单可见?wbr>

1.3子窗口(ChildWindowsQ?wbr>
子窗口具有WS_CHILD样式q且它被限制在其父窗口的客户Z。应用程序典型地使用子窗口来把其父窗口的客户区划分成几个功能区域。你可以通过在CreateWindowEx中指定WS_CHILD样式来创建子H口?wbr>

子窗口必d有一个父H口。父H口可以是一个层叠窗口,弹出H口Q或者另外一个子H口。你可以在CreateWindowEx中指定父H口。假如你在CreateWindowEx中指定了WS_CHILD样式但是没有指定父窗口,那么pȝ不会(x)创徏q个子窗口?wbr>

子窗口只h一个客户区而没有其他特性,除非q些Ҏ(gu)被明确的请求。应用程序可以ؓ(f)子窗口添加标题栏Q系l菜单,最化最大化按钮Q边框,以及(qing)滚动条。但是子H口不能h自定义菜单。假如应用程序指定了一个自定义菜单句柄Q那么无论是在它注册q个子窗口类q是创徏q个子窗口时Q这个菜单句柄都被忽略。假如没有指定边框样式,pȝ创Z个无Ҏ(gu)H口。应用程序可以用无Ҏ(gu)的子H口来划分父H口的客户区假如想保持这U划分对用户是不可见的话?wbr>

下面一节讨论窗口的布置、裁剪、与父窗口的关系、消息四个主题?/strong>

1.4H口布置QPositioningQ?wbr>
pȝL相对于父H口客户区的左上角来攄子窗口。子H口的Q何部分都不会(x)出现在其父窗口的Ҏ(gu)之外。假如应用程序创Z个比父窗口大的子H口Q或者移动子H口使得一个或者所有子H口出了父H口的边框,那么pȝ?x)裁剪子H口Q即在父H口Ҏ(gu)之外的部分不被显C。对父窗口生媄响的行ؓ(f)同样?x)媄响子H口Q这些行为如下:(x)

 



q幽 2008-08-16 13:38 发表评论
]]>
Window下拖放操作Drag & Drop 全解?/title><link>http://www.shnenglu.com/justin-shi/archive/2008/08/14/58866.html</link><dc:creator>q幽</dc:creator><author>q幽</author><pubDate>Thu, 14 Aug 2008 11:19:00 GMT</pubDate><guid>http://www.shnenglu.com/justin-shi/archive/2008/08/14/58866.html</guid><wfw:comment>http://www.shnenglu.com/justin-shi/comments/58866.html</wfw:comment><comments>http://www.shnenglu.com/justin-shi/archive/2008/08/14/58866.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/justin-shi/comments/commentRss/58866.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/justin-shi/services/trackbacks/58866.html</trackback:ping><description><![CDATA[<p><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><strong>OLE</strong><strong>拖放实现</strong></font></span></p> <p><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>MFC</font>本n?font face=Tahoma>CView</font>cL支持拖放操作的,通过研究<font face=Tahoma>CView</font>cȝ源码Q大体知道它的实现原理是q样的:(x)<font face=Tahoma>CView</font>cM有一?font face=Tahoma>COleDropTarget</font>cȝ对象Q在视图H口初始化时Q调?font face=Tahoma>COleDropTarget</font>cL员函?font face=Tahoma>Register()</font>Q以此在pȝ中注册该视图H口为拖放接收窗口。当q行拖放操作的鼠标指针处于视囄口范围内Ӟ<font face=Tahoma>COleDropTarge</font>cM(x)做出反应Q它?font face=Tahoma>OnDragEnter</font>?font face=Tahoma>OnDragOver</font>?font face=Tahoma>OnDropEx</font>?font face=Tahoma>OnDrop</font>{成员函数被依次调用Q这些函数默认均是调用与其相对应?font face=Tahoma>CView</font>cL员函?font face=Tahoma>OnDragEnter</font>?font face=Tahoma>OnDragOver</font>?font face=Tahoma>OnDropEx</font>?font face=Tahoma>OnDrop</font>{,E序员只需重蝲q些<font face=Tahoma>CView</font>cL员函敎ͼ卛_Ҏ(gu)动的q程?qing)结果进行控制?/font></span></p> <p><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>因ؓ(f)<font face=Tahoma>COleDropTarget</font>默认只对<font face=Tahoma>CView</font>提供支持Q所以如果要让其他的H口支持拖放Q我们必d时对要支持拖攄H口cd<font face=Tahoma>COleDropTarget</font>c进行派生。把Ҏ(gu)放操作具体进行处理的代码装成派生窗口类的成员函敎ͼ然后重蝲<font face=Tahoma>COleDropTarget</font>中对应的五个虚函敎ͼ当它接收到拖攑֊作时Q调用窗口派生类的处理函数即可。但q里有一个问题,是我们怎么知道何时调用zcȝ处理函数呢?{案是运?font face=Tahoma>RTTI</font>技术。如?font face=Tahoma>COleDropTarget</font>zcL到的H口指针cdQ就是我们派生的H口c,那么p用它的处理函敎ͼ否则调用基类q行处理?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>首先生成一个对话框工程Q添加二个新cR?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>W一个类名ؓ(f)<font face=Tahoma>CListCtrlEx</font>Q父cMؓ(f)<font face=Tahoma>CListCtrl</font>。添加完毕后Q在<font face=Tahoma>CListCtrlEx</font>的定义头文g中加?font face=Tahoma>DECLARE_DYNAMIC(CListCtrlEx)</font>Q在其实现文件中加入<font face=Tahoma>IMPLEMENT_DYNAMIC(CListCtrlEx,CListCtrl)</font>Q这样就?font face=Tahoma>CListCtrlEx</font>cL加了<font face=Tahoma>RTTI</font>q行期类型识别(<font face=Tahoma>Run Time Type Information</font>Q支持?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>W二个类名ؓ(f)<font face=Tahoma>COleDropTargetEx</font>Q父cMؓ(f)<font face=Tahoma>COleDataTarget</font>?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>?font face=Tahoma>CListCtrlEx</font>中添?font face=Tahoma>COleDropTargetEx</font>cȝ对象Qƈd下列公有虚函数的声明Q?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       virtual BOOL Initialize();</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       virtual DROPEFFECT OnDropEx(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, DROPEFFECT dropList, CPoint point);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       virtual void OnDragLeave(CWnd* pWnd);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>Initialize</font>函数用于注册<font face=Tahoma>CListCtrlEx</font>成ؓ(f)拖放接收H口Q?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>OnDragOver</font>在拖N标进入窗口时被调用。此函数的返回值决定了后箋的动作的cdQ如果返?font face=Tahoma>DROPEFFECT_MOVE</font>Q则产生一个剪切动作;如果q回<font face=Tahoma>DROPEFFECT_COPY</font>Q则产生一个复制动作,如果q回<font face=Tahoma>DROPEFFECT_NONE</font>Q则不会(x)产生拖放动作Q因?font face=Tahoma>OnDropEx</font>?font face=Tahoma>OnDrop</font>函数不?x)被调用Q?font face=Tahoma>OnDragLeave</font>函数仍会(x)被调用)?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>OnDropEx</font>函数?x)?font face=Tahoma>OnDrop</font>函数之前调用Q如?font face=Tahoma>OnDropEx</font>函数没有Ҏ(gu)攑֊作进行处理,则应用程序框架会(x)接着调用<font face=Tahoma>OnDrop</font>函数q行处理。所以必要在派生类中重?font face=Tahoma>OnDropEx</font>函数——即使什么动作都都没有做——否则我们的<font face=Tahoma>OnDrop</font>函数不?x)被执行刎ͼ因?f)没有重蝲的话Q将?x)调用基cȝ<font face=Tahoma>OnDropEx</font>函数Q而基cȝ<font face=Tahoma>OnDropEx</font>函数Ҏ(gu)放是q行了处理的——尽不是我们所惌的动作。当然你也可以把Ҏ(gu)放进行处理的动作攑֜<font face=Tahoma>OnDropEx</font>中——那样就不需要重?font face=Tahoma>OnDrop</font>了?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>OnDragLeave</font>函数?x)在鼠标dH口时被调用Q在此可以进行一些简单的清理工作。譬如在<font face=Tahoma>OnDragEnter</font>或?font face=Tahoma>OnDragOver</font>函数中,我们改变了光标的形态,那么此时我们应该把光标恢复q来?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>q些函数中最重要的是<font face=Tahoma>OnDrop</font>函数Q拖攑֊作将在此q行处理Q它的全部源码如下:(x)</font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>BOOL CListCtrlEx::OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>{</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       UINT              nFileCount = 0;</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       HDROP           hDropFiles = NULL;</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       HGLOBAL        hMemData = NULL;</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma size=2> </font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       AfxMessageBox("OnDrop");</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       if(pDataObject->IsDataAvailable(CF_HDROP)) </font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       {</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>              hMemData = pDataObject->GetGlobalData(CF_HDROP);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>              hDropFiles = (HDROP)GlobalLock((HGLOBAL)hMemData); //</font>锁定内存?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>              if(hDropFiles != NULL)</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>              {</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>                     char chTemp[_MAX_PATH+1] = {0};</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>                     nFileCount = DragQueryFile(hDropFiles, 0xFFFFFFFF, NULL, 0);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>                     for(UINT nCur=0; nCur<nFileCount; ++nCur) //</font>遍历取得每个文g?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>                     {</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>                            ZeroMemory(chTemp, _MAX_PATH+1);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>                DragQueryFile(hDropFiles, nCur, (LPTSTR)chTemp, _MAX_PATH+1);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>                            AddAllFiles(chTemp);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>                     }</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>              }</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>              GlobalUnlock(hMemData);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>              return TRUE;</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       }</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       else</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       {</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>              return FALSE;</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       }</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>}</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>在第二个c?font face=Tahoma>COleDropTarget</font>中添加如下对应的函数Q?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>    virtual DROPEFFECT OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>    virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       virtual DROPEFFECT OnDropEx(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, DROPEFFECT dropList, CPoint point);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       virtual void OnDragLeave(CWnd* pWnd);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>它们的动作都差不多:(x)先用<font face=Tahoma>RTTI</font>判断H口指针<font face=Tahoma>pWnd</font>的类型,如果?font face=Tahoma>CListCtrlEx</font>Q则调用<font face=Tahoma>CListCtrlEx</font>中对应的处理函数Q否则调用基cȝ处理函数。以<font face=Tahoma>OnDrop</font>ZQ?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>BOOL COleDropTargetEx::OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>{</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       CListCtrlEx*     pListCtrlEx = NULL;</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       </font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       ASSERT_VALID(this);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       ASSERT(IsWindow(pWnd->m_hWnd));</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       </font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       if(pWnd->IsKindOf(RUNTIME_CLASS(CListCtrlEx)))</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       {</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>              pListCtrlEx = (CListCtrlEx*)pWnd;</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>              return pListCtrlEx->OnDrop(pWnd, pDataObject, dropEffect, point);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       }</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       else</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       {</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>              return COleDropTarget::OnDrop(pWnd, pDataObject, dropEffect, point);     </font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       }</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>}</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2></font></font></span> </p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>//倒霉?4K限制Q只能再截断了:(x)Q?br><br></font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>xQ我们成功地?font face=Tahoma>CListCtrlEx</font>d了文件拖入操作的支持。一个完整的拖放操作Q还包括拖出动作Q所以必要cdd拖出操作Q即Q将列表中的某一Ҏ(gu)者多Ҏ(gu)出成Z个文件。这需要用到另一个类Q?font face=Tahoma>COleDataSource</font>。具体步骤如下:(x)<br></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>?font face=Tahoma>CListCtrlEx</font>中加入一?font face=Tahoma>COleDataSource</font>的实例,q映列表框?font face=Tahoma>LVN_BEGINDRAG</font>消息处理函数Q在此我们添加拖出操作的代码?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>实现拖出非常单,只需要依ơ调?font face=Tahoma>COleDataSource</font>的三个函数即可:(x)<font face=Tahoma>Empty</font>用于清空原先对象中缓存的数据Q?font face=Tahoma>CacheGlobalData</font>用来~存数据以进行拖放操作,最后调?font face=Tahoma>DoDragDrop</font>启动本次拖放操作?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>但在调用之前Q必要做一些准备工作。主要的d是创徏一?font face=Tahoma>DROPFILES</font>l构体,q拷贝要拖放的文件名到结构体后的内存中?font face=Tahoma>DROPFILES</font>l构体定义了<font face=Tahoma>CF_HDROP</font>剪脓(chung)板格式,紧跟它后面的是一pd被拖放文件的路径名。它的定义如下:(x)</font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>typedef struct _DROPFILES</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>{</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>    DWORD     pFiles;  //</font>文g名v始地址</font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>    POINT      pt;     //</font>鼠标放下的位|,坐标?font face=Tahoma>fNC</font>成员指定</font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>    BOOL        fNC;    //</font>?font face=Tahoma>TRUE</font>表示适用屏幕坐标p,否则使用客户坐标p?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>    BOOL        fWide;  //</font>文g名字W串是否使用宽字W?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>} DROPFILES, FAR* LPDROPFILES; </font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>拖放之前的准备动作的代码如下Q?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>uBufferSize = sizeof(DROPFILES) + uBufferSize + 1;</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>    hMemData = GlobalAlloc(GPTR,uBufferSize);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>    ASSERT(hMemData != NULL);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       </font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>       lpDropFiles = (LPDROPFILES)GlobalLock(hMemData); //</font>锁定?font face=Tahoma>,</font>q设|相x?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       ASSERT(lpDropFiles != NULL);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       lpDropFiles->pFiles = sizeof(DROPFILES);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>#ifdef _UNICODE</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       lpDropFiles->fWide = TRUE;</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>#else</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       lpDropFiles->fWide = FALSE;</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>#endif</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma size=2> </font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>       //</font>把选中的所有文件名依次复制?font face=Tahoma>DROPFILES</font>l构体后?font face=Tahoma>(</font>全局内存?font face=Tahoma>)</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       pItemPos = strSelectedList.GetHeadPosition();</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       pszStart = (char*)((LPBYTE)lpDropFiles + sizeof(DROPFILES));</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       while(pItemPos != NULL)</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       {</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>              lstrcpy(pszStart, (LPCTSTR)strSelectedList.GetNext(pItemPos));</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>        pszStart = strchr(pszStart,'\0') + 1; //</font>下次的v始位|是上一ơ结?font face=Tahoma>+1</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       }</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>准备完毕之后可以进行拖放了Q拖攑֊作有<font face=Tahoma>DoDragDrop</font>函数触发Q其原型如下Q?/font></span></p> <p><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>DROPEFFECT DoDragDrop( </font></font></span></p> <p><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>DWORD dwEffects = DROPEFFECT_COPY|DROPEFFECT_MOVE|DROPEFFECT_LINK, LPCRECT lpRectStartDrag = NULL, </font></font></span></p> <p><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>COleDropSource* pDropSource = NULL </font></font></span></p> <p><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>q里Q?font face=Tahoma>dwEffects</font>指定了允许施加于?font face=Tahoma>COleDataSource</font>实例之上的动作集Q剪切、复制或无动作?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>    lpRectStartDrag</font>指示拖放操作真正开始的矩ŞQ如果鼠标没有移矩ŞQ则拖放操作视作攑ּ处理。如果本成员设ؓ(f)<font face=Tahoma>NULL</font>Q则该v始矩形将Z个像素大?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>    pDropSource</font>表明拖放所使用?font face=Tahoma>COleDataSource</font>对象?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>而该函数的返回|则表明本ơ拖放操作所实际产生的效果,至于具体产生何种效果Q则ql决定。譬如在拖放时按?font face=Tahoma>Shift</font>键,生剪切效果;按住<font face=Tahoma>Ctrl</font>键,生复制效果,{等?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>拖放的代码如下:(x)</font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       m_oleDataSource.Empty();</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       m_oleDataSource.CacheGlobalData(CF_HDROP, hMemData);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>       DropResult = m_oleDataSource.DoDragDrop(DROPEFFECT_MOVE|DROPEFFECT_COPY);</font></font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>最后一点要注意的是Q在<font face=Tahoma>Windows NT 4.0</font>以上的系l中Q即使实际生的?font face=Tahoma>DROPEFFECT_MOVE</font>动作Q?font face=Tahoma>DoDragDrop</font>函数也只q回<font face=Tahoma>DROPEFFECT_NONE</font>。生这个问题的原因在于Q?font face=Tahoma>Windows NT 4.0</font>?font face=Tahoma>Shell</font>?x)直接移动文件本w来对移动操作进行优化。返回?font face=Tahoma>DROPEFFECT_MOVE</font>最初的含义Q就是通知执行拖放操作的应用程序去删除原位|上的文件。但是因?font face=Tahoma>Shell</font>已经替应用程序完成了q个Q删除)动作Q所以,函数q回<font face=Tahoma>DROPEFFECT_NONE</font>。要想知道文件是否真的被Ud了也很简单,只要在函数返回之后检查一下原位置上的文g是否存在可以了?/font></span></p> <p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>Windows 9x</font>pd的操作系l也?x)对Udq行同样的优化动作,但是它不?x)返?font face=Tahoma>DROPEFFECT_NONE</font>来代?font face=Tahoma>DROPEFFECT_MOVE</font>。详l的解释参见<font face=Tahoma>MS</font>知识?font face=Tahoma>Q182219</font>?/font></span></p> <img src ="http://www.shnenglu.com/justin-shi/aggbug/58866.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/justin-shi/" target="_blank">q幽</a> 2008-08-14 19:19 <a href="http://www.shnenglu.com/justin-shi/archive/2008/08/14/58866.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SHGetFileInfo http://www.shnenglu.com/justin-shi/archive/2008/08/13/58782.htmlq幽q幽Wed, 13 Aug 2008 15:11:00 GMThttp://www.shnenglu.com/justin-shi/archive/2008/08/13/58782.htmlhttp://www.shnenglu.com/justin-shi/comments/58782.htmlhttp://www.shnenglu.com/justin-shi/archive/2008/08/13/58782.html#Feedback0http://www.shnenglu.com/justin-shi/comments/commentRss/58782.htmlhttp://www.shnenglu.com/justin-shi/services/trackbacks/58782.htmlfunction SHGetFileInfo(pszPath: PAnsiChar; dwFileAttributes: DWORD;
  var psfi: TSHFileInfo; cbFileInfo, uFlags: UINT): DWORD; stdcall;
pszPath 参数:指定的文件名?br>当uFlags的取g不包?SHGFI_PIDL?可直接指?
当uFlags的取g包含 SHGFI_PIDL时pszPath要通过计算获得,不能直接指定;
dwFileAttributes参数:文g属性?br>仅当uFlags的取g包含SHGFI_USEFILEATTRIBUTES时有?一般不用此参数;
psfi 参数:q回获得的文件信?是一个记录类?有以下字D?
  _SHFILEINFOA = record
    hIcon: HICON;                      { out: icon }  //文g的图标句?br>    iIcon: Integer;                    { out: icon index }     //图标的系l烦引号
    dwAttributes: DWORD;               { out: SFGAO_ flags }    //文g的属性?br>    szDisplayName: array [0..MAX_PATH-1] of  AnsiChar; { out: display name (or path) }  //文g的显C名
    szTypeName: array [0..79] of AnsiChar;             { out: type name }      //文g的类型名
  end;
cbFileInfo 参数:psfi的比特?
uFlags 参数:指明需要返回的文g信息标识W?常用的有以下常数:
    SHGFI_ICON;           //获得图标
    SHGFI_DISPLAYNAME;    //获得昄?br>    SHGFI_TYPENAME;       //获得cd?br>    SHGFI_ATTRIBUTES;     //获得属?br>    SHGFI_LARGEICON;      //获得大图?br>    SHGFI_SMALLICON;      //获得图?br>    SHGFI_PIDL;           // pszPath是一个标识符
函数SHGetFileInfo()的返回g随uFlags的取值变化而有所不同?br>可见通过调用SHGetFileInfo()可以由psfi参数得到文g的图标句柄。但要注意在uFlags参数中不使用SHGFI_PIDL?SHGetFileInfo()不能获得“我的?sh)?#8221;{虚似文件夹的信息?br>应该注意的是Q在调用SHGetFileInfo()之前Q必M?CoInitialize 或者OleInitialize 初始化COM,否则表面上能够用,但是?x)造成不安全或者失部分功能。例如,一个常见的例子Q如果不初始化COM,那么调用该函数就无法得到.htm/.mht/.xml文g的图标?br>以下是两个例子:(x)
1.获得pȝ图标列表Q?br>//取得pȝ图标列表
uses
ShellAPI
var
  ImageListHandle : THandle;
  FileInfo: TSHFileInfo;
//图?
ImageListHandle := SHGetFileInfo('C:\',
                           0,
                           FileInfo,
                           SizeOf(FileInfo),
                           SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
//把图标列表同一个名叫ListView1的ListView控g的小图标兌?nbsp;                          
SendMessage(ListView1.Handle, LVM_SETIMAGELIST, LVSIL_SMALL, ImageListHandle);  
//大图?nbsp;  
ImageListHandle := SHGetFileInfo('C:\',
                           0,
                           FileInfo,
                           SizeOf(FileInfo),
                           SHGFI_SYSICONINDEX or SHGFI_LARGEICON);
//把图标列表同一个名叫ListView1的ListView控g的大图标兌?nbsp;                          
SendMessage(ListView1.Handle, LVM_SETIMAGELIST, LVSIL_NORMAL, ImageListHandle);
2.获得一个文件的昄名和图标
var
  sfi: TSHFileInfo;
IconIndex : Integer;
//取图标的索引L(fng)信息
SHGetFileInfo(PAnsiChar(FileName),
                0,
                sfi,
                sizeof(TSHFileInfo),
                ShellAPI.SHGFI_DISPLAYNAME or ShellAPI.SHGFI_TYPENAME or ShellAPI.SHGFI_LARGEICON or ShellAPI.SHGFI_ICON);
//昄名和图标在系l图标列表中的编号就分别在sfi.szDisplayName和sfi.iIcon?



q幽 2008-08-13 23:11 发表评论
]]>
GetSystemMetrics()用法http://www.shnenglu.com/justin-shi/archive/2008/08/10/58469.htmlq幽q幽Sun, 10 Aug 2008 13:42:00 GMThttp://www.shnenglu.com/justin-shi/archive/2008/08/10/58469.htmlhttp://www.shnenglu.com/justin-shi/comments/58469.htmlhttp://www.shnenglu.com/justin-shi/archive/2008/08/10/58469.html#Feedback0http://www.shnenglu.com/justin-shi/comments/commentRss/58469.htmlhttp://www.shnenglu.com/justin-shi/services/trackbacks/58469.html下面是GetSystemMetrics函数参数nIndex的定义:(x)

  SM_ARRANGE Flags specifying how the system arranged minimized windows. For more information about minimized windows, see the following Remarks section.

  SM_CLEANBOOT q回pȝ启动方式:

  0 正常启动

  1 安全模式启动

  2 |络安全模式启动

  SM_CMOUSEBUTTONS q回gؓ(f)pȝ支持的鼠标键敎ͼq回0Q则pȝ中没有安装鼠标?br>
  SM_CXBORDER,

  SM_CYBORDER q回以像素gؓ(f)单位的WindowsH口Ҏ(gu)的宽度和高度Q如果Windows的ؓ(f)3D形态,?br>
  {同于SM_CXEDGE参数

  SM_CXCURSOR,

  SM_CYCURSOR q回以像素gؓ(f)单位的标准光标的宽度和高?br>
  SM_CXDLGFRAME,

  SM_CYDLGFRAME {同与SM_CXFIXEDFRAME and SM_CYFIXEDFRAME

  SM_CXDOUBLECLK,

  SM_CYDOUBLECLK 以像素gؓ(f)单位的双?yn)L效的矩Ş区域

  SM_CXEDGE,SM_CYEDGE 以像素gؓ(f)单位?DҎ(gu)的宽度和高度

  SM_CXFIXEDFRAME,

  SM_CYFIXEDFRAME 围绕h标题但无法改变尺寸的H口Q通常是一些对话框Q的Ҏ(gu)的厚?br>
  SM_CXFRAME,SM_CYFRAME {同于SM_CXSIZEFRAME and SM_CYSIZEFRAME

  SM_CXFULLSCREEN,

  SM_CYFULLSCREEN 全屏q窗口的H口区域的宽度和高度

  SM_CXHSCROLL,

  SM_CYHSCROLL 水^滚动条的高度和水qx动条上箭头的宽度

  SM_CXHTHUMB 以像素ؓ(f)单位的水qx动条上的滑动块宽?br>
  SM_CXICON,SM_CYICON pȝ~省的图标的高度和宽度(一般ؓ(f)32*32Q?br>
  SM_CXICONSPACING,

  SM_CYICONSPACING 以大图标方式查看Item时图标之间的间距Q这个距LL大于{于

  SM_CXICON and SM_CYICON.

  SM_CXMAXIMIZED,

  SM_CYMAXIMIZED 处于层的最大化H口的缺省尺?br>
  SM_CXMAXTRACK,

  SM_CYMAXTRACK h可改变尺寸边框和标题栏的H口的缺省最大尺寸,如果H口大于q个

  寸Q窗口是不可Ud的?br>
  SM_CXMENUCHECK,

  SM_CYMENUCHECK 以像素ؓ(f)单位计算的菜单选中标记位图的尺?br>
  SM_CXMENUSIZE,

  SM_CYMENUSIZE 以像素计的菜单栏按钮的寸

  SM_CXMIN,SM_CYMIN H口所能达到的最尺?br>
  SM_CXMINIMIZED,

  SM_CYMINIMIZED 正常的最化H口的尺?br>
  SM_CXMINTRACK,

  SM_CYMINTRACK 最跟t距,当用者拖动窗口移动距d于这个|H口不会(x)Ud?br>
SM_CXSCREEN,

  SM_CYSCREEN 以像素ؓ(f)单位计算的屏q尺寸?br>
  SM_CXSIZE,SM_CYSIZE 以像素计的标题栏按钮的寸

  SM_CXSIZEFRAME,

  SM_CYSIZEFRAME 围绕可改变大的H口的边框的厚度

  SM_CXSMICON,

  SM_CYSMICON 以像素计的图标的寸Q小图标一般出现在H口标题栏上?br>
  SM_CXVSCROLL,

  SM_CYVSCROLL 以像素计的垂直滚动条的宽度和垂直滚动条上箭头的高度

  SM_CYCAPTION 以像素计的普通窗口标题的高度

  SM_CYMENU 以像素计的单个菜单条的高度

  SM_CYSMCAPTION 以像素计的H口标题栏的高?br>
  SM_CYVTHUMB 以像素计的垂直滚动条中滚动块的高度

  SM_DBCSENABLED 如果为TRUE或不?的D明系l安装了双字节版本的USER.EXE,为FALSE?则不是?br>
  SM_DEBUG 如果为TRUE或不?的D明系l安装了debug版本的USER.EXE,为FALSE?则不是?br>
  SM_MENUDROPALIGNMENT 如果为TRUE或不?的g拉菜单是叛_齐的否则是左寚w的?br>
  SM_MOUSEPRESENT 如果为TRUE或不?的值则安装了鼠标,否则没有安装?br>
  SM_MOUSEWHEELPRESENT 如果为TRUE或不?的值则安装了滚轮鼠标,否则没有安装?Windows NT only)

  SM_SWAPBUTTON 如果为TRUE或不?的值则鼠标左右键交换,否则没有?


q幽 2008-08-10 21:42 发表评论
]]>
把C++cL员方法直接作为线E回调函?/title><link>http://www.shnenglu.com/justin-shi/archive/2008/07/22/56813.html</link><dc:creator>q幽</dc:creator><author>q幽</author><pubDate>Mon, 21 Jul 2008 19:13:00 GMT</pubDate><guid>http://www.shnenglu.com/justin-shi/archive/2008/07/22/56813.html</guid><wfw:comment>http://www.shnenglu.com/justin-shi/comments/56813.html</wfw:comment><comments>http://www.shnenglu.com/justin-shi/archive/2008/07/22/56813.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/justin-shi/comments/commentRss/56813.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/justin-shi/services/trackbacks/56813.html</trackback:ping><description><![CDATA[<p>我以前写U程时要么老老实实照着声明?要么使用C++cȝ静态成员函数来作ؓ(f)回调函数,l常?x)因为线E代码而破坏封?之前虽然知道cL员函数的展开形式Q但从没惌利用q它Q昨天看深入ATL时无意中学会(x)了这一?) </p> <p>cL员方法是一个比较特D的函数Q它在编译时?x)被转化成普通函敎ͼ比如有TMyClassc?<br>class TMyClass{<br>    void Func();<br>};</p> <p>q个TMyClass::Func最l会(x)转化?void Func(TMyClass *this); 也就是说在原W一个参数前插入指向对象本n的this指针?/p> <p>我们可以利用q个Ҏ(gu)写一个非静态类成员Ҏ(gu)来直接作为线E回调函敎ͼ先看_beginthread函数的定?<br>unsigned long _RTLENTRY _EXPFUNC _beginthread (void (_USERENTRY *__start)(void *),unsigned __stksize, void *__arg);<br>其中的第一个参数就是作为线E执行主体的回调函数。它的原型是:void Func(void *)Q这个void*参数是作定义数据传入的。对比一下上面所说的TMyClass::Func的最lŞ式,它正好可以符合这里的要求?/p> <p>现在做个实验:<br>#include <stdio.h><br>#include <process.h></p> <p>class TMyClass{<br>    int m_nCount;<br>    int m_nId;<br>public:<br>    TMyClass(int nId,int nCount)<br>        :m_nId(nId),m_nCount(nCount)<br>    {<br>    }</p> <p>    void _USERENTRY ThreadProc()            // cL员方?br>    {<br>        for(int i=0; i<m_nCount; i++)       // Ҏ(gu)m_nCount成员打印一排数?br>        {<br>            printf("Class%d : %d\n",m_nId,i);<br>        }<br>    }<br>};</p> <p>int main(int argc, char* argv[])<br>{<br>    union {                                // 联合c,用于转换cL员方法指针到普通函数指针(试过~译器不允许在这两种函数之间强制转换Q,不知道有没有更好的方法?br>        void (_USERENTRY *ThreadProc)(void *);<br>        void (_USERENTRY TMyClass::*MemberProc)();<br>    } Proc;                                // 管联合里的两种函数cd现在看v来有很大不同Q但它们的最lŞ式是相同的?/p> <p>    TMyClass MyClass1(1,10),MyClass2(2,5); // 产生两个TMyClass对象</p> <p>    Proc.MemberProc = &TMyClass::ThreadProc;   // 转换QProc.ThreadProc是对应的普通函数指针了</p> <p>    _beginthread(Proc.ThreadProc,4096,&MyClass1);   // 开始线E,q里的Proc.ThreadProc实际上是TMyClass::ThreadProc, 它要的this指针是我们给?amp;MyClass1?br>    _beginthread(Proc.ThreadProc,4096,&MyClass2);<br>    system("pause");<br>    return 0;<br>}</p> <p>q行Q神奇吧Q?-)</p> <p>其实不止U程回调函数Q其实只要是形如Func(void*,...)的回调函数都可以用这U方法直接用类成员Ҏ(gu)?前提是第一个void*是自定义数据Q也是说它不能有其它功??br><br>转自:http://blog.csdn.net/waiting4you/archive/2007/12/29/2000796.aspx</p> <img src ="http://www.shnenglu.com/justin-shi/aggbug/56813.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/justin-shi/" target="_blank">q幽</a> 2008-07-22 03:13 <a href="http://www.shnenglu.com/justin-shi/archive/2008/07/22/56813.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>滚动控g(ScrollBar)http://www.shnenglu.com/justin-shi/archive/2008/07/21/56730.htmlq幽q幽Mon, 21 Jul 2008 01:57:00 GMThttp://www.shnenglu.com/justin-shi/archive/2008/07/21/56730.htmlhttp://www.shnenglu.com/justin-shi/comments/56730.htmlhttp://www.shnenglu.com/justin-shi/archive/2008/07/21/56730.html#Feedback3http://www.shnenglu.com/justin-shi/comments/commentRss/56730.htmlhttp://www.shnenglu.com/justin-shi/services/trackbacks/56730.html滚动控g(ScrollBar)


  滚动?ScrollBar)主要用来从某一预定义D围内快速有效地q行选择。滚动条分垂直滚动条和水qx动条两种。在滚动条内有一个滚动框Q用来表C当前的倹{用鼠标单击滚动条,可以使滚动框Ud一,鼠标单击滚动条两端的剪头可以使滚动框Ud一行,也可以直接拖动滚动框。许多窗口控件如列表框和l合框等都带有滚动条子窗口。Win32的滚动条支持比例滚动框,即用滚动框的大小来反映页相对于整个范围的大小?br>  当CreateWindowEx创徏滚动条时Q其风格常数中带SBS_VERT为水qx动条Q不带SBS_VERT或带SBS_HORZ为垂直滚动条?br>  创徏控g时应初始化滚动条的各U参数?br>  应用E序可以通过调用SendMessage向控件发送如下消息来讑֮控g各种参数?br>
uMsg wParam lParam 说明
SBM_ENABLE_ARROWS ESB_DISABLE_BOTH 0 止双向滚动剪头
ESB_DISABLE_DOWN 0 止向下滚动剪头
ESB_DISABLE_LTUP 0 止向上和向左滚动剪?/td>
ESB_DISABLE_LEFT 0 止向左滚动剪头
ESB_DISABLE_RTDN 0 止向下和向x动剪?/td>
ESB_DISABLE_UP 0 止向上滚动剪头
ESB_ENABLE_BOTH 0 允许双向滚动剪头(撤消各种止)
SBM_SETPOS 指定位置 TRUE 讄滚动框位|,ql控?/td>
FALSE 讄滚动框位|,不重l控?/td>
SBM_SETRANGE 最?/td> 最大?/td> 讄滚动框位|的变化范围
SBM_SETRANGEREDRAW 最?/td> 最大?/td> 讄滚动框位|的变化范围Qƈ重绘控g
SBM_SETSCROLLINFO TRUE或FALSE SCROLLINFOl构指针 本消息通过一个SCROLLINFOl构来同时指定控件的多种参数Q具体指定哪些参数由l构中的fMask成员定。wParam指定是否重绘控gQ详?#8220;SCROLLINFOl构”
  当用户在滚动条控件上q行各种操作Ӟ其父H口收到WM_HSCROLL或WM_VSCROLL通知消息Q同时wParam的低16位带有如下表的消息代?nScrollCode)QwParam的高16位带滚动框的指定位置(nPos)Q该值在消息代码{于SB_THUMBPOSITION或SB_THUMBTRACK时才有效。lParam带控件句?hwndScrollBar)?br>  应用E序可以Ҏ(gu)消息代码做相应的操作Q重新设|滚动框位置Q控件本w是不会(x)改变滚动框位|的?
消息代码 动作 响应
SB_LINEUP
SB_LINELEFT
用户点击了向??剪头 滚动框位|减一Q客L(fng)口向??滚动一行?br>注:(x)q两个代码数值相{,因此可以L(fng)Q下同?/td>
SB_LINEDOWN
SB_LINERIGHT
用户点击了向??剪头 滚动框位|加一Q客L(fng)口向??滚动一行?/td>
SB_PAGEUP
SB_PAGELEFT
用户点击了滚动框以上(?剪杆 滚动框位|减M个大单位Q客L(fng)口向??滚动一c(din)?
SB_PAGEDOWN
SB_PAGERIGHT
用户点击了滚动框以下(?剪杆 滚动框位|加上一个大单位Q客L(fng)口向??滚动一c(din)?
SB_THUMBPOSITION 用户拖动q放滚动框到指定位|?/td> 讑֮滚动框到指定位置。客L(fng)口滚动到指定位置?/td>
SB_THUMBTRACK 用户正在拖动滚动?/td> 讑֮滚动框到指定位置。客L(fng)口滚动到指定位置。如果应用程序需要快速浏览窗口,可以响应本消息重l窗口,如果不需要快速浏览,可以{待收到SB_THUMBPOSITION消息旉l窗口?
SB_ENDSCROLL 用户释放按下剪头或剪杆的鼠标 无须做Q何响?
  应用E序可以通过调用SendMessage向控件发送如下消息来取得当前控g各种参数?
uMsg wParam lParam 说明
SBM_GETPOS 0 0 q回滚动框当前位|?/td>
SBM_GETRANGE 最值地址指针 最大值地址指针 在指定地址中填?2位的滚动框位|的变化范围
SBM_GETSCROLLINFO 0 SCROLLINFOl构指针 在一个SCROLLINFOl构中返回控件的多种参数Q必M先设定结构的fMask成员来确定具体要取得哪些参数。详?#8220;SCROLLINFOl构”
  当控仉要重L向每父窗口发送WM_CTLCOLORSCROLLBAR消息,同时在wParam中带控g的设备场景句?hDC)QlParam中带控g句柄。如果应用程序响应这个消息ƈq回一个画?brush)句柄Q控件将Ҏ(gu)q个句柄l制背景艌Ӏ?br>
SCROLLINFOl构Q?
SCROLLINFO STRUCT
            cbSize        DWORD      ?
            fMask         DWORD      ?
            nMin          DWORD      ?
            nMax          DWORD      ?
            nPage         DWORD      ?
            nPos          DWORD      ?
            nTrackPos     DWORD      ?
            SCROLLINFO ENDS
成员说明Q?br>  cbSize: SCROLLINFOl构长度字节敎ͼ该值在讄和查询参数时都必d写?br>  fMask: 指定l构中的哪些成员是有效,该值共有如?U选择Q可以选择多种?#8220;OR”l合hQ该值在讄和查询参数时都必d写?br>    SIF_ALL      :整个l构都有?br>    SIF_DISABLENOSCROLL:该g在设定参数时使用Q视控g参数讑֮的需要来Ҏ(gu)l构的成员进行取舍?br>    SIF_PAGE      :nPage成员有效
    SIF_POS      :nPos成员有效
    SIF_RANGE     :nMin和nMax成员有效
  nMin:滚动范围最?br>  nMax:滚动范围最大?br>  nPage:尺寸,用来定比例滚动框的大小
  nPos:滚动框的位置
  nTrackPos:拖动时滚动框的位|,该参数只能查询,不能讄?br>  



q幽 2008-07-21 09:57 发表评论
]]>
如何让类的成员函C为回调函?/title><link>http://www.shnenglu.com/justin-shi/archive/2008/07/06/55448.html</link><dc:creator>q幽</dc:creator><author>q幽</author><pubDate>Sat, 05 Jul 2008 19:58:00 GMT</pubDate><guid>http://www.shnenglu.com/justin-shi/archive/2008/07/06/55448.html</guid><wfw:comment>http://www.shnenglu.com/justin-shi/comments/55448.html</wfw:comment><comments>http://www.shnenglu.com/justin-shi/archive/2008/07/06/55448.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/justin-shi/comments/commentRss/55448.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/justin-shi/services/trackbacks/55448.html</trackback:ping><description><![CDATA[     摘要:        Z么类(class)的成员函(member function)C能作为回调函?callback function)首先来看看回调函数有怎样的特炏Vwindows中,回调函都昑ּ(explicit)使用CALLBACK修饰W?decorator)修饰(decorated)。实际上CALLBACK是_stdcall参数?..  <a href='http://www.shnenglu.com/justin-shi/archive/2008/07/06/55448.html'>阅读全文</a><img src ="http://www.shnenglu.com/justin-shi/aggbug/55448.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/justin-shi/" target="_blank">q幽</a> 2008-07-06 03:58 <a href="http://www.shnenglu.com/justin-shi/archive/2008/07/06/55448.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于GetDC与GetWindowDChttp://www.shnenglu.com/justin-shi/archive/2008/06/26/54627.htmlq幽q幽Thu, 26 Jun 2008 00:27:00 GMThttp://www.shnenglu.com/justin-shi/archive/2008/06/26/54627.htmlhttp://www.shnenglu.com/justin-shi/comments/54627.htmlhttp://www.shnenglu.com/justin-shi/archive/2008/06/26/54627.html#Feedback0http://www.shnenglu.com/justin-shi/comments/commentRss/54627.htmlhttp://www.shnenglu.com/justin-shi/services/trackbacks/54627.html=============================================================

GetDc?/span>敎ͼ(x)用于获得hWnd参数所指定H口的客户区域的一个设备环境?/span>

所获得的设备环境可以是通用、类或者私有类型,具体由指定窗口的c风格决定。对于通用讑֤环境Q?/span>GetDc函数每次获取一个设备环境时都会(x)用默认属性对它进行初始化。该函数获得的类和私有设备环境会(x)与它们最后一ơ的讄保持一致。当讑֤环境不再需要时Q应该调?/span>ReleaseDC函数其释放?/span>   
    
GetWindowDC
函数Q返?/span>hWnd参数所指定的窗口的讑֤环境?/span>

获得的设备环境覆盖了整个H口Q包括非客户区)Q例如标题栏、菜单、滚动条Q以?qing)边框。这使得E序能够在非客户区域实现自定义图形,例如自定义标题或者边框。当不再需要该讑֤环境Ӟ需要调?/span>ReleaseDC函数释放讑֤环境。注意,该函数只获得通用讑֤环境Q该讑֤环境的Q何属性改变都不会(x)反映到窗口的U有或者类讑֤环境中(如果H口有的话)   
    
   ----------
摘自?/span>Delphi    Win32核心API参考?/span>

=============================================================



q幽 2008-06-26 08:27 发表评论
]]>
޺ݺۺϾþþþ | ϼþùƷӰԺ| þۺ97ɫֱ| þۺ| 99þùں;Ʒ1ӳ| þþƷר| ϼþùƷӰԺ| þùƷ99þþþþ | ݺɫݺɫۺϾþ| þþƷһ| 99þþþ| ӰһѾþþþþþþ | һþaþþƷ| ˼˼þúúȾƷ| þĻר| þӰԺҹƬ| AVһþ | һþaþþƷ| ŷպƷþþþ| yy6080þ| ޾Ʒþþþþ| ޹ƷþSM| ޾Ʒһþ | þþĻձ| ܻƺ۵վþmimiɫ| Ʒþþþþþö| þþƷ| ޹˾Ʒþþþþۺ | þþƷѹƬС| Ʒ99þþþþè| Ʒպŷþۺ| ŷպƷþþѹۿ| Ļþ| AV12þ| ƷþóӰԺ| ˾ƷۺϾþþ| 㽶99þùۺϾƷլ | Ʒ9999þþþ| þþƷ | þ99ȹоƷ| þþþùƷ鶹ARӰԺ|