[リストへもどる]   [VBレスキュー(花ちゃん)]
一括表示

投稿時間:2005/01/27(Thu) 09:49
投稿者名:DODOON
URL :
タイトル:
RtlMoveMemoryの振る舞い
すいませんDODOONと申します。
プログラム4年目です。
VB6をservice Pack5で使用しています。

質問はRtlMoveMemoryの振る舞いについてです。
いま、VCで共有メモリを作成して、そこにVBから書き込むプログラムを作成しています。
VC上でcharの4バイトの領域をCreateFileしました。
そこをVBからOpenFileMappingをして、MapViewOfFileを行います。

Ptr = MapViewOfFile(hMFd, FILE_MAP_ALL_ACCESS, 0, 0, 0)

そのポインタの場所にstring型のstrStrを書き込もうとしました。
dim strStr as string
strStr = "C1  "
Call RtlMoveMemory(ByVal Ptr , ByVal StrPtr(strStr), 4)
上記のように書き込むとcharの4バイトのところに
char[0] = 'C' char[1] = 0x00 char[2] = '1' char[3] = 0x00
とユニコードの形で書き込まれます。
また
Call RtlMoveMemory(ByVal Ptr , ByVal strStr, 4)
上記のように文字列ポインタの関数を使わないと
char[0] = 'C' char[1] = '1' char[2] = 0x20' char[3] = 0x20
と書き込まれます。
基本的にVBのString型はユニコードだと思ってますが、
よくシーケンシャルファイルに書き込んだら、普通にアスキーコードに変換されてたり
します。
このあたりは、皆さんはVBまかせにしているのでしょうか?
私としてはAPIでString型を使う時はユニコードとして振舞ってもらうほうが
ありがたいのですが、日本語文字の2バイトも含めて。
このあたりの振る舞いについて、教えていただけますでしょうか?
よろしくお願いします

投稿時間:2005/01/27(Thu) 11:59
投稿者名:魔界の仮面弁士
Eメール:
URL :
タイトル:
Re: RtlMoveMemoryの振る舞い
> 基本的にVBのString型はユニコードだと思ってますが、
VB6のUnicodeは、UCS-2/UTF-16 で表現されていますね。
(ちなみに VB.NET では、UTF-8 がベースになっているようです)

> このあたりは、皆さんはVBまかせにしているのでしょうか?
私は、ほとんどをVBに任せています。

APIでUnicodeを扱いたいなら、「String」ではなく、「Byte配列」を使って、
  Declare Sub UnicodeProc Lib "dllname" (ByRef X As Byte)
  Dim B() As Byte
  B = "あいうえお"
  Call UnicodeProc(B(0))
のようにすれば、そのまま渡せますしね。

> 私としてはAPIでString型を使う時はユニコードとして振舞ってもらうほうが
> ありがたいのですが、日本語文字の2バイトも含めて。
Unicodeで渡されないのは、ある程度の理由があります。

今では、殆どのOSが NTベースのもの(NT4, 2000, XP, 2003, ……)に
なっていますが、以前は、いわゆる9x系のOS(95, 98, Me)が非常に
多く使われていました。

そして9x系では、Unicode対応のAPIは僅かしかありません。
ほとんどのAPIがANSI版のみです。(SendMessageAとか)

一方のNT系では、UnicodeエントリとANSIエントリの両方を持っていますので、
API操作に関しては、ANSI版にあわせた設計の方が都合が良かったそうです。

# なお、VB.NET では、"Auto"キーワードによって、Unicode版/ANSI版の
# いずれを使うべきか、自動判定する機構が設けられています。

投稿時間:2005/01/27(Thu) 13:37
投稿者名:DODOON
URL :
タイトル:
Re^2: RtlMoveMemoryの振る舞い
返事ありがとうございます。
魔界の仮面弁士さん。いつもgoogleで検索すると
お名前がでて、参考にさせていただいています。
じかに、返答いただけて、うれしいです。

> (ちなみに VB.NET では、UTF-8 がベースになっているようです)
知りませんでした。

> 私は、ほとんどをVBに任せています。
やはり、それが正しいですよね。シーケンシャルファイルの時は
何も考えてなかったのですが、このような使い方をすると
きになってしまいました。
>
> APIでUnicodeを扱いたいなら、「String」ではなく、「Byte配列」を使って、
>   Declare Sub UnicodeProc Lib "dllname" (ByRef X As Byte)
>   Dim B() As Byte
>   B = "あいうえお"
>   Call UnicodeProc(B(0))
> のようにすれば、そのまま渡せますしね。
>
そのように、するのが一番確実ですね。
byvalでstring型で渡すのは何か気持ち悪いのです。

> 今では、殆どのOSが NTベースのもの(NT4, 2000, XP, 2003, ……)に
> なっていますが、以前は、いわゆる9x系のOS(95, 98, Me)が非常に
> 多く使われていました。
>
> そして9x系では、Unicode対応のAPIは僅かしかありません。
> ほとんどのAPIがANSI版のみです。(SendMessageAとか)
>
> 一方のNT系では、UnicodeエントリとANSIエントリの両方を持っていますので、
> API操作に関しては、ANSI版にあわせた設計の方が都合が良かったそうです。
>
勉強になります。

> # なお、VB.NET では、"Auto"キーワードによって、Unicode版/ANSI版の
> # いずれを使うべきか、自動判定する機構が設けられています。
.NETはまだ、使ったことないので、記憶に入れときます。

ありがとうございました。

投稿時間:2005/01/27(Thu) 17:11
投稿者名:魔界の仮面弁士
Eメール:
URL :
タイトル:
Re^3: RtlMoveMemoryの振る舞い
> byvalでstring型で渡すのは何か気持ち悪いのです。

「相手が LPSTR の場合に、ByVal で渡す仕様である」という点に関しては、
VB6のヘルプにも書かれていますね。
hhttp://www.microsoft.com/japan/developer/library/VBCon98/vbconpassingstringstodllprocedure.htm


ちなみに、(S≠vbNullStringの場合)、
 CopyMemory P, ByVal VarPtr(S), 4
は、Long値 P は、StrPtr(S) と同じ値になります。

ついでに、
 CopyMemory P, ByVal StrPtr(S) - 4, 4
では、P に LenB(S) と同じ値が返されます。蛇足までに。

投稿時間:2005/01/27(Thu) 17:50
投稿者名:魔界の仮面弁士
Eメール:
URL :
タイトル:
Re^4: RtlMoveMemoryの振る舞い
一箇所補足。

> > byvalでstring型で渡すのは何か気持ち悪いのです。
> 「相手が LPSTR の場合に、ByVal で渡す仕様である」という点に関しては、
> VB6のヘルプにも書かれていますね。

「ByVal S As String」で渡す必要があるのは、相手が LPSTR で
ある時だけだという事に注意してください。
それ以外の文字列型では、別の手順が必要になる可能性があります。


たとえば下記では、 LPOLESTR 形式の文字列を操作する API (CLSIDFromString) を
利用していますが、この場合、宣言側の引数を ByVal lpszCLSID As String や
ByRef lpszCLSID As String にしてしまうと、正しく処理できなくなってしまいます。

========================
Private Type UUID
    Data1    As Long    'unsigned long  Data1
    Data2    As Integer 'unsigned short Data2
    Data3    As Integer 'unsigned short Data3
    Data4(7) As Byte    'unsigned char  Data4[8]
End Type

'第1引数は、Long型の値渡しになっている点に注意
Private Declare Function CLSIDFromString Lib "ole32" _
   (ByVal lpszCLSID As Long, ByRef pclsid As UUID) As Long

Private Function ToCLSID(ByVal S As String) As UUID
    'ByVal As Long に対して、StrPtr()を渡しています。
    CLSIDFromString StrPtr(S), ToCLSID
End Function

Private Sub Form_Load()
    Dim X As UUID
    X = ToCLSID("{00000514-0000-0010-8000-00AA006D2EA4}")
    'X にデータが格納される。
End Sub
========================

このタイプの関数に文字列を渡す(あるいは受け取る)場合の手順は、
下記を参照してみてください。
hhttp://support.microsoft.com/kb/183544/