VB 6でCopyMemoryで文字列をコピーする様々な猫飽き(四)
下记の文章の原始出典と作者の情报と本声明の作者:xixixi出典:http://blog.csdn.net/slowgrace/archive/2009/09/14/4550530.aspx
本文はこの帖の冗長な討論から来て、Tigerに感謝しますZhaoの全行程の指点と陳輝、阿勇、馬雲剣など多くの友达の熱心な参加.本文のその他の部分は:(一)、(二)、(三).
第4節CopyMemoryで文字列を正しくコピーする方法
こんなに多くの問題のあるコードを分析して、CopyMemoryで文字列を正確にコピーする方法を見てみましょう.仮にString 1=「ちょっとSlow」
(1)最も簡単な迷惑をかけない方法は,直接住所を伝えることである.次のように
この方法はUA/AU変換に係わらず、コピーするのがUnicode文字列そのものであるため、バイト数はLenB(String 1)とすればよいが、String 2の初期長さはString 1のすべての文字を受け入れればよいのでLen(String 1)とする.注意:1つはLenB、1つはLen、混同しないでください.
(2)あるいはあなたはVBのお母さんが煩わしいことを嫌がらないで、下のようにします
ここでコピーするバイト数とString 2の初期化文字数は、lngALen、すなわちString 1に対応するANSI文字列のバイト数である.これは、CopyMemoryに伝達されるのは、実際にはANSI文字列の一時変数であるからである.tmp 1なので、コピーするバイト数はもちろんこれで計算します.一方、String 2は、初期にlngALen個0になった後(0文字あたり2バイトを占める)、対応するANSI文字列のバイト数(0文字あたり1バイトに縮小)がlngALenとなり、変換後のANSI文字列_tmp 2は完全な_を受信することができるtmp 1の文字列.
なお、このような用法では、String 2の初期長さがその最終長さに等しくなる必要はないことに注意してください.String 2の文字列バッファはAPI関数呼び出しが完了した後に再割り当てされるため、string 2の初期長さは_tmp 1のLenB長が決まる.完全なコードを添付します.
'文字列バッファをコピーする方法:正しいSubtest 7_CpyBuf() Dim lngALen As Long String1 = STR_C'14 bytes lngALen=LenB(StrConv(String 1,vbFromUnicode)'変換後のANSI文字列_tmp 2は完全な_を受信することができるtmp 1 String 2=String$(lngALen,0)CopyMemory ByVal String 2,ByVal String 1,lngALen'はUA/AU変換がなく、すべてが楽なマルチString 2=String$(Len(String 1),0)'14 bytesは、String 1と同じ大きさでOK'CopyMemory ByVal StrPtr(String 2),ByVal StrPtr(String 1),LenB(String 1)Debug.Print String 2&"*"End Sub"
推奨手法には,ターゲットアドレスとソースアドレスの対称性という共通の特徴が見られる.もしLongが両方ともLongを伝えるならば、もし文字列が両方とも文字列を伝えるならば、このようにしてやっと正しい結果を得ることができます;もし1つのアドレスがLongを伝えるならば、1つのアドレスが文字列を伝えるならば、それは問題が発生して、原因、実はVBのお母さんが1つに対してUA/AC変換をしたためで、もう1つに対してしていないで、互いに番号に合わないで、もっと余分な文を加えて修正します.
また、次の2つの数字を正しく処理することに注意してください.
(1)CopyMemoryの3番目のパラメータbyteLen.ソースアドレスパラメータがUA/AU変換に関与するか否かにより、該当する場合は対応するANSI文字列のバイト数をとり、該当しない場合はそのままLenB(String 1)
(2)String 2の初期文字数(文字数がバイト数ではないことに注意).対象アドレスパラメータがUA/AU変換に関与するか否かにより、該当するANSI文字列のバイト数がbyteLenに等しく、該当しない場合はUnicode文字列のバイト数がbyteLenに等しいことが保証される.
第五節練習:これらの返事は全部読めますか.
(二)、(三)詳しく議論したほか、多くの友达がこの投稿に自分の修正コードを提供しているので、一度練習として本稿の学習成果を固めてみてはいかがでしょうか.以下のように総説する.
8階、正しいです.
これは実際に0階コードの直接修正です.まずString 2の長さを拡張して対応する_tmp 2の長さは十分である.最後にUA変換をしてVBが多くしたAU変換を相殺します.
9階、正しいです.
UA/AU変換なしで文字列バッファを直接コピーします.
12階、正しいです.
UA/AU変換なしで文字列バッファを直接コピーします.
15階(1)、正しいです.
目的とソースを同時にUA/AU変換し、文字列バッファを直接コピーします.
15階(2)、正しいです.
UA/AU変換なしで文字列バッファを直接コピーします.
22階、間違いです.
同じ10階です.248階で説明します.
23階、間違いです.
同じ10階です.248階で説明します.
38階です.正しいです.
文字列パラメータを直接渡すには、正しい結果を得るには、対バイト数を計算することが重要です.悪い神はASCI文字列が占めるバイト数を計算するために関数を書いたので、正しい結果を得ることができます.しかし、このGetStringLength関数は、LenB(StrConv(「ちょっとslow」,vbFromUnicode))という文に完全に簡略化できると思います.
46階、正しいです.
同じ15階の最初の方法です.
50階(1)、正しいです.
同じ8階です.
50階(2)、正しいです.
同じ15階の最初の方法です.(ただし、解釈は完全に正確ではありません:)
57階です.正しいです.
これは実は15階の最初の方法と同じですが、もっと通用します.文字列パラメータを直接渡す場合は、ANSI文字列でバイトを計算します.
58階、完全に正確ではありません.
String 2の初期化長さはLen(String 1)とすればよい.
62階です.正しいです.
ByVal VarPtr(ByVal String 1)を使って、ほほほ、本当に回ります.
129階、間違いです.
文字列バッファポインタをコピーすると、メモリが繰り返し解放されます.134141階の説明を参照してください.
165階、正しいです.同じ9階です.
しかし,LenとLenB関数を用いてコードをより汎用化した.
231階、間違いです.
文字列バッファポインタをコピーすると、メモリとメモリの重複解放が発生します.134141階の説明を参照してください.
237階、間違いです.
文字列バッファポインタをコピーすると、メモリとメモリの重複解放が発生します.134141階の説明を参照してください.
第六節補足質問
6.1メモリの表示方法
実はCopyMemory関数を熟知するには、推測するよりメモリを直接見るほうがいいです.メモリをどう思いますか?ターゲットアドレスのメモリCopyMemoryを配列に入れ、1バイトずつHexすることができます.メモリを分析するには、常にこのようにする必要があります.
また、いくつかの補助デバッグツールも使用できます.たとえば、OllyDbg:RING 3のデバッグツールは、各変数値またはレジスタの値をリアルタイムで参照するために使用できます.たとえば、Idaや氷の刃などの静的逆アセンブリのツールは、高度な言語の実際の実行動作を理解するのに役立ちます.
6.2 VB 6でAPIを呼び出して文字列パラメータを使う時UA/AU変換を避けることができますか
VBはAPIを呼び出して、いつも1つの仲介を通って、msvbvm 60.dllの中のDllFunctionCall、これはUA/AU変換の始業者です.自分で定義したTLBを利用してDllFunctionCallを迂回すると、文字列はUA/AU変換されません.
6.3すべてのAPI関数は文字列パラメータをANSI文字列として処理しますか
答えは?API関数の中には、そうでないものもあります.Unicode文字列を期待するAPI関数(W版APIとなる)については,VB呼び出しで文字列パラメータに渡すと問題が発生する.VBはAPI関数が何を期待しているのか気にしないので、ANSI文字列に頭を回して伝えます.したがって、異なるタイプのAPIについては、このブログを参照してください.
第七節全文の概要
VB 6でCopyMemory関数を使って正しいコピー文字列を使うのはちょっとうるさいです.本文はいくつかの経典コードを分析することを通じて、この中の各方面の知識を紹介した.
(1)VB 6による文字列パラメータの自動UA/AU変換機構
(2)VBにおける文字列について:BSTR構造、StrPtrおよびVtrPtr関数の意味、文字列メモリの初期化、文字列符号化の表示方法、VB 6が文字列変数を解放する方法など.
(3)CopyMemory関数について;その様々な異なる形式のパラメータの意味、上書きをどのように自動的に処理するか、VB 6がCopyMemoryを呼び出した後にString 2の長さをどのように決定するかなど.
(4)その他の内容:大端順、小端順、ANSI符号化メモリ構造、スタック、VBクラッシュに関する処理、メモリの表示方法、TlbでUA/AU変換を避ける方法など.
添付:クラシックコードセグメントインデックス
第1節:詳細図、“表”はand“文字”はVB 6の文字列パラメータに対する自動UA/AU変換機構を示す.
第3節:例1:非対称のパラメータ形式は非対称のUA/AU変換を招き、その後初期化バイト数が足りず結果が短縮される.例2:非対称のパラメータ形式は非対称のUA/AU変換をもたらし、「むくみ」の結果を得た;例3:String 1パスパラメータを直接使用することによる危険な結果.例4、この値がアドレスに渡された後の結果.例5、中国語と英語が混在する文字列はどのようにバイト数を計算するか.例6,危険な置換ポインタ法.
第四節:正しい方法の剖析.
第五節:超多他のコードの簡単な分析.
全文が終わる
本文はこの帖の冗長な討論から来て、Tigerに感謝しますZhaoの全行程の指点と陳輝、阿勇、馬雲剣など多くの友达の熱心な参加.本文のその他の部分は:(一)、(二)、(三).
第4節CopyMemoryで文字列を正しくコピーする方法
こんなに多くの問題のあるコードを分析して、CopyMemoryで文字列を正確にコピーする方法を見てみましょう.仮にString 1=「ちょっとSlow」
(1)最も簡単な迷惑をかけない方法は,直接住所を伝えることである.次のように
String2 = String$(Len(String1), 0) '14 bytes, String1 OK
CopyMemory ByVal StrPtr(String2), ByVal StrPtr(String1), LenB(String1)
この方法はUA/AU変換に係わらず、コピーするのがUnicode文字列そのものであるため、バイト数はLenB(String 1)とすればよいが、String 2の初期長さはString 1のすべての文字を受け入れればよいのでLen(String 1)とする.注意:1つはLenB、1つはLen、混同しないでください.
(2)あるいはあなたはVBのお母さんが煩わしいことを嫌がらないで、下のようにします
lngALen = LenB(StrConv(String1, vbFromUnicode))
String2 = String$(lngALen, 0)
CopyMemory ByVal String2, ByVal String1, lngALen
ここでコピーするバイト数とString 2の初期化文字数は、lngALen、すなわちString 1に対応するANSI文字列のバイト数である.これは、CopyMemoryに伝達されるのは、実際にはANSI文字列の一時変数であるからである.tmp 1なので、コピーするバイト数はもちろんこれで計算します.一方、String 2は、初期にlngALen個0になった後(0文字あたり2バイトを占める)、対応するANSI文字列のバイト数(0文字あたり1バイトに縮小)がlngALenとなり、変換後のANSI文字列_tmp 2は完全な_を受信することができるtmp 1の文字列.
なお、このような用法では、String 2の初期長さがその最終長さに等しくなる必要はないことに注意してください.String 2の文字列バッファはAPI関数呼び出しが完了した後に再割り当てされるため、string 2の初期長さは_tmp 1のLenB長が決まる.完全なコードを添付します.
'文字列バッファをコピーする方法:正しいSubtest 7_CpyBuf() Dim lngALen As Long String1 = STR_C'14 bytes lngALen=LenB(StrConv(String 1,vbFromUnicode)'変換後のANSI文字列_tmp 2は完全な_を受信することができるtmp 1 String 2=String$(lngALen,0)CopyMemory ByVal String 2,ByVal String 1,lngALen'はUA/AU変換がなく、すべてが楽なマルチString 2=String$(Len(String 1),0)'14 bytesは、String 1と同じ大きさでOK'CopyMemory ByVal StrPtr(String 2),ByVal StrPtr(String 1),LenB(String 1)Debug.Print String 2&"*"End Sub"
推奨手法には,ターゲットアドレスとソースアドレスの対称性という共通の特徴が見られる.もしLongが両方ともLongを伝えるならば、もし文字列が両方とも文字列を伝えるならば、このようにしてやっと正しい結果を得ることができます;もし1つのアドレスがLongを伝えるならば、1つのアドレスが文字列を伝えるならば、それは問題が発生して、原因、実はVBのお母さんが1つに対してUA/AC変換をしたためで、もう1つに対してしていないで、互いに番号に合わないで、もっと余分な文を加えて修正します.
また、次の2つの数字を正しく処理することに注意してください.
(1)CopyMemoryの3番目のパラメータbyteLen.ソースアドレスパラメータがUA/AU変換に関与するか否かにより、該当する場合は対応するANSI文字列のバイト数をとり、該当しない場合はそのままLenB(String 1)
(2)String 2の初期文字数(文字数がバイト数ではないことに注意).対象アドレスパラメータがUA/AU変換に関与するか否かにより、該当するANSI文字列のバイト数がbyteLenに等しく、該当しない場合はUnicode文字列のバイト数がbyteLenに等しいことが保証される.
第五節練習:これらの返事は全部読めますか.
(二)、(三)詳しく議論したほか、多くの友达がこの投稿に自分の修正コードを提供しているので、一度練習として本稿の学習成果を固めてみてはいかがでしょうか.以下のように総説する.
8階、正しいです.
これは実際に0階コードの直接修正です.まずString 2の長さを拡張して対応する_tmp 2の長さは十分である.最後にUA変換をしてVBが多くしたAU変換を相殺します.
9階、正しいです.
UA/AU変換なしで文字列バッファを直接コピーします.
12階、正しいです.
UA/AU変換なしで文字列バッファを直接コピーします.
15階(1)、正しいです.
目的とソースを同時にUA/AU変換し、文字列バッファを直接コピーします.
15階(2)、正しいです.
UA/AU変換なしで文字列バッファを直接コピーします.
22階、間違いです.
同じ10階です.248階で説明します.
23階、間違いです.
同じ10階です.248階で説明します.
38階です.正しいです.
文字列パラメータを直接渡すには、正しい結果を得るには、対バイト数を計算することが重要です.悪い神はASCI文字列が占めるバイト数を計算するために関数を書いたので、正しい結果を得ることができます.しかし、このGetStringLength関数は、LenB(StrConv(「ちょっとslow」,vbFromUnicode))という文に完全に簡略化できると思います.
46階、正しいです.
同じ15階の最初の方法です.
50階(1)、正しいです.
同じ8階です.
50階(2)、正しいです.
同じ15階の最初の方法です.(ただし、解釈は完全に正確ではありません:)
57階です.正しいです.
これは実は15階の最初の方法と同じですが、もっと通用します.文字列パラメータを直接渡す場合は、ANSI文字列でバイトを計算します.
58階、完全に正確ではありません.
String 2の初期化長さはLen(String 1)とすればよい.
62階です.正しいです.
ByVal VarPtr(ByVal String 1)を使って、ほほほ、本当に回ります.
129階、間違いです.
文字列バッファポインタをコピーすると、メモリが繰り返し解放されます.134141階の説明を参照してください.
165階、正しいです.同じ9階です.
しかし,LenとLenB関数を用いてコードをより汎用化した.
231階、間違いです.
文字列バッファポインタをコピーすると、メモリとメモリの重複解放が発生します.134141階の説明を参照してください.
237階、間違いです.
文字列バッファポインタをコピーすると、メモリとメモリの重複解放が発生します.134141階の説明を参照してください.
第六節補足質問
6.1メモリの表示方法
実はCopyMemory関数を熟知するには、推測するよりメモリを直接見るほうがいいです.メモリをどう思いますか?ターゲットアドレスのメモリCopyMemoryを配列に入れ、1バイトずつHexすることができます.メモリを分析するには、常にこのようにする必要があります.
また、いくつかの補助デバッグツールも使用できます.たとえば、OllyDbg:RING 3のデバッグツールは、各変数値またはレジスタの値をリアルタイムで参照するために使用できます.たとえば、Idaや氷の刃などの静的逆アセンブリのツールは、高度な言語の実際の実行動作を理解するのに役立ちます.
6.2 VB 6でAPIを呼び出して文字列パラメータを使う時UA/AU変換を避けることができますか
VBはAPIを呼び出して、いつも1つの仲介を通って、msvbvm 60.dllの中のDllFunctionCall、これはUA/AU変換の始業者です.自分で定義したTLBを利用してDllFunctionCallを迂回すると、文字列はUA/AU変換されません.
6.3すべてのAPI関数は文字列パラメータをANSI文字列として処理しますか
答えは?API関数の中には、そうでないものもあります.Unicode文字列を期待するAPI関数(W版APIとなる)については,VB呼び出しで文字列パラメータに渡すと問題が発生する.VBはAPI関数が何を期待しているのか気にしないので、ANSI文字列に頭を回して伝えます.したがって、異なるタイプのAPIについては、このブログを参照してください.
第七節全文の概要
VB 6でCopyMemory関数を使って正しいコピー文字列を使うのはちょっとうるさいです.本文はいくつかの経典コードを分析することを通じて、この中の各方面の知識を紹介した.
(1)VB 6による文字列パラメータの自動UA/AU変換機構
(2)VBにおける文字列について:BSTR構造、StrPtrおよびVtrPtr関数の意味、文字列メモリの初期化、文字列符号化の表示方法、VB 6が文字列変数を解放する方法など.
(3)CopyMemory関数について;その様々な異なる形式のパラメータの意味、上書きをどのように自動的に処理するか、VB 6がCopyMemoryを呼び出した後にString 2の長さをどのように決定するかなど.
(4)その他の内容:大端順、小端順、ANSI符号化メモリ構造、スタック、VBクラッシュに関する処理、メモリの表示方法、TlbでUA/AU変換を避ける方法など.
添付:クラシックコードセグメントインデックス
第1節:詳細図、“表”はand“文字”はVB 6の文字列パラメータに対する自動UA/AU変換機構を示す.
第3節:例1:非対称のパラメータ形式は非対称のUA/AU変換を招き、その後初期化バイト数が足りず結果が短縮される.例2:非対称のパラメータ形式は非対称のUA/AU変換をもたらし、「むくみ」の結果を得た;例3:String 1パスパラメータを直接使用することによる危険な結果.例4、この値がアドレスに渡された後の結果.例5、中国語と英語が混在する文字列はどのようにバイト数を計算するか.例6,危険な置換ポインタ法.
第四節:正しい方法の剖析.
第五節:超多他のコードの簡単な分析.
全文が終わる