hDCに関するエラーを治すには?


真琴  2004-11-02 13:28:27  No: 86411

最近VB6から.NETに移行した.NET初心者です。

以前のVB6の環境では、モジュール内に

Public Declare Sub Drawing Lib "dynamic.dll" (ByVal hDC&, ByVal settingData!) 


Public Sub Display()
  Call Drawing(Form1.picBox.hDC, settingData(0))
End Sub

と記述して、settingData配列をdynamic.dll(描画ライブラリ)に渡して
Form1からDisplay()を呼び出してピクチャボックス(picBox)に描画していました。

しかし、.NETでこれをしようとすると、
'hDC'は'System.Windows.Forms.PictureBox'のメンバではありません。
というエラーが出てしまいます。

どうすれば解決できるのか途方に暮れています。

どなたか、解決方法をお教え願えないでしょうか?


真琴  2004-11-02 13:43:04  No: 86412

今、デバイスコンテキストについて調べていたのですが、http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cpguide/html/_gdiplus_changes_in_the_programming_model_about.asp
にあるように、デバイスコンテキストの代わりに、
Graphics オブジェクトを作成して呼び出す方法というのがあるのですが、
もしかしてこれが原因?なのでしょうか??

混乱してきました〜(^^;)


魔界の仮面弁士  2004-11-02 18:34:10  No: 86413

VB6でいう、hDCプロパティ(Long型/OLE_HANDLE型)に相当する物はありません。
http://www.microsoft.com/japan/msdn/library/ja/Vbcon/html/vxconchangestopictureboxcontrolinvisualbasicnet.asp

GDI+ を利用するならば、Graphics クラスを使う事になります。
GDI  を利用するならば、hWnd に相当する Handleプロパティ(IntPtr型) から、
     GetDC APIを使って GDI のための hDC を取得する事になります。
DirectDraw を利用するならば、Microsoft.DirectX.DirectDraw 名前空間です。

# 作成したGraphicsクラスやデバイスコンテキストハンドルは、最後に
# 解放処理(DisposeメソッドやReleaseDC APIなど)を行ってください。


真琴  2004-11-04 06:30:49  No: 86414

>魔界の仮面弁士さん
ご回答、ありがとうございます。

>GDI+ を利用するならば、Graphics クラスを使う事になります。
>GDI  を利用するならば、hWnd に相当する Handleプロパティ(IntPtr型) から、
>GetDC APIを使って GDI のための hDC を取得する事になります。

Visual Studio6の時はC++側では、
_declspec(dllexport) void _stdcall Drawing(HDC hDC,float* setData)
{・・・}
VB側では上記のように情報をやり取りしていたのですが、
具体的に、GDI+のGraphics クラスを使いたい場合は、
VC、VBにどのような記述が必要になるのでしょうか?
また、蛇足のような質問かもしれませんが、GDI+のGraphics Classと
GDIのhDCには速度の差なんていうものはあるのでしょうか?


真琴  2004-11-04 07:56:46  No: 86415

連続投稿ですが…。

>GDI  を利用するならば、hWnd に相当する Handleプロパティ(IntPtr型) から、
>GetDC APIを使って GDI のための hDC を取得する事になります。

というのをやってみようと思い、以下のようにしてみました。

'標準モジュール内

Public Declare Sub Drawing Lib "dynamic.dll" (ByVal hDC&, ByVal settingData!) 
Private Declare Function GetDC Lib "user32" Alias "GetDC" (ByVal hWnd As Integer) As Integer


Public Sub Display()
        Dim pic_hDC As Integer
        pic_hDC = GetDC(frmspace.picSpace.Handle.ToInt32)
        Call Drawing(pic_hDC, setData(0))
End Sub

としてみたのですが、

'System.DllNotFoundException' のハンドルされていない例外が dynamic.exe で発生しました。
追加情報 : DLL (dynamic.dll) を読み込めません。

というエラーが…。
データと同じ場所にdynamic.dllを置いているのですが、
なぜ読み込めないのでしょうか?


魔界の仮面弁士  2004-11-04 09:53:33  No: 86416

GDI+ は、GDI を機能強化して、グラフィカルイメージをオブジェクトとして扱えるように
設計された物であり、コーディングが全く異なります。そのため、単純な置き換えはできません。

> 具体的に、GDI+のGraphics クラスを使いたい場合は、

VC++.NET(Managed C++) と VB.NET の組み合わせにすれば、
Graphicsクラスをそのまま扱えますよ。

もし、C++側が GDI の hDC を取り扱うようになっているのであれば、
Graphics.FromHdc メソッドを使って、hDC から Graphics オブジェクトを生成したり、
Graphics.GetHdc/ReleaseHdc メソッドにて、逆に hDC を取り出す事もできます。

> VC、VBにどのような記述が必要になるのでしょうか?

GDI では、GDI32.DLL や User32.dll が公開する関数群(たとえば、DrawText等)を使いますが、
GDI+では、GDIPlus.dll が公開する関数群(たとえば、GdipDrawString等)を使う事になります。
VB6であろうと、VC++6であろうと、必要になる関数は同じです。

ただ、.NET においては、GDI+ の操作を容易にするために、GDI+ のAPI関数などが
Graphicsクラスとしてカプセル化されているため、より扱いやすくなっています。

たとえば VB.NET から、P/Invoke (API 呼び出し) にて GdipDrawString APIを呼ぶ事も
可能ですが、それは System.Drawing.Graphicsクラスの DrawStringメソッドで代用できるわけです。

> また、蛇足のような質問かもしれませんが、GDI+のGraphics Classと
> GDIのhDCには速度の差なんていうものはあるのでしょうか?
# デバイスコンテキストではなく、デバイスコンテキストハンドルと比べるのですか…?(^_^;)

とりあえず、GDI と GDI+ は、できる事にも差がありますので、単純な比較はできません。
たとえば、GDIではαチャネルを取り扱えませんし。
ただ、ビットマップの単純な転送速度を比べるなら、GDI の方が圧倒的に早いです。
http://lamoo.s53.xrea.com/develop/gdiplus/gdiplus_blt.html

> Public Declare Sub Drawing Lib "dynamic.dll" (ByVal hDC&, ByVal settingData!)
> Private Declare Function GetDC Lib "user32" Alias "GetDC" (ByVal hWnd As Integer) As Integer
宣言が間違っているようです。
hDC や hWnd は、IntPtr型で宣言するのが一般的です。

中には、整数型で宣言する人も居ますが、その場合は Long型(System.Int64)ではなく、
Integer型 (System.Int32)を使う必要があります。(少なくとも、Win32環境においては)

> データと同じ場所にdynamic.dllを置いているのですが、
「データ」とは、具体的には何の事でしょうか。

もしかして、ソースコードと同じフォルダに置いていませんか?

Visual Studio.NETでは、exeはbinフォルダの下に作られますので、
開発環境で dll を利用する場合は、配置位置に注意してください。


真琴  2004-11-04 10:28:01  No: 86417

>魔界の仮面弁士さん
回答ありがとうございます。
魔界の仮面弁士さんの説明にもう脱帽です(^o^)/

>> Public Declare Sub Drawing Lib "dynamic.dll" (ByVal hDC&, ByVal settingData!)
>> Private Declare Function GetDC Lib "user32" Alias "GetDC" (ByVal hWnd As Integer) As Integer
>宣言が間違っているようです。
>hDC や hWnd は、IntPtr型で宣言するのが一般的です。
>中には、整数型で宣言する人も居ますが、その場合は Long型(System.Int64)ではなく、
>Integer型 (System.Int32)を使う必要があります。(少なくとも、Win32環境においては)

に従って、

Public Declare Sub Drawing Lib "dynamic.dll" (ByVal hDC As IntPtr, ByVal settingData!)
Public Declare Function GetDC Lib "user32" Alias "GetDC" (ByVal hWnd As IntPtr) As IntPtr

としたのですが、GetDCの記述部分、
pic_hDC = GetDC(frmspace.picSpace.Handle.ToInt32)
において、
「型 'Integer' の値を 'System.IntPtr' に変換できません。」
というエラーが発生してしまいます。
ToInt32が怪しいと思っているのですが、ToIntPtrなるものは無く…困りました。


真琴  2004-11-04 10:41:45  No: 86418

たびたびの連続投稿で、申し訳ありません。

Public Declare Function GetDC Lib "user32" Alias "GetDC" (ByVal hWnd As Integer) As IntPtr←hWnd As IntPtrをAs Integerに
pic_hDCの型をIntPtrに直したらビルドエラーは消えました。

しかし、実行中に
'System.NullReferenceException' のハンドルされていない例外が dynamic.exe で発生しました。
追加情報 : オブジェクト参照がオブジェクト インスタンスに設定されていません。
と言うエラーが…。
ご享受お願いいたします!!


真琴  2004-11-04 10:45:34  No: 86419

因みに、Call Drawing(pic_hDC, setData(0))の部分でのエラーです。


魔界の仮面弁士  2004-11-04 11:31:28  No: 86420

> ToInt32が怪しいと思っているのですが、ToIntPtrなるものは無く…困りました。
えぇと……そもそも、なぜ ToInt32 メソッドを使われたのでしょうか?
そのメソッドは、IntPtr型を Integer型に変換するメソッドですよね。

Handleプロパティ(これは、IntPtr型を返します)を、IntPtr型を
受け取る引数に渡すのに、変換は不要でしょう。単純に、
  pic_hDC = GetDC(frmspace.picSpace.Handle)
でよいかと思いますよ。

> ご享受お願いいたします!!
こちらには試せる環境も無いですし、コードの全容も見えないので、
提示された情報だけではアドバイスのしようが無いです。(^^;)


真琴  2004-11-04 13:25:06  No: 86421

>魔界の仮面弁士さん

> こちらには試せる環境も無いですし、コードの全容も見えないので、
> 提示された情報だけではアドバイスのしようが無いです。(^^;)

当方の説明不足、申し訳ないです。
ソースの主要部分抜粋ですが、

Module _Module
    Public Declare Sub drawing Lib "dynamic.dll" (ByVal hDC As IntPtr, ByVal setData!)
    Public Declare Function GetDC Lib "user32" Alias "GetDC" (ByVal hWnd As IntPtr) As IntPtr

    Public setData(30) As Single 'VC++側へ渡す設定データ

    Public Sub Display()
        Dim frmspace As New frmspace()

        setData(0) = frmspace.picSpace.Width
   ・
  ・
  ・
        setData(15) = ・・・

        Dim pic_hDC As IntPtr = GetDC(frmspace.picSpace.Handle)

        Call drawing(pic_hDC, setData(0))

    End Sub

End Module

Display()内でsetData配列に各数値情報を与えてdrawing関数をCallして
フォーム(frmSpace)上のピクチャボックス(picSpace)に描画します。

こんな感じでお分かりいただけますでしょうか(^^;)?


魔界の仮面弁士  2004-11-05 07:41:28  No: 86422

> こんな感じでお分かりいただけますでしょうか(^^;)?

全くわからないです。m(_ _)m 役立たずですみません。

一般的なAPI等であれば、試して確認する事もできますけど、
利用されているVC++のDLL側の内部処理がわからない以上、
少なくとも私は、(VB.NETのソースだけ見ても)判断できません。

# かといって、DLL側のソースを見せられても困りますが…。

今の状態だと、宣言に問題があるのか、呼び出し方に問題があるのかさえも
判断がつきませんので、まずは問題の切り分けのために、たとえば、
値を受け取るだけの単純なDLLを作ってみて、まずは、そのDLLの
呼び出しが成功するかどうかを確認してみては如何でしょうか?

そうすれば、DLL内部でエラーが発生したのか、あるいは、そもそも
DLLの呼び出しが行われていないのかなどを切り分けできるかと思います。

まぁ、とりあえず、VB.NET側のソースで気になった点としては、
・ハンドルが正しく取得できたかどうかを確認していない。
・アンマネージドリソースの開放処理が(少なくてもVB側では)行われていない。
といったあたりでしょうか。


真琴  2004-11-05 07:44:46  No: 86423

>魔界の仮面弁士さん

ありがとうございます!
もう一度基本名部分からやりなおしてみます!

「解決」チェックが入れられる日を夢見て(笑)


るる  2004-11-06 20:58:26  No: 86424

失礼します。
私も同じような事で悩んでいます。
私の場合もVB6とVC++6の組み合わせの時はDLLのやりとりができていたのですが、
VB6をVB.NETに変更したところ、動かなくなりました。

上の投稿を参考にして、VB.NET側で、

Module _Module
    Public Declare Sub drawing Lib "dynamic.dll" (ByVal hDC As IntPtr, ByVal setData!)
    Public Declare Function GetDC Lib "user32" Alias "GetDC" (ByVal hWnd As IntPtr) As IntPtr

    Public setData(30) As Single

    Public Sub Display()
        Dim frmspace As New frmspace()

        setData(0) = frmspace.picSpace.Width
        setData(1) = frmspace.picSpace.Height

        Dim pic_hDC As IntPtr = GetDC(frmspace.picSpace.Handle)'←hDCを取得?

        Call drawing(pic_hDC, setData(0))'←DLLの関数drawingを呼び出して、setData配列を渡しているのか?

    End Sub

End Module

と、同じようなことをやってみましたが、
真琴さんと同様に、'System.NullReferenceException' のハンドルされていない例外…
が発生します。

因みにVC++6側でDLLのExportは、
_declspec(dllexport) void _stdcall drawing(HDC hDC,float* setData)
としています。

>・ハンドルが正しく取得できたかどうかを確認していない。
>・アンマネージドリソースの開放処理が(少なくてもVB側では)行われていない。
というのも、よく分からないです。


魔界の仮面弁士  2004-11-07 12:05:10  No: 86425

dynamic.dll という物を知らないため、有効な回答には
ならないかも知れませんが…一応回答。

> Dim pic_hDC As IntPtr = GetDC(frmspace.picSpace.Handle)'←hDCを取得?
『ハンドルが正しく取得できたかどうかの確認』を行ってみてください。
呼び出し後、pic_hDC が IntPtr.Zero になっているなら、失敗でしょう。

> Call drawing(pic_hDC, setData(0))'←DLLの関数drawingを呼び出して、setData配列を渡しているのか?
違うでしょう。配列を渡すなら、ByValではなくByRefになるはずですから。

> 因みにVC++6側でDLLのExportは、
> _declspec(dllexport) void _stdcall drawing(HDC hDC,float* setData)
> としています。
float setData の場合が ByVal setData As Single でしょう。
float* setData なら、ByRef setData As Single になるかと。


るる  2004-11-10 20:36:41  No: 86426

>『ハンドルが正しく取得できたかどうかの確認』を行ってみてください。
>呼び出し後、pic_hDC が IntPtr.Zero になっているなら、失敗でしょう。
 pic_hDCには変な数が入っていたので取得は出来ているようです。

>違うでしょう。配列を渡すなら、ByValではなくByRefになるはずですから。
VB6のときはByValでも動いていたのですが、ByRefにしなければ
ならないのは.NETの仕様なのでしょうか?

>float setData の場合が ByVal setData As Single でしょう。
>float* setData なら、ByRef setData As Single になるかと。

Public Declare Sub drawing Lib "dynamic.dll" (ByVal hDC As IntPtr, ByRef setData!)
としてみましたが、今度は「ハンドルされていない例外」が出ない代わりに
PictureBoxには何の反応もないんです…。


HI-KO  2004-11-30 01:22:46  No: 86427

ネットワークパスワードの入力ウィンドウを自動で表示するにはどうしたらいいのでしょうか?またパスワードを自動入力するにはどうすればよいのでしょうか?どなたかご指導お願いします。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加