from MicoAg:
[ VB2008 ]中如何使用 Copymemory API ?
下列說明:
1. ByVal、ByRef?
2. CopyMemory API 原型?
3. 何謂型別?
4. 範例。
1. ByVal、ByRef與VB6無差異, ByVal傳值與ByRef傳址。VB6預設參數為 ByRef,VB2005(.Net 1.0以後)改為 ByVal。
2. CopyMemory 是針對記憶體區塊做操作,很重要的參數 Destination、Source。
Destination [in] :A pointer to the starting address of the copied block's destination.
Source [in] :A pointer to the starting address of the block of memory to copy.
Length [in] :The size of the block of memory to copy, in bytes.
Destination、Source 都是以記憶體地址來操作,所以 ByVal、ByRef 傳值、傳址結果要指向記憶體地址
。
3. 型別?區分 (Value Type) 實值型別、(Reference Type) 參考型別、其他型別,在記憶體區塊配置有很大不同。
實值型別是將實際資料放在 Stack 區;而參考型別是將實際資料放在 Managed Heap 區,但是會將指標地址放在 Stack 區。Stack 記憶體區塊小,Heap 記憶體區塊為 2GB,Managed Heap 受.NET記憶體回收器(GC _ Garbage Collection)控管。
4.範例:From:MicoAg
Imports System.Runtime.InteropServices
Public Class Form1
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination
As Integer, ByVal Source As Integer, ByVal Length As Integer)
Private Declare Sub CopyMemoryDate Lib "kernel32" Alias "RtlMoveMemory" (ByVal
Destination As Integer, ByRef SourceDate As Date, ByVal Length As Integer)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles MyBase.Load
Dim tInt As Integer = &H4030201
Dim tLng As Long = &H807060504030201
Dim tSng As Single = 10.25
Dim tDouble As Double = 0.125
Dim tStr As String = "_MicoAg_"
Dim tArray() As Byte = {&H10, &H20, &H30, &H40}
Dim tDate As Date = Now
Dim B() As Byte
' (Value Type) 實值型別
ReDim B(3)
CopyMemory(VarPtr(B), VarPtr(tInt), 4)
ReDim B(7)
CopyMemory(VarPtr(B), VarPtr(tLng), 8)
ReDim B(3)
CopyMemory(VarPtr(B), VarPtr(tSng), 4)
ReDim B(7)
CopyMemory(VarPtr(B), VarPtr(tDouble), 8)
' (Reference Type) 參考型別
ReDim B(15)
CopyMemory(VarPtr(B), VarPtr(tstr), 16)
ReDim B(3)
CopyMemory(VarPtr(B), VarPtr(tArray), 4)
' 其他型別
ReDim B(8)
CopyMemoryDate(VarPtr(B), tDate, 8)
End Sub
Private Function VarPtr(ByVal e As Object) As Integer
Dim GC As GCHandle = GCHandle.Alloc(e, GCHandleType.Pinned)
Dim GC2 As Integer = GC.AddrOfPinnedObject.ToInt32
GC.Free()
Return GC2
End Function
End Class
有了 VarPtr(),相信VB6走向VB2008的使用者會很受用。
字串(string)複製到字串數組(byte()):
Imports System.Runtime.InteropServices
Public Class Form1
Private Declare Function MessageBox Lib "User32" Alias "MessageBoxA" (ByVal hWnd As Integer, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Integer) As Integer
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Integer, ByVal Source As Integer, ByVal Length As Integer)
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim sText As String = "Windows data type, string."
Dim bText As Byte()
ReDim bText(Strings.Len(sText) * 2 - 1)
MessageBox(Me.Handle, sText, "String", 0)
CopyMemory(VarPtr(bText), VarPtr(sText), bText.Length)
MessageBox(Me.Handle, System.Text.Encoding.Unicode.GetString(bText), "BYTE", 0)
End Sub
Private Function VarPtr(ByVal e As Object) As Integer
Dim GC As GCHandle = GCHandle.Alloc(e, GCHandleType.Pinned)
Dim GC2 As Integer = GC.AddrOfPinnedObject.ToInt32
GC.Free()
Return GC2
End Function
End Class
上面程式改成底下這樣也可以:
Public Class Form1
Private Declare Function MessageBox Lib "User32" Alias "MessageBoxA" (ByVal hWnd As Integer, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Integer) As Integer
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Byte(), ByVal Source As String, ByVal Length As Integer)
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim sText As String = "Windows data type, string."
Dim bText As Byte()
ReDim bText(Len(sText))
MessageBox(Me.Handle, sText, "String", 0)
CopyMemory(bText, sText, bText.Length)
MessageBox(Me.Handle, System.Text.Encoding.Default.GetChars(bText), "BYTE", 0)
End Sub
End Class
VC++:
#include <windows.h>
#include <stdio.h>
int WinMain(
HINSTANCE hInstance,
HINSTANCE hPreInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
//定義字串
LPSTR szString = "Windows data type, string.";
//定義字串數組
CHAR lpString[120]; //要大於szString的長度
//定義DWORD類型的資料
DWORD dwMax = 0xFFFFFFFF;
DWORD dwOne = 0x1;
//定義INT類型的資料
INT iMax = 0xFFFFFFFF;
INT iOne = 0x1;
//顯示字串
MessageBox(NULL,szString,"LPSTR",MB_OK);
//複製記憶體,將字串複製到數組中(包括NULL結束符號)
CopyMemory(lpString, szString, lstrlen(szString)+1);
//顯示複製的字串
MessageBox(NULL,lpString,"CHAR[]",MB_OK);
//比較DWORD並顯示結果
if(dwMax>dwOne)
{
MessageBox(NULL,"DWORD類型的資料0xFFFFFFFF > 0x1", "DWORD",MB_OK);
}
//比較INT並顯示結果
if(iMax < iOne)
{
MessageBox(NULL,"INT類型的資料0xFFFFFFFF < 0x1", "INT", MB_OK);
}
return 0;
}
WinBase.h:
#define MoveMemory RtlMoveMemory
#define CopyMemory RtlCopyMemory
#define FillMemory RtlFillMemory
#define ZeroMemory RtlZeroMemory
#define SecureZeroMemory RtlSecureZeroMemory
#define CaptureStackBackTrace RtlCaptureStackBackTrace
WinNT.h:
#define RtlEqualMemory(Destination,Source,Length) (!memcmp((Destination),(Source),(Length)))
#define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length))
#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length))
#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length))
#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))
MSDN:
void CopyMemory(
__in PVOID Destination,
__in const VOID *Source,
__in SIZE_T Length
);
Parameters
Destination [in]
A pointer to the starting address of the copied block's destination.
Source [in]
A pointer to the starting address of the block of memory to copy.
Length [in]
The size of the block of memory to copy, in bytes.
Return Value
This function has no return value.
Remarks
This function is defined as the RtlCopyMemory function. Its implementation is provided inline. For more information, see Winbase.h and Winnt.h.
If the source and destination blocks overlap, the results are undefined. For overlapped blocks, use the MoveMemory function.
沒有留言:
張貼留言