用VarPtr传给CopyMemory拷贝字符串 为啥结果不正确
Option ExplicitDeclare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (pDest As Any, pSource As Any, ByVal byteLen As Long)Sub test2() Dim String1 As String Dim String2 As String Dim pString1 As Long String1 = "PowerVB" String2 = String$(7, 0) 'Try three: Get the string's pointer from VarPtr CopyMemory pString1, ByVal VarPtr(String1), 4 CopyMemory ByVal String2, ByVal pString1, 14 Debug.Print String2 '得到的不是PowerVB,而是“P o w e”?为什么?End Sub
Sub test2() Dim String1 As String Dim String2 As String Dim pString1 As Long String1 = "PowerVB" String2 = String$(14, 0) 'Try three: Get the string's pointer from VarPtr CopyMemory pString1, ByVal VarPtr(String1), 4 CopyMemory ByVal String2, ByVal pString1, 14 Debug.Print StrConv(String2, vbFromUnicode) '得到的不是PowerVB,而是“P o w e”?为什么?End Sub
[解决办法]
Sub test2() Dim String1 As String Dim String2 As String Dim pString1 As Long String1 = "PowerVB" String2 = String$(7, 0) 'Try three: Get the string's pointer from VarPtr CopyMemory pString1, StrPtr(String1), 4 CopyMemory ByVal StrPtr(String2), ByVal pString1, 14 Debug.Print String2 '得到的不是PowerVB,而是“P o w e”?为什么?End Sub
[解决办法]
CopyMemory pString1, ByVal VarPtr(String1), 4
CopyMemory String2, pString1, 14
[解决办法]
Sub test2() Dim String1 As String Dim String2 As String Dim pString1 As Long String1 = "PowerVB" String2 = String$(14, 0) 'Try three: Get the string's pointer from VarPtr CopyMemory pString1, VarPtr(String1), 4 CopyMemory String2, ByVal pString1, 4 Debug.Print StrConv(String2, vbFromUnicode) '得到的不是PowerVB,而是“P o w e”?为什么?End Sub
[解决办法]
没注意到你的代码
这样才对
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (pDest As Any, pSource As Any, ByVal byteLen As Long)Sub test2() Dim String1 As String Dim String2 As String Dim pString1 As Long String1 = "PowerVB" String2 = Space$(Len(String1))' pString1 = Space$(Len(String1)) CopyMemory pString1, ByVal VarPtr(String1), 4 CopyMemory ByVal StrPtr(String2), ByVal (pString1), LenB(String2) Debug.Print String2 '得到的不是PowerVB,而是“P o w e”?为什么?End Sub
------解决方案--------------------
CopyMemory ByVal String2, ByVal pString1, 14
[解决办法]
通俗易懂 还不出错
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal byteLen As Long)Sub test2() Dim String1 As String Dim String2 As String Dim pString1 As Long Dim pString2 As Long String1 = "PowerVB" String2 = Space$(Len(String1)) CopyMemory pString1, String1, 4 CopyMemory pString2, String2, 4 CopyMemory pString2, pString1, LenB(String1) Debug.Print String2End Sub
[解决办法]
Option ExplicitPrivate Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (pDest As Any, pSource As Any, ByVal byteLen As Long)Sub test2() Dim String1 As String Dim String2 As String Dim pString1 As Long String1 = "PowerVB" String2 = String$(7, 0) 'Try three: Get the string's pointer from VarPtr CopyMemory pString1, ByVal VarPtr(String1), 4 CopyMemory String2, pString1, Len(String2) Debug.Print StrConv(String2, vbFromUnicode) '得到的是PowerVBEnd SubPrivate Sub Command1_Click() test2End Sub
[解决办法]
Option ExplicitPrivate Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (pDest As Any, pSource As Any, ByVal byteLen As Long)Sub test2() Dim String1 As String Dim String2 As String Dim pString1 As Long Dim lngA As Long String1 = "PowerVB" String2 = String$(7, 0) lngA = VarPtr(String1) 'Try three: Get the string's pointer from VarPtr CopyMemory pString1, ByVal lngA, LenB(pString1) CopyMemory String2, pString1, 14 Debug.Print String2 '得到的不是PowerVB,而是“P o w e”?为什么?End SubPrivate Sub Command1_Click() Call test2End Sub
[解决办法]
千万别用没分配内存的指针(pString1)来拷贝,否则很容易崩溃的
[解决办法]
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)Private Function GetStringLenght(ByVal strString As String) As Integer Dim nLen As Integer Dim oneChar As String Dim i As Integer GetStringLenght = 0 nLen = Len(strString) For i = 1 To nLen oneChar = Mid(strString, i, 1) If CLng("&H" & Hex(AscW(oneChar))) > 255 Then '具体汉字的编码范围可以再查证,这里只是做一个推测。 GetStringLenght = GetStringLenght + 2 Else GetStringLenght = GetStringLenght + 1 End If Next iEnd FunctionPrivate Sub Form_Load()Dim String1C As String, String1E As String Dim String2_7 As String, String2_14 As String Dim String2_1C As String Dim String2_1E As String Dim nLenght As Integer String1C = "我有点Slow" String1E = "WYDSlow" nLenght = GetStringLenght(String1C) String2_1C = Space(nLenght) CopyMemory ByVal String2_1C, ByVal String1C, nLenght Debug.Print String2_1C & "*", Len(String2_1C),nLenght nLenght = GetStringLenght(String1E) String2_1E = Space(nLenght) CopyMemory ByVal String2_1E, ByVal String1E, nLenght Debug.Print String2_1E & "*", Len(String2_1E),nLenghtEnd Sub
[解决办法]
整如36楼所说的,操作系统为了保护自己,会强行关闭它自认为潜在的“威胁”。而一旦保护不了,而且出错,就出现所谓的“蓝屏”
[解决办法]
'说明'XX - 源值确定 And 目标溢出'?? - 源值不确定'?X - 源值不确定 And 目标溢出String1C = "我有点Slow"'Unicode : 11-62-09-67-B9-70-53-00-6C-00-6F-00-77-00'Ansi : CE-D2-D3-D0-B5-E3-53-6C-6F-77String1E = "WYDSlow"'Unicode : 57-00-59-00-44-00-53-00-6C-00-6F-00-77-00'Ansi : 57-59-44-53-6C-6F-77String2_7 = String$(7, 0)'Unicode : 00-00-00-00-00-00-00-00-00-00-00-00-00-00'Ansi : 00-00-00-00-00-00-00String2_14 = String$(14, 0)'Unicode : 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00'Ansi : 00-00-00-00-00-00-00-00-00-00-00-00-00-00CopyMemory ByVal String2_7, ByVal String1C, 7 '例1 我有点S* 4 8'Ansi : CE-D2-D3-D0-B5-E3-53 ;复制 7 字节'Unicode : 11-62-09-67-B9-70-53-00CopyMemory ByVal String2_14, ByVal String1C, 7 '例2 我有点S * 11 22'Ansi : CE-D2-D3-D0-B5-E3-53-00-00-00-00-00-00-00 ;复制 7 字节,后 7 字节不变'Unicode : 11-62-09-67-B9-70-53-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00CopyMemory ByVal String2_7, ByVal String1E, 7 '例3 WYDSlow* 7 14'Ansi : 57-59-44-53-6C-6F-77 ;复制 7 字节'Unicode : 57-00-59-00-44-00-53-00-6C-00-6F-00-77-00CopyMemory ByVal String2_14, ByVal String1E, 7 '例4 WYDSlow * 14 28'Ansi : 57-59-44-53-6C-6F-77-00-00-00-00-00-00-00 ;复制 7 字节,后 7 字节不变'Unicode : 57-00-59-00-44-00-53-00-6C-00-6F-00-77-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00CopyMemory ByVal String2_7, ByVal String1C, 14 '例5 我有点S* 4 8'Ansi : CE-D2-D3-D0-B5-E3-53-XX-XX-XX-?X-?X-?X-?X ;复制 14 字节,后 7 字节溢出(丢弃)'Unicode : 11-62-09-67-B9-70-53-00CopyMemory ByVal String2_14, ByVal String1C, 14 '例6 我有点Slow * 11 22'Ansi : CE-D2-D3-D0-B5-E3-53-6C-6F-77-??-??-??-?? ;复制 14 字节,后 4 字节不确定'Unicode : 11-62-09-67-B9-70-53-00-6C-00-6F-00-77-00-??... ;长度也不确定CopyMemory ByVal String2_7, ByVal String1E, 14 '例7 WYDSlow* 7 14'Ansi : 57-59-44-53-6C-6F-77-?X-?X-?X-?X-?X-?X-?X ;复制 14 字节,后 7 字节溢出(丢弃)'Unicode : 57-00-59-00-44-00-53-00-6C-00-6F-00-77-00CopyMemory ByVal String2_14, ByVal String1E, 14 '例8 WYDSlow * 14 28'Ansi : 57-59-44-53-6C-6F-77-??-??-??-??-??-??-?? ;复制 14 字节,后 7 字节不确定'Unicode : 57-00-59-00-44-00-53-00-6C-00-6F-00-77-00-??... ;长度也不确定CopyMemory ByVal String2_7, ByVal String1C, 28 '例9 我有点S* 4 8'Ansi : CE-D2-D3-D0-B5-E3-53-XX-XX-XX-?X-?X-?X... ;复制 28 字节,后 21 字节溢出(丢弃)'Unicode : 11-62-09-67-B9-70-53-00CopyMemory ByVal String2_14, ByVal String1C, 28 '例10 我有点Slow * 11 22'Ansi : CE-D2-D3-D0-B5-E3-53-6C-6F-77-??-??-??-??-?X... ;复制 28 字节,4 字节不确定,后 14 字节溢出(丢弃)'Unicode : 11-62-09-67-B9-70-53-00-6C-00-6F-00-77-00-??... ;长度也不确定CopyMemory ByVal String2_7, ByVal String1E, 28 '例11 WYDSlow* 7 14'Ansi : 57-59-44-53-6C-6F-77-?X-?X-?X-?X-?X-?X-?X... ;复制 28 字节,后 21 字节溢出(丢弃)'Unicode : 57-00-59-00-44-00-53-00-6C-00-6F-00-77-00CopyMemory ByVal String2_14, ByVal String1E, 28 '例12 WYDSlow * 14 28'Ansi : 57-59-44-53-6C-6F-77-??-??-??-??-??-??-??-?X... ;复制 28 字节,7 字节不确定,后 14 字节溢出(丢弃)'Unicode : 57-00-59-00-44-00-53-00-6C-00-6F-00-77-00-??... ;长度也不确定
[解决办法]
其实CopyMemory等函数是VB学习者的一个槛,过了这个槛技术水平就要“上升”一个层次可。
[解决办法]
可以说理解一半,也有理解错了的,不是api把什么当做是Ansi,而是你自己要区分字符串类型,vb默认是unicode.
其实你写的函数不需要那么复杂直接这么就可以了
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(pDest As Any, pSource As Any, ByVal byteLen As Long)
Sub test2()
Dim String1 As String
Dim String2 As String
Dim pString1 As Long
String1 = "PowerVB"
String2 = String$(7, 0)
'Try three: Get the string's pointer from VarPtr
' CopyMemory pString1, ByVal VarPtr(String1), 4
' CopyMemory ByVal String2, ByVal pString1, 14
CopyMemory ByVal String2, ByVal String1, 7
Debug.Print String2 '得到的不是PowerVB,而是“P o w e”?为什么?
End Sub
[解决办法]
好了我刚才稍微验证了一下的出结论了
写下测试代码如下:
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(pDest As Any, pSource As Any, ByVal byteLen As Long)
Sub test2()
Dim String1 As String
Dim String2 As String
Dim pString1 As Long
String1 = "PowerVB"
String2 = String$(14, 0)
'Try three: Get the string's pointer from VarPtr
' CopyMemory pString1, ByVal VarPtr(String1), 4
' CopyMemory ByVal String2, ByVal pString1, 14
CopyMemory ByVal String2, ByVal StrPtr(String1), 14
Debug.Print StrConv(String2, vbFromUnicode) '这时字符串是一个Unicode字符串所以要打印出来需要转换一下
End Sub
Private Sub Form_Load()
test2
End Sub
从这里代码可以看出VB默认是按Unicode处理是正确的
因为StrPtr(String1)得到的是字符串在内存中的开始地址
那么这段地址指向的就是一串Unicode字符串我用内存察看工具也再次验证
这时我们分配的内存就应该是14个字节不然只能拷贝一半
再看下面代码
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(pDest As Any, pSource As Any, ByVal byteLen As Long)
Sub test2()
Dim String1 As String
Dim String2 As String
Dim pString1 As Long
String1 = "PowerVB"
String2 = String$(7, 0)
'Try three: Get the string's pointer from VarPtr
' CopyMemory pString1, ByVal VarPtr(String1), 4
' CopyMemory ByVal String2, ByVal pString1, 14
CopyMemory ByVal String2, ByVal String1, 7
Debug.Print String2
End Sub
Private Sub Form_Load()
test2
End Sub
这是因为有了vb内部修饰符号Byval 所以vb会自动转换成Ansi字符串所以我们申请的内存只需要7个字节就行了
[解决办法]
Option Explicit
'Ansi版(中文)
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(pDest As Any, pSource As Any, ByVal byteLen As Long)
Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As String) As Long
Sub test2()
Dim String1 As String
Dim String2 As String
Dim Length As Long
String1 = "abc我爱你"
Length = lstrlen(String1)
String2 = String$(Length, 0)
CopyMemory ByVal String2, ByVal String1, Length
Debug.Print String2
End Sub
Private Sub Form_Load()
test2
End Sub
[解决办法]
Option Explicit
'Unicode版(中文)
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(pDest As Any, pSource As Any, ByVal byteLen As Long)
Private Declare Function lstrlenA Lib "kernel32" (ByVal lpString As String) As Long
Sub test2()
Dim String1 As String
Dim String2 As String
Dim Length As Long
String1 = "abc我爱你"
Length = LenB(String1)
String2 = String$(Length, 0)
'或者直接转换成Ansi就用
'CopyMemory ByVal StrPtr(String2), ByVal StrPtr(String1), Length
CopyMemory ByVal String2, ByVal StrPtr(String1), Length
Debug.Print StrConv(String2, vbFromUnicode)
End Sub
Private Sub Form_Load()
test2
End Sub
[解决办法]
VB 对所有 API 中的 String 参数,调用前进行 Unicode-Ansi 转换,调用后进行 Ansi-Unicode 转换。
------解决方案--------------------