CopyMemory函数的应用两则

例则1:利用VB调用windows api函数来编写比较复杂的程序时,大家比较普遍遇到

的问题是很多API函数中使用到了指针调用,而VB本身并不支持指针的调用,所以在使

用了有些API之后,获得的只是指向想要获取的数据的32位指针,而无法得到具体的数

据,看下面的例子:

    Windows API中有一个Choosefont函数,这个函数可以弹出字体选择对话框让用户选择字体并且返回选择的字体类型、大小

等信息,这个函数在Windows API Help中是这样定义的:

 

BOOL ChooseFont(

    LPCHOOSEFONT lpcf        // pointer to structure with initialization data

   );

    参数lpcf是一个指向一个CHOOSEFONT结构的指针,而CHOOSEFONT结构的定义是这样的:

typedef struct {    // cf 

    DWORD        lStructSize;

    HWND         hwndOwner;

    HDC          hDC;

    LPLOGFONT    lpLogFont;

    INT          iPointSize;

    DWORD        Flags;

    DWORD        rgbColors;

    LPARAM       lCustData;

    LPCFHOOKPROC lpfnHook;

    LPCTSTR      lpTemplateName;

    HINSTANCE    hInstance;

    LPTSTR       lpszStyle;

    WORD         nFontType;

    WORD         ___MISSING_ALIGNMENT__;

    INT          nSizeMin;

 

    INT          nSizeMax;

} CHOOSEFONT;

其中的成员lpLogFont又是一个指向一个LOGFONT结构的指针,而该指针指向的

LOGFONT结构的内存缓冲区中保存的正是用户选择的字体的信息,如果按照正常的VB

调用Windows API的方式,我们获得的只是一个32位的整型指针。那么在这里就要使用

CopyMemory函数了。下面的具体的程序:

       建立一个新的工程,将Form1Name属性改变为Dialog,然后在Form中加入两个

CommandButton控件,Name属性分别改变为cmdShowFontcmdShowColorCaption

性分别改变为“选择字体”和“选择颜色”在Form中加入一个PictureBox控件,将它的

Name属性改变为txtColor,加入一个TextBox控件,将它的Name属性改变为txtResult

Dialog窗口的窗口界面入图1所示:


       然后在Dialog窗口的代码窗口中加入以下的代码:

Option Explicit

 

Private Sub cmdShowFont_Click()

   Dim myfont As CHOOSEFONT

   Dim mylog As LOGFONT

   Dim ret As Long

   Dim lMem As Long

   Dim astr As String * 32

   Dim bstr As String

   Dim i As Integer

     

   lMem = GlobalAlloc(0, 60)

   CopyMemoryM2P lMem, mylog.lfHeight, 60

   myfont.lpLogFont = lMem

   With myfont

       .lStructSize = Len(myfont)

       .flags = CF_SCREENFONTS Or CF_EFFECTS Or CF_INITTOLOGFONTSTRUCT 'Or CF_ENABLEHOOK

       .hwndOwner = Me.hWnd

       .iPointSize = 100

   End With

  

   ret = CHOOSEFONT(myfont)

   If ret <> 0 Then

      CopyMemoryP2M mylog.lfHeight, lMem, 60

      txtColor.BackColor = myfont.rgbColors

      CopyMemoryH2S astr, mylog.lfFaceName(0), 32

      Debug.Print mylog.lfCharSet, mylog.lfHeight, mylog.lfWeight, mylog.lfWidth

      bstr = Left$(astr, (InStr(astr, Chr(0)))) + vbNullChar

      txtResult.Text = "选择的字体为:" + bstr

      txtResult.Text = txtResult.Text + "大小为:" + Str(myfont.iPointSize / 10)

   End If

   GlobalFree lMem

End Sub

 

Private Sub cmdShowColor_Click()

  Dim mycolor As ChooseColor

  Dim ret As Long

 

  With mycolor

     .lStructSize = Len(mycolor)

     .hwndOwner = Me.hWnd

     .flags = 0

     .lpCustColors = String$(16 * 4, 0)

  End With

 

  ret = ChooseColor(mycolor)

 

  If ret <> 0 Then

     txtColor.BackColor = mycolor.rgbResult

     txtResult.Text = "选择的颜色为:" & mycolor.rgbResult

  End If

End Sub

       在工程文件中加入一个Modules文件,将文件保存为dlg.bas文件,然后在dlg.bas

文件中加入以下代码:

Option Explicit

 

Declare Function ChooseColor Lib "comdlg32.dll" Alias "ChooseColorA" (pChoosecolor As ChooseColor) As Long

 

Type ChooseColor

     lStructSize As Long

     hwndOwner As Long

     hInstance As Long

     rgbResult As Long

     lpCustColors As String

     flags As Long

     lCustData As Long

     lpfnHook As Long

     lpTemplateName As String

End Type

 

 

Declare Function CHOOSEFONT Lib "comdlg32.dll" Alias "ChooseFontA" (pChoosefont As CHOOSEFONT) As Long

 

Public Declare Sub CopyMemoryP2M Lib "kernel32" Alias "RtlMoveMemory" (hpvDest As Any, ByVal _

    hpvSource As Long, ByVal cbCopy As Long)

Public Declare Sub CopyMemoryM2P Lib "kernel32" Alias "RtlMoveMemory" (ByVal hpvDest As Long, _

    hpvSource As Any, ByVal cbCopy As Long)

Public Declare Sub CopyMemoryH2S Lib "kernel32" Alias "RtlMoveMemory" (ByVal dst As String, _

    src As Any, ByVal SIZE As Long)

 

 

Public Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long

Public Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long

 

Public Const GMEM_FIXED = &H0

Public Const CF_EFFECTS = &H100&

Public Const CF_SCREENFONTS = &H1

Public Const CF_INITTOLOGFONTSTRUCT = &H40&

Public Const CF_ENABLEHOOK = &H8&

 

Public Const BOLD_FONTTYPE = &H100

Public Const ITALIC_FONTTYPE = &H200

 

Declare Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Long

 

Const LF_FACESIZE = 32

Public Const WM_USER = &H400

Public Const WM_CHOOSEFONT_GETLOGFONT = (WM_USER + 1)

 

Public Type LOGFONT

        lfHeight As Long

        lfWidth As Long

        lfEscapement As Long

        lfOrientation As Long

        lfWeight As Long

        lfItalic As Byte

        lfUnderline As Byte

        lfStrikeOut As Byte

        lfCharSet As Byte

        lfOutPrecision As Byte

        lfClipPrecision As Byte

        lfQuality As Byte

        lfPitchAndFamily As Byte

        lfFaceName(0 To LF_FACESIZE - 1) As Byte

End Type

 

Public Type CHOOSEFONT

        lStructSize As Long

        hwndOwner As Long      '  caller's window handle

        hdc As Long             '  printer DC/IC or NULL

        lpLogFont As Long       

        iPointSize As Long          '  10 * size in points of selected font

        flags As Long              '  enum. type flags

        rgbColors As Long        '  returned text color

        lCustData As Long         '  data passed to hook fn.

        lpfnHook As Long         '  ptr. to hook function

        lpTemplateName As String  '  custom template name

        hInstance As Long         '  instance handle of.EXE that

                                '    contains cust. dlg. template

        lpszStyle As String         '  return the style field here

                                '  must be LF_FACESIZE or bigger

        nFontType As Integer        same value reported to the EnumFonts

                                '    call back with the extra FONTTYPE_

                                '    bits added

        MISSING_ALIGNMENT As Integer

        nSizeMin As Long         '  minimum pt size allowed &

        nSizeMax As Long         '  max pt size allowed if

                                 '    CF_LIMITSIZE is used

End Type

Function CFHookproc(ByVal hDLG As Long, ByVal uiMsg As Long, ByVal wparam As Long, ByVal lparam As Long) As Long

    If uiMsg = &H112 Then

        Debug.Print wparam, lparam

    End If

    CFHookproc = 0

End Function

       运行上面的程序,点击“选择字体”,然后在弹出的字体选择对话框中选择任意的字体

后点击“确定”按钮,选择的字体和字体大小信息就会出现在txtResult文本框中。

通过上面的程序可以看到,利用CopyMemory函数可以将一个内存指针指向的内存缓

冲区的内容拷贝到VB中定义的字符串数组、数据结构中。

 

例则2:文本的拷贝

       在工程文件的Form1中加入一个CommandButton控件和两个TextBox控件,然后在

Form1的代码窗口中加入以下代码:

Private Declare Sub CopyMemoryH2S Lib "kernel32" Alias _

        "RtlMoveMemory" (ByVal dst As String, ByVal _

        src As Long, ByVal SIZE As Long)

Private Declare Sub CopyMemoryS2H Lib "kernel32" Alias _

        "RtlMoveMemory" (ByVal dst As Long, ByVal src _

        As String, ByVal SIZE As Long)

 

Private Declare Function GlobalAlloc Lib "kernel32" (ByVal _

        wFlags As Long, ByVal dwBytes As Long) As Long

Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem _

        As Long) As Long

 

Const GMEM_FIXED = &H0

 

Private Sub Command1_Click()

    Dim mHandle As Long

    Dim astr As String * 256

    Dim bstr As String * 256

   

    astr = Left$(Text1.Text, 255)

    '分配一个300字节的内存块

    mHandle = GlobalAlloc(GMEM_FIXED, 300)

    '将字符串中的内容拷贝到分配的内存块中

    CopyMemoryS2H mHandle, astr, 255

    '将内存块的内容拷贝到字符串中

    CopyMemoryH2S bstr, mHandle, 255

    Text2.Text = bstr

    GlobalFree mHandle

End Sub

       运行程序,点击Command1,可以看到Text1中的文本内容拷贝到了text2中。

       通过上面的两个范例可以看到,通过定义CopyMemory函数的不同变体,可以实现

内存中任意两块区域的拷贝,也可以在Windows中分配的内存和VB中定义的字符串、

数据结构之间互相拷贝,利用这个函数可以实现Windows中一些指针套指针的API调用

同时也简化了一些VB中关于内存的操作。例如在编写文本处理程序时就可以向上面范例

2中所示的一样,使用GlobalAlloc函数分配内存,使用CopyMemory函数在内存、文本控

件之中相互被数据,而不用定义一个个的String来操作数据。