DOBON.NET DOBON.NETプログラミング掲示板過去ログ

API "GetPixel" 関数について

環境/言語:[VB.NET]
分類:[.NET]

VB.NETでタイトルの関数を使用すると、うまくいきません。
具体的にいうと、色の違っても全て同じ値が返ってきます。
解決策をご存知の方いませんか?
> VB.NETでタイトルの関数を使用すると、うまくいきません。
> 具体的にいうと、色の違っても全て同じ値が返ってきます。
> 解決策をご存知の方いませんか?

正しくコーディングされていれば、そういうことにならないはずなので、
問題の再現する最低限のコードを提示してもらわないことには、
解決策を一緒に考えることはできないと思います。

ちなみにAPI関数のGetPixel関数を使わなくても、
BitmapクラスのGetPixelメソッドがあります。
> ちなみにAPI関数のGetPixel関数を使わなくても、
> BitmapクラスのGetPixelメソッドがあります。
このメソッドを使用すると、処理が遅くなってしまうので(追加の処理をしなくてはいけなくなる)、
なるべく使用したくないのです。

問題のコードは↓
////////////////////////////////////////////////////
Private Declare Function GetPixel Lib "gdi32" Alias "GetPixel" _
(ByVal hdc As Long, ByVal nXPos As Long, ByVal nYPos As Long) As Long

Private Declare Function GetDesktopWindow Lib "user32" () As Long

Private Declare Function GetDC Lib "user32" _
(ByVal hWnd As Long) As Long

Private Declare Function ReleaseDC Lib "user32" _
(ByVal hWnd As Long, ByVal hdc As Long)

中略
Private Sub GP()
Dim cl as Long
Dim hWnd as Long = GetDesktopWindow()
Dim hdc as Long = GetDC(hWnd)
cl = GetPixel(hdc,**,**)
Me.Text = cl
ReleaseDC(hWnd,hdc) ←後ここもうまく動作しません
End Sub
/////////////////////////////////////////////////////
■No1988に返信(Lexusさんの記事)
>>ちなみにAPI関数のGetPixel関数を使わなくても、
>>BitmapクラスのGetPixelメソッドがあります。
> このメソッドを使用すると、処理が遅くなってしまうので(追加の処理をしなくてはいけなくなる)、
> なるべく使用したくないのです。

対象がデスクトップだったのですね。
それだとBitmapクラスは使えない(使いづらい)ですね。

さて、本題の件、実験してみました。
最後尾添付の環境、ソースコードで動作確認しました。
VB.NETでのAPI使用上のポイントとしては、

・VB.NETではLong型の出番はまずない。(旧VBでのLong型(4バイト)はVB.NETでのInteger型(4バイト)のため)
・ハンドル関連はIntPtr型を使用する(Integer型でも代用はできる)

といったところでしょうか。

------------------------------------------------------------
実験環境:Windows2000(SP4)、IE6(SP1+その他セキュリティパッチ)
.NET Framework 1.1、VS.NET 2003
実験コード:下記
------------------------------------------------------------

Public Class Form1
Inherits System.Windows.Forms.Form

Private Declare Function GetPixel Lib "gdi32" Alias "GetPixel" _
(ByVal hdc As IntPtr, ByVal nXPos As Integer, ByVal nYPos As Integer) As Integer

Private Declare Function GetDesktopWindow Lib "user32" () As IntPtr
Private Declare Function GetDC Lib "user32" Alias "GetDC" _
(ByVal hwnd As IntPtr) As IntPtr
Declare Function GetWindowDC Lib "user32" Alias "GetWindowDC" _
(ByVal hwnd As IntPtr) As IntPtr

Private Declare Function ReleaseDC Lib "user32" Alias "ReleaseDC" _
(ByVal hwnd As IntPtr, ByVal hdc As IntPtr) As Integer

Private Declare Function CreateCompatibleBitmap Lib "gdi32" Alias "CreateCompatibleBitmap" _
(ByVal hdc As IntPtr, ByVal nWidth As Integer, ByVal nHeight As Integer) As IntPtr

#Region " Windows フォーム デザイナで生成されたコード "

Public Sub New()
MyBase.New()

' この呼び出しは Windows フォーム デザイナで必要です。
InitializeComponent()

' InitializeComponent() 呼び出しの後に初期化を追加します。

End Sub

' Form は、コンポーネント一覧に後処理を実行するために dispose をオーバーライドします。
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

' Windows フォーム デザイナで必要です。
Private components As System.ComponentModel.IContainer

' メモ : 以下のプロシージャは、Windows フォーム デザイナで必要です。
'Windows フォーム デザイナを使って変更してください。
' コード エディタを使って変更しないでください。
Friend WithEvents Timer1 As System.Windows.Forms.Timer
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container
Me.Timer1 = New System.Windows.Forms.Timer(Me.components)
'
'Timer1
'
Me.Timer1.Interval = 1000
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 12)
Me.ClientSize = New System.Drawing.Size(280, 45)
Me.Name = "Form1"
Me.Text = "Form1"

End Sub

#End Region

Private hwnd As IntPtr
Private hdc As IntPtr

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Me.Text = Control.MousePosition.ToString() & " " & ColorTranslator.FromWin32(GetPixel(hdc, Control.MousePosition.X, Control.MousePosition.Y)).ToString()
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
#If True Then
' OKパターン1
hwnd = GetDesktopWindow()
hdc = GetWindowDC(hwnd)
#Else
' OKパターン2
hwnd = IntPtr.Zero
hdc = GetDC(hwnd)
#End If
' NGパターン(何故かは不明だが、下記の2行のコードだとうまくいかない
' hwnd = GetDesktopWindow()
' hdc = GetDC(hwnd)
Me.Timer1.Enabled = True
End Sub

Private Sub Form1_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed
Me.Timer1.Enabled = False
Dim ret As Integer = ReleaseDC(hwnd, hdc)
Debug.WriteLine("(戻り値:1-成功、0-失敗)ret=" & ret)
End Sub
End Class
XPでの動作確認しました。
原因はNGパターンのコードだったんですね。色々と勉強になりました。

追記:よねKENさんは凄いですね。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板