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

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

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

Re[3]: 64bitOSでのWinAPI参照


(過去ログ 141 を表示中)

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

■82603 / inTopicNo.1)  64bitOSでのWinAPI参照
  
□投稿者/ 大谷刑部 (4回)-(2017/01/20(Fri) 12:49:32)

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

非常に漠然とした質問ですが、

kernel32などのDLLをDeclare Function宣言で参照しているVB.netのアプリで、
現状は32bitOSで稼動しているものを64bitOSに移行した場合、
要改修となるとなるのはどのようなケースでしょうか?
(引数の型の変更とかが必要となるレベルで)
引用返信 編集キー/
■82604 / inTopicNo.2)  Re[1]: 64bitOSでのWinAPI参照
□投稿者/ Hongliang (489回)-(2017/01/20(Fri) 13:40:20)
ポインタやハンドルについて、IntPtrで宣言すべきところをIntegerにしていたりすれば修正が必要ですね。
それ以外はもうケースバイケースとしか言い様がないですね…。
引用返信 編集キー/
■82605 / inTopicNo.3)  Re[2]: 64bitOSでのWinAPI参照
□投稿者/ 大谷刑部 (5回)-(2017/01/20(Fri) 14:00:17)
No82604 (Hongliang さん) に返信
> ポインタやハンドルについて、IntPtrで宣言すべきところをIntegerにしていたりすれば修正が必要ですね。

ご回答ありがとうございます。
上記の話は思いっきり該当してます。
VB6から.Netに数年前に変換してますが、
その際の環境がWin7 32bitだったので、64bitOSのことは考慮されてないというのが現実です。

> それ以外はもうケースバイケースとしか言い様がないですね…。

Aliasとか、Stringで宣言されている場合に要対応のケースはあるでしょうか?
引用返信 編集キー/
■82607 / inTopicNo.4)  Re[1]: 64bitOSでのWinAPI参照
□投稿者/ 774RR (471回)-(2017/01/20(Fri) 14:10:54)
オイラの手元で x64 と x86 で明確にソースコードを切り分ける必要があったのは
SetupDiGetDeviceInterfaceDetail に渡す SP_DEVICE_INTERFACE_DETAIL_DATA 構造体

これは可変長配列を含んでいて API 関数を呼ぶとその可変長配列部分に値を返す仕様なんだけど
SetupAPI.h に書かれているソースコードは古い C 規格で通るように固定長配列が使われている。
ユーザーランドつまりオイラたち末端プログラマは C/C++ ソース上 datail.cbSize=sizeof(detail); と書く約束で、
こう書くと C コンパイラ的には可変長配列部分が 1 に見える。
でも実際に使われている Win32 API 関数の実装上の動きはもっと多くのメモリを使うといういやらしい代物だ。
C# 側で使いやすいよう MarshalAttribute を正しく書くと
C ソースの sizeof と C# ソースの Marshal.SizeOf が一致しない、ので特別対処が必要、かつ
x86 と x64 で padding 仕様が違う関係で C# ソースコード側で x86/x64 で切り分ける必要がある、のでした。

Win32 API の使う構造体が、可変長配列を使っていたら x86/x64 で要手直し、な可能性がある。
とりあえず http://www.pinvoke.net サイトの中を IntPtr.Size で検索してみるといい。
IntPtr.Size==4 とかの比較をしている Win32 API を使っていたら詳細を読んでみるのがよさそう。

引用返信 編集キー/
■82609 / inTopicNo.5)  Re[3]: 64bitOSでのWinAPI参照
□投稿者/ 魔界の仮面弁士 (1068回)-(2017/01/20(Fri) 14:45:39)
No82605 (大谷刑部 さん) に返信
> VB6から.Netに数年前に変換してますが、
> その際の環境がWin7 32bitだったので、64bitOSのことは考慮されてないというのが現実です。
ByRef As Integer は大丈夫だと思いますが、
ByVal As Integer は要確認ですね。
あとは、IntPtr.ToInt32() とか。
SendMessage の WPARAM / LPRAM あたりが嵌りどころ。


>>それ以外はもうケースバイケースとしか言い様がないですね…。
> Aliasとか、Stringで宣言されている場合に要対応のケースはあるでしょうか?

有名どころでは GetWindowLongPtr & SetWindowLongPtr API に対する Alias ですね。
 https://msdn.microsoft.com/ja-jp/library/cc411204.aspx
 64bit 環境では、SetWindowLongPtrA / SetWindowLongPtrW 関数
 32bit 環境では、SetWindowLongA / SetWindowLongW 関数


あとは Declare(DllImport) とはちょっと異なりますけど、現在使用している
依存コンポーネントが、すべて x64 対応に移行できるのかも要確認です。

たとえば Microsoft.JET.OLEDB.4.0 は 32bit 版しかありませんので、
ODBC ドライバー、OLE DB Provider、帳票ツール等々を使っている場合は、
代替機能を用意できるか確認しておく必要があるかもしれません。
Microsoft 以外のものだと、UnZip32.dll あたりも影響を受けるでしょう。


あとはごく稀なケースとして、16bit アプリとの連携があったら NG だとか、
Office の 32bit/64bit 版との違いを吸収せねばならないパターンとか。
この辺になると、通常は気にしなくてもよいレベルだと思います。
引用返信 編集キー/
■82611 / inTopicNo.6)  Re[1]: 64bitOSでのWinAPI参照
□投稿者/ PANG2 (155回)-(2017/01/20(Fri) 15:02:16)
2017/01/20(Fri) 15:03:04 編集(投稿者)

No82603 (大谷刑部 さん) に返信
> kernel32などのDLLをDeclare Function宣言で参照しているVB.netのアプリで、
> 現状は32bitOSで稼動しているものを64bitOSに移行した場合、
> 要改修となるとなるのはどのようなケースでしょうか?

ターゲットCPUをAnyCPUではなく、x86でビルドする手も。

http://bbs.wankuma.com/index.cgi?mode=al2&namber=49882&KLOG=84
引用返信 編集キー/
■82612 / inTopicNo.7)  Re[3]: 64bitOSでのWinAPI参照
□投稿者/ 大谷刑部 (6回)-(2017/01/20(Fri) 15:06:19)
極め付けは、VB6でOLEコンテナを使っていたものを
OLEコンテナが無くなったため、
OLEコンテナに似せたクラスをOLE32.dllを参照して無理やり作ったクラスなども存在します。
具体的にはWordのバイナリをはめ込んで使うイメージです。

これはどちらかというと.Netの標準コントロール(リッチテキストボックスあたり?)でつくり替えたいですが、
そもそもOLE32.dllは64bitOSに対応してますか?

引用返信 編集キー/
■82613 / inTopicNo.8)  Re[4]: 64bitOSでのWinAPI参照
□投稿者/ 大谷刑部 (7回)-(2017/01/20(Fri) 15:22:50)
No82609 (魔界の仮面弁士 さん) に返信
> >>それ以外はもうケースバイケースとしか言い様がないですね…。
>>Aliasとか、Stringで宣言されている場合に要対応のケースはあるでしょうか?
>
> 有名どころでは GetWindowLongPtr & SetWindowLongPtr API に対する Alias ですね。
>  https://msdn.microsoft.com/ja-jp/library/cc411204.aspx
>  64bit 環境では、SetWindowLongPtrA / SetWindowLongPtrW 関数
>  32bit 環境では、SetWindowLongA / SetWindowLongW 関数

ありがとうございます。
メッセージボックスとプログレスバーで思いっきり使ってました。
メッセージボックスの方はなんかVB標準のものに変えてしまいたいですね。
個人的な希望としては。


引用返信 編集キー/
■82615 / inTopicNo.9)  Re[4]: 64bitOSでのWinAPI参照
□投稿者/ 大谷刑部 (8回)-(2017/01/20(Fri) 15:58:52)
No82609 (魔界の仮面弁士 さん) に返信
> ■No82605 (大谷刑部 さん) に返信
> SendMessage の WPARAM / LPRAM あたりが嵌りどころ。

WPARAM はinteger、LPRAM はobjectで宣言されてました。
objectってことは、VB6時代にVariantで宣言されてたと思います。

多分、アウトですよね?

引用返信 編集キー/
■82623 / inTopicNo.10)  Re[5]: 64bitOSでのWinAPI参照
□投稿者/ 魔界の仮面弁士 (1069回)-(2017/01/20(Fri) 18:35:02)
No82615 (大谷刑部 さん) に返信
> objectってことは、VB6時代にVariantで宣言されてたと思います。
多分、As Any だったのだと思いますよ。
VB.NET の場合は、オーバーロードで解決した方が良いでしょう。


> WPARAM はinteger、LPRAM はobjectで宣言されてました。

元々は名前の通り
 WPARAM は WORD 型のパラメーター
 LPARAM は LONG 型のパラメーター
を意味していたのですが、歴史的な経緯から、現在はいずれも
IntPtr あるいは UIntPtr 相当のサイズになっています。

Win16 WPARAM => 16bit長
Win32 WPARAM => 32bit長
Win64 WPARAM => 64bit長

Win16 LPARAM => 32bit長
Win32 LPARAM => 32bit長
Win64 LPARAM => 64bit長


データサイズさえ間違っていなければ何型を使っても構いませんが、
WPARAM / LPARAM をどのように解釈するかは、メッセージによって
異なりますのでご注意下さい。


たとえば WM_COMMAND などは、Win32/Win64 共に
WPARAM を 16bit×2 の 32bit 幅分しか利用していません。

 WPARAM(HIGH) → 通知コード
 WPARAM(LOW) → コントロール/メニューID

こういう場合、32bit長/64bit長の構造体を用意して使い分けてもよいですし、
あるいは WPARAM を IntPtr で受けてから、ToUInt64 して値をビット演算で
分解してもよいと思います。(32bit 幅ですが ToInt32 は使いません)


なお、IntPtr の中身が 80000000〜FFFFFFFF の範囲だった場合、
「IntPtr.ToInt32」を使えるとは限りません。
x86 ビルドの場合は、負数が返されるだけなのですが、
x64 ビルドの場合は、OverflowException を返す可能性があります。
(しかも何故か、VB と C# で動作が異なるようで…)
引用返信 編集キー/
■82636 / inTopicNo.11)  Re[6]: 64bitOSでのWinAPI参照
□投稿者/ 大谷刑部 (9回)-(2017/01/23(Mon) 10:10:31)
No82623 (魔界の仮面弁士 さん) に返信
> ■No82615 (大谷刑部 さん) に返信
>>objectってことは、VB6時代にVariantで宣言されてたと思います。
> 多分、As Any だったのだと思いますよ。
> VB.NET の場合は、オーバーロードで解決した方が良いでしょう。

VB6時代のソースが全部あるわけではないようなので、同じ個所かわかりませんが、
「As Any」を使った箇所はありました。
「As Any」はアップグレード ウィザードでも変換されない箇所のようなので、
手でobjectに変えたか、関連会社のツールの仕様がそうだったと推測されます。
いずれにしても、objectのままにしたのが?ですが。
汎用objectは遅延バインディングなど何かと評判の悪い型ですから。

>>WPARAM はinteger、LPRAM はobjectで宣言されてました。
>
> 元々は名前の通り
>  WPARAM は WORD 型のパラメーター
>  LPARAM は LONG 型のパラメーター
> を意味していたのですが、歴史的な経緯から、現在はいずれも
> IntPtr あるいは UIntPtr 相当のサイズになっています。
>
> Win16 WPARAM => 16bit長
> Win32 WPARAM => 32bit長
> Win64 WPARAM => 64bit長
>
> Win16 LPARAM => 32bit長
> Win32 LPARAM => 32bit長
> Win64 LPARAM => 64bit長
>
>
> データサイズさえ間違っていなければ何型を使っても構いませんが、
> WPARAM / LPARAM をどのように解釈するかは、メッセージによって
> 異なりますのでご注意下さい。
>
>
> たとえば WM_COMMAND などは、Win32/Win64 共に
> WPARAM を 16bit×2 の 32bit 幅分しか利用していません。
>
>  WPARAM(HIGH) → 通知コード
>  WPARAM(LOW) → コントロール/メニューID
>
> こういう場合、32bit長/64bit長の構造体を用意して使い分けてもよいですし、
> あるいは WPARAM を IntPtr で受けてから、ToUInt64 して値をビット演算で
> 分解してもよいと思います。(32bit 幅ですが ToInt32 は使いません)
>
>
> なお、IntPtr の中身が 80000000〜FFFFFFFF の範囲だった場合、
> 「IntPtr.ToInt32」を使えるとは限りません。
> x86 ビルドの場合は、負数が返されるだけなのですが、
> x64 ビルドの場合は、OverflowException を返す可能性があります。
> (しかも何故か、VB と C# で動作が異なるようで…)

汎用object型がだめといいつつ、一方で、
VB側のロジックを複雑にしたくない、汎用的にしたいというのもあるのですが、
Declare Function宣言の引数としては、IntPtrとして受けておいて、
VB側のロジックとしてはTryParseとかで判定しておいて、オーバーフロー回避とかですかね?


引用返信 編集キー/
■82639 / inTopicNo.12)  Re[2]: 64bitOSでのWinAPI参照
□投稿者/ 魔界の仮面弁士 (1074回)-(2017/01/23(Mon) 11:36:11)
■82636 / inTopicNo.11)  Re[6]: 64bitOSでのWinAPI参照
> いずれにしても、objectのままにしたのが?ですが。

個別に見てみないと何とも言えないところではありますね。
VB6 当時でも As Object で呼び出すことはありましたし。

' for VB6
Private Declare Function OleDraw Lib "ole32" _
( ByVal pUnk As Object, ByVal dwAspect As DVASPECT, _
ByVal hDCDraw As OLE_HANDLE, lprcBounds As RECT ) As Long


> 汎用objectは遅延バインディングなど何かと評判の悪い型ですから。

VB6 の Variant よりはマシかも。


> VB側のロジックを複雑にしたくない、汎用的にしたいというのもあるのですが、

汎用的に利用できるようなクラスを作成するためには、
カプセル化した処理(クラス等)の実装は、
それなりに凝った設計にする必要があると思います。

そうすれば、クラスの利用者(他の開発者)が、
複雑なロジックの利用(IntPtrを直接扱うなど)を回避できるでしょう。


> Declare Function宣言の引数としては、IntPtrとして受けておいて、
ポインタ作業が多いなら、いっそ C# で unsafe コードな DLL を用意するとか。


> VB側のロジックとしてはTryParseとかで判定しておいて、オーバーフロー回避とかですかね?
どういう意味でしょうか? TryParse の実装は基本的に、
 Function TryParse(ByVal s As String, <[Out]> ByRef result As 変換結果) As Boolean
だと思うのですが、IntPtr やオーバーフローとどういう繋がりがあるのか読み取れませんでした。

引用返信 編集キー/
■82647 / inTopicNo.13)  Re[3]: 64bitOSでのWinAPI参照
□投稿者/ 大谷刑部 (10回)-(2017/01/23(Mon) 14:58:45)
No82639 (魔界の仮面弁士 さん) に返信
> ■82636 / inTopicNo.11)  Re[6]: 64bitOSでのWinAPI参照
>>いずれにしても、objectのままにしたのが?ですが。
>
> 個別に見てみないと何とも言えないところではありますね。
> VB6 当時でも As Object で呼び出すことはありましたし。
>
> ' for VB6
> Private Declare Function OleDraw Lib "ole32" _
> ( ByVal pUnk As Object, ByVal dwAspect As DVASPECT, _
> ByVal hDCDraw As OLE_HANDLE, lprcBounds As RECT ) As Long

OleDrawはOLEコンテナ代わりのクラスで定義はされているが、
幸い使用してません。

ole32がらみでの64bitの懸念点としては、
他と変わりなく、引数等の型の問題が中心でしょうか?
あるオブジェクトがそもそも使えないとかはありますか?


引用返信 編集キー/


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

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -