C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

簡体字が取り込めません。+α(こっちの方が本題かも)

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■94007 / inTopicNo.1)  簡体字が取り込めません。+α(こっちの方が本題かも)
  
□投稿者/ 山猿 (6回)-(2020/03/02(Mon) 20:04:44)

分類:[VB.NET/VB2005 以降] 

またまた、お世話になります。
前回は、おバカな質問、大変失礼致しました。

今回も、似た様なご質問となることをご容赦下さいませ。

以下の様なコードで、他プロセスのListViweから文字列を取り出そうとしています。
問題点は2点あります。
1.Debugモードでは正常に取り出せるのですが、Releaseモードだと正しく取り出せず文字列にNullが返ります。(DebugとReleaseで動作が異なる問題)
  一部、初期化等を試みましたが、解決には至っておりません。
2.使用している関数(ReadProcessMemory等)の問題だと思うのですが、前回同様、簡体字(Unicode)が文字化けしてしまいます。

適切な対処方法をご存知の方、おりましたら宜しくお願い致します。

【実行部分】

'クリック行の情報取得
Dim cline As Long = Int((y - 33) / 32) + 1
Dim str As String = ""
Dim rtc As Integer = Getlistviewitem(hwnd, cline, str) ←(該当関数。下記参照。hwndは別プロセスのListViewID)
If rtc < 0 Then
Call MsgBox("リストに情報がありません", "確認")
Exit Function
End If
Dim text() As String = Split(str, vbTab)
Logfile(3, "対局室:" & text(0)) ←ログファイル用私設関数
Logfile(3, "タイプ:" & text(1))
Logfile(3, "白  :" & text(3))
Logfile(3, "黒  :" & text(4))
Logfile(3, "状態 :" & text(5))
If text(5) <> "終了" Then
Call MsgBox("対局が終了していません", "確認")
Exit Function
End If


尚、肝心のGetlistviewitem関数に付きましては、容量が大きくて記事に添付できませんでしたが、無いと質問になりませんので、イレギュラーかもしれませんが、以下のデータファイル転送サービスを利用させて頂きました。期間は、本日(3月2日)から一週間(3月9日20:00)です。延長が必要な場合は、対応致します。
ダウンロードURL:https://okurin.bitpark.co.jp/download.php?unb=ec2bd&sid=oJhFf&uid=NyCqK&t=1583146910

以上、宜しくお願い致します。

引用返信 編集キー/
■94008 / inTopicNo.2)  Re[1]: 簡体字が取り込めません。+α(こっちの方が本題かも)
□投稿者/ 魔界の仮面弁士 (2578回)-(2020/03/02(Mon) 20:59:43)
No94007 (山猿 さん) に返信
> 以下のデータファイル転送サービスを利用させて頂きました。
OneDrive の公開フォルダーを使えば、期間制限しなくて済みそう。



> 前回同様、簡体字(Unicode)が文字化けしてしまいます。
前回と言うのは、 No93935 のスレッドですね。
http://bbs.wankuma.com/index.cgi?mode=al2&namber=93935


アップロード頂いたソースをざっと見ただけで、実行はしていないのですが、
問題点が結構ありますね。もしかして、VB5 あたりから移植してたりしますか?


まず、データ型があちこち間違っています。
『Option Strict On』を指定して、その状態でコンパイルが通るようにしておいてください。


次に、これは前回と同じですが、ANSI / Unicode を明確にするようにしてください。
API 宣言もそうですし、構造体宣言もそうです。

たとえば StructLayout 属性には、CharSet フィールドがありますし、
LV_ITEM 構造体にも、ANSI バージョンと Unicode バージョンがあります。

https://docs.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-lvitemw
https://docs.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-lvitema



> Dim rtc As Integer = Getlistviewitem(hwnd, cline, str) ←(該当関数。下記参照。hwndは別プロセスのListViewID)

Getlistviewitem を Public にするのは分かりますが、
Decalre まで Public にする必要は無いのでは…?
間違いというわけでは無いですが、できるだけカプセル化した方が良いですよ。

それと、hwnd 引数を ByRef にしているようですが、これは出力引数では無いので、
ByVal として宣言されるべきです。



そして最初の OpenProcess API ですが、SDK 上の定義が
 HANDLE OpenProcess(
   DWORD dwDesiredAccess,
   BOOL  bInheritHandle,
   DWORD dwProcessId
 );
なのですから、それを
   Public Declare Function OpenProcess Lib "kernel32" (
       ByVal dwDesiredAccess As Integer,
       ByVal bInheritHandle As Integer,
       ByVal dwProcessId As Integer) As Integer
とするのは正しくありません。

引数については、一応許容範囲。
DWORD は「32bit 符号なし整数型」なので、Integer という「32bit 符号付整数型」に翻訳するのは許容範囲。(As UInteger でも良い)
BOOL は「4 バイトの Boolean 値 (true != 0、false = 0)」なので、これも Integer にできます。(As Boolean でも良い)


問題は戻り値。
SDK 上の定義は HANDLE 型ですが、これは Integer ではなく、As IntPtr として宣言されるべきです。
(丁寧に書く場合は、SafeHandle や SafeHandleZeroOrMinusOneIsInvalid を使うこともあります)

今回は "Any CPU 32-bit preferred" なビルドなので、As Integer でも一応通るのですが、
Integer に翻訳するのは、あまり良いコードとは言えません。


VirtualAllocEx / VirtualFreeEx / CloseHandle においても、IntPtr 指定とすべきところが
間違っているようですので、SDK を見ながら、正しい記述に直しておいてください。


それと、SendMessage API の宣言がありませんでした。こちらの提示もお願いします。
これも ANSI 版と Unicode 版が存在する関数です。( No93938 で幾つか例示しましたよね)


で、ANSI / Unicode 以外で間違っているのが、引数の指定。
> nrow = SendMessage(hWnd, LVM_GETTITEMCOUNT, IntPtr.Zero, CLng(0))
となっていますが、これも明確に間違いです。

WPARAM 型は、Win64 では 64bit/Win32 では 32bit/Win16 では 16bit
LPARAM 型は、Win64 では 64bit/Win32 では 32bit/Win16 では 32bit

64bit ビルドの時は CLng(0) を渡せますが、そうすると OpenProcess や VirtualAllocEx 等の宣言が合わなくなります。

32bit ビルドだとしたら、CLng(0) を渡すのは NG です。SendMessage の宣言内容によっては、暗黙の型変換によって
32bit 値に縮小されて渡されるかもしれませんが、そうだとしたら CLng するのは無意味ですし、
そもそも「Option Strict On」の時にコンパイルエラーとして検出されることになるでしょう。


> Dim cline As Long = Int((y - 33) / 32) + 1

y の型が分からないですが、これも不自然なコードです。
代入式の左辺は Long 型ですが、右辺はそうではないからです。(おそらく Double のはず)

API を使うのであれば、「Option Strict On」であっても
正しくコンパイルできるようなコードを記述することを強くおすすめします。


> SendMessageW(hWnd, LVM_GETITEMW, IntPtr.Zero, sm1) '取得依頼

API 宣言が省略されているので確証は持てませんが、上記自体は正しい呼び出しに見えます。

ただ、A 系と W 系を混在させたコードになるのは望ましくないので、
今回のケースでは、W 系に統一させたコードに置き換えましょう。

引用返信 編集キー/
■94009 / inTopicNo.3)  Re[1]: 簡体字が取り込めません。+α(こっちの方が本題かも)
□投稿者/ 魔界の仮面弁士 (2579回)-(2020/03/02(Mon) 21:45:59)
No94007 (山猿 さん) に返信
> 前回同様、簡体字(Unicode)が文字化けしてしまいます。

もう一つ、ここもおかしいですね。

Dim tmp As String = System.Text.Encoding.Default.GetString(str)


System.Text.Encoding.Default は ANSI でのデコードを意味します。

簡体字版の Windows 環境においては
System.Text.Encoding.GetEncoding(936) あるいは
System.Text.Encoding.GetEncoding("gb2312") 相当。

日本語版の Windows 環境においては
System.Text.Encoding.GetEncoding(932) あるいは
System.Text.Encoding.GetEncoding("Shift_JIS") 相当。



簡体字版 Windows で ANSI 版 API を使っているのなら、Dim str() As Byte の内容は GB2312 なバイナリであることが期待されます。
日本語版 Windows で ANSI 版 API を使っているのなら、Dim str() As Byte の内容はシフト JIS バイナリであることが期待されます。

日本語版 Windows で ANSI 版 API を使っている場合は、どうやっても 簡体字 のテキストは得られません。

一方、Unicode 版 API を使っている場合は、Windows が簡体字であれ日本語であれ
Dim str() As Byte の内容は、常に UTF-16 相当のバイナリであることが期待されます。
この場合、System.Text.Encoding.Unicode で変換できるでしょう。

ただ、そもそも今回のケースで Byte 配列を使う必要は無いように思えます。

ReadProcessMemory には IntPtr のまま渡すようにして、文字列として読み取るために
Marshal.PtrToString 何某を利用してみては如何でしょう。
引用返信 編集キー/
■94010 / inTopicNo.4)  Re[2]: 簡体字が取り込めません。+α(こっちの方が本題かも)
□投稿者/ 山猿 (7回)-(2020/03/03(Tue) 08:23:44)
魔界の仮面弁士さま
ご指導ご指摘、多謝歓喜でございます。
久し振りのVB、「あ、こんなんでも動くんだ」とばかりに、仰る通り、思い出し思い出し方々から部品を&#25620;き集めて、細かな気配りなどそっちのけで組み上げた作品となっておりました。
最近、ひょんな事から.NET Nativeを目にし、久々に心が踊っている還暦超えの“猿爺”でございます。
Option Strict Onにしたら、何と全体でエラーが200越え。Releaseモードで動かないのは当たり前?逆に、debugモードで動いていたのが、奇跡的だったとしか思えません。「下手にいじって動かなくなるのも困るし」との意識も働いちゃいました。200ちょいで収まったのも奇跡かも。
個人用途の所為もあってか、職人的意識が、多少(多々?)欠落していたかもしれません。欠落と言うか健忘と言うか、面目無い。
一応、SendMessageは、以下の様に定義しておりました。
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
直には関係ないと思いましたが、やはり、全体的にANSIでなく、Unicodeを意識しての改修(他も含め)が必須と痛感致しました。
再度全体を見直し、後日改めてご報告させて頂きたいと思います。
碁好き還暦じじいを見捨てずに、懇切丁寧にご指導ご対応頂き、まことにありがとうございます。

引用返信 編集キー/
■94011 / inTopicNo.5)  Re[3]: 簡体字が取り込めません。+α(こっちの方が本題かも)
□投稿者/ KOZ (88回)-(2020/03/03(Tue) 21:12:56)
2020/03/03(Tue) 21:13:14 編集(投稿者)
LV_ITEM 構造体なのですが

普通に書くと

<StructLayout(LayoutKind.Sequential)>
Public Structure LV_ITEM
    Public mask As Integer
    Public iItem As Integer
    Public iSubItem As Integer
    Public state As Integer
    Public stateMask As Integer
    Public pszText As IntPtr
    Public cchTextMax As Integer
    Public iImage As Integer
    Public lParam As IntPtr
    Public iIndent As Integer
    Public iGroupId As Integer
    Public cColumns As Integer
    Public puColumns As Integer
    Public piColFmt As IntPtr
    Public iGroup As Integer
End Structure

こうなります。

64bit だと 88バイト、32bit だと 60バイトになりますので、
読み取るプロセスがどちらで動いているかによって変更する必要があります。

' 64ビット用
<StructLayout(LayoutKind.Sequential, Pack:=8)>
Public Structure LVITEM64
    Public mask As Integer
    Public iItem As Integer
    Public iSubItem As Integer
    Public state As Integer
    Public stateMask As Integer
    Public pszText As Long
    Public cchTextMax As Integer
    Public iImage As Integer
    Public lParam As Long
    Public iIndent As Integer
    Public iGroupId As Integer
    Public cColumns As Integer
    Public puColumns As Integer
    Public piColFmt As Long
    Public iGroup As Integer
End Structure

' 32ビット用
<StructLayout(LayoutKind.Sequential, Pack:=4)>
Public Structure LVITEM32
    Public mask As Integer
    Public iItem As Integer
    Public iSubItem As Integer
    Public state As Integer
    Public stateMask As Integer
    Public pszText As Integer
    Public cchTextMax As Integer
    Public iImage As Integer
    Public lParam As Integer
    Public iIndent As Integer
    Public iGroupId As Integer
    Public cColumns As Integer
    Public puColumns As Integer
    Public piColFmt As Integer
    Public iGroup As Integer
End Structure

引用返信 編集キー/
■94012 / inTopicNo.6)  Re[4]: 簡体字が取り込めません。+α(こっちの方が本題かも)
□投稿者/ 山猿 (8回)-(2020/03/04(Wed) 00:00:00)
KOZさま
ご指摘ありがとうございます。
仰られている点を確認しましたところ、x64にてコンパイルしておりましたので、試しにx86に変更しましたところ、Releaseモードでの動作確認が取れました。もちろんAnyCPUでも同様の結果を得ることが出来ました。
ありがとうございます。
魔界の仮面弁士さまのご指摘通り、Option Strict Onによるエラーを、一先ず取り除き、SendMessageをSendMessageWに変更したり、他にも幾つか変更を加えている最中のものでしたが、現時点での改修状況下では、x64のままですと、1.文字列が取り込めない。2.簡体字が文字化けする。の何れも想定した結果を得られなかったものの、x86(AnyCPU共)にしますと、(見た目は)想定値が返って来る様になりました。
(プロジェクトそのものが、流用だったので、x64のままだったみたいです。嗚呼、何と無神経なこと)
然し、魔界の仮面弁士さまのご指摘もご尤もでありますので、今後(とは言っても、じじいの生い先は知れていますが)の為にも、引き続きコードの補修、改修を続けようと思っております。
一先ず、本件、これにて解決とさせて頂きます。
魔界の仮面弁士さま、KOZさま、まことにありがとうございました。

解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ