Solved

The GetPixel API function  - It doesn't work!

Posted on 2001-09-02
31
561 Views
Last Modified: 2012-05-04
'Delaration for the getPixel API function
Private Declare Function GetPixel Lib "gdi32" _
    (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long) As Long

'code
Dim pixVal As Long
pixVal = GetPixel(Form1.hdc, 100, 100)


The value pixVal gets set to is -1, when it should be some positive number. What are possible problems with this code? It seems like it should certainly work to me.
0
Comment
Question by:jamesxi
  • 13
  • 5
  • 3
  • +6
31 Comments
 
LVL 49

Expert Comment

by:Ryan Chong
ID: 6449697
0
 
LVL 6

Expert Comment

by:JonFish85
ID: 6449698
try setting the forms ScaleMode = vbPixels.

hope this helps!
0
 

Author Comment

by:jamesxi
ID: 6449725
Changing the mode to pixel didn't help. That MVPS.org example used almost the exact same code that I did. The only difference I can see is that they used a picture instead of a form. Shouldn't getPixel work on any type of object though?
0
 
LVL 6

Expert Comment

by:JonFish85
ID: 6449735
try using your same code on a picturebox... That way we know that the GetPixel() is working...
0
 

Author Comment

by:jamesxi
ID: 6449749
It won't give me the hdc of the picture. I'll try using another program I have though that can get the hdc of any object.
0
 

Author Comment

by:jamesxi
ID: 6449752
No, it simply does not work at all. Not on a picurebox. Not on anything. Did you try to get the code to work? Its extremely quick to try. Just copy the delcare statement in a module, then the rest of the code in with the form code.
0
 
LVL 6

Expert Comment

by:JonFish85
ID: 6449753
its worked for me before, as I've used the GetPixel stuff... Im burning a cd now, but Ill try it in a little bit.
0
 

Author Comment

by:jamesxi
ID: 6449773
OK, well see if you can stuff a working getPixel function in a module so all i have to do is call the thing using a call statement. It seems like it works perfectly for everyone but me!
0
 

Author Comment

by:jamesxi
ID: 6449778
Wait a second, can only one hDC be open at a time?
0
 
LVL 6

Expert Comment

by:JonFish85
ID: 6449781
this worked for me:

Option Explicit
Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long

Private Sub Command1_Click()
  MsgBox GetPixel(Me.hdc, 100, 100)
End Sub

when Me.Picture is set to some whatever sort of picture...
0
 

Author Comment

by:jamesxi
ID: 6449810
OK, now i'm mad!!!!!!!!! I copied and pasted, then fixed your code since getPixel has to be in a module and it has to be public. The command click has to be on the form code. After that I ran the program and it gave me this value: -1! I click the button and it gives me a -1! Thats right. -1!
0
 

Author Comment

by:jamesxi
ID: 6449820
Finally! The author of GetPixel program (Feng Jian Yu) sent me this code which actually works! I am still trying to figure out why it works because my code and your code look just like it! I'll let you know when I figure it out.

'**************************modules*************************
Type POINTAPI
    X As Long
    Y As Long
End Type
Public Declare Function GetDC Lib "User32" (ByVal hWnd As Long) As Long
Public Declare Function GetCursorPos Lib "User32" (lpPoint As POINTAPI) As Long
Public Declare Function GetPixel Lib "gdi32" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long) As Long
Public Declare Function ReleaseDC Lib "User32" (ByVal hWnd As Long, ByVal hDC As Long) As Long
'*********************************************************

Private Sub Form_Load()
    Dim pt As POINTAPI
    Dim c As Long

    h = GetDC(0)
    GetCursorPos pt
    c = GetPixel(h, pt.X, pt.Y)
    ReleaseDC 0, h
End Sub
0
 
LVL 6

Expert Comment

by:pierrecampe
ID: 6450378
put all this in a form:

Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long

Private Sub Command1_Click()
    dim a as long
    a = GetPixel(Me.hdc, 100, 100)
    MsgBox a
End Sub

it will work
why it does not work for you is that the declaration is probably in a module
if in a module the declaration has to be public

what that other code does:
Private Sub Form_Load()
   'it dims a variable as pointapi (udt)
   Dim pt As POINTAPI
   ' it dims a variable as a long
   Dim c As Long

   'it gets the device context to the screen
   'not your form
    h = GetDC(0)
    'it puts the screen coordinates of the mouse in pt
    GetCursorPos pt
    'it gets the color of the pixel under the mouse
    c = GetPixel(h, pt.X, pt.Y)
    'it releases the device context
    ReleaseDC 0, h
End Sub
0
 
LVL 1

Expert Comment

by:dekeldate
ID: 6450878
The main difference btw the ode that works on jamesxi and the others whih are simillar is that Feng Jian Yu uses h = GetDC(0) to get the handle to a display device context, in this case the form.
0
 
LVL 1

Expert Comment

by:dekeldate
ID: 6450885
disregard the previous, my c key is a bit jammed.
The main difference btw the code that works on jamesxi machine and the others which are simillar is that Feng
Jian Yu uses h = GetDC(0) to get the handle to a display device context, in this case the form.
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 

Author Comment

by:jamesxi
ID: 6451226
OK. I understand the problem better now, though I am not really any closer to the solution. My progrom is designed to grab the pixel color ANYWHERE on the screen, not just within my program. Therefore, it must get the DC handle on whatever object it is currently over.

The problem occurs when the object does not start at 0,0 on the screen. This means if the object starts at 100,100 on the screen then pixels at 10,10 do not even exist which would be why it returns -1.

To solve this issue I guess I have to figure out which pixel the object starts at on the screen. I hope this is possible!
0
 
LVL 6

Expert Comment

by:JonFish85
ID: 6451229
you could try the ScreenToClient and ClientToScreen API's. Im not sure what you are really asking though...
0
 

Author Comment

by:jamesxi
ID: 6451299
This code works when the curser is over the desktop screen but its performance is spotty at best when over other objects:

'module code
Private Type POINTAPI
    x As Long
    y As Long
End Type
Private curPoint As POINTAPI

Public Sub getColorOverCurser(ByRef red As Integer, ByRef green As Integer, ByRef blue As Integer)
Dim objHandle As Long
Dim dcHandle As Long
Dim fxResponse As Long
Dim pixVal As Long
Dim xLoc As Long
Dim yLoc As Long

Call GetCursorPos(curPoint)
xLoc = curPoint.x
yLoc = curPoint.y

objHandle = WindowFromPoint(xLoc, yLoc) 'gets object handle from given coord
dcHandle = GetDC(objHandle) 'gets dc handle from given object
 
pixVal = GetPixel(dcHandle, xLoc, yLoc)

red = pixVal Mod &H100  'get red
pixVal = pixVal \ &H100  'process formula
green = pixVal Mod &H100 'get green
pixVal = pixVal \ &H100  'process formula
blue = pixVal Mod &H100 'get blue
 
fxResponse = ReleaseDC(objHandle, dcHandle) 'releases dc handle

End Sub

'form objects: a timer(interval set to 200) and a textbox

'form code:
Private Sub Timer1_Timer()
Dim red As Integer
Dim green As Integer
Dim blue As Integer
Call getColorOverCurser(red, green, blue)
Text1.Text = red & "," & green & "," & blue
End Sub
0
 

Author Comment

by:jamesxi
ID: 6451305
Oops, I forgot some code in my last comment. The API declares in the module should be:

'gets position of curser
Public Declare Function GetCursorPos Lib "user32" _
    (lpPoint As POINTAPI) As Long

'gets the window handle from a given point
Private Declare Function WindowFromPoint Lib "user32" _
    (ByVal xPoint As Long, ByVal yPoint As Long) As Long

'gets the color of a given pixel
Private Declare Function GetPixel Lib "gdi32" _
    (ByVal hDC As Long, ByVal x As Long, ByVal y As Long) As Long
'gets the device context(DC) of a given handle
Private Declare Function GetDC Lib "user32" _
(ByVal hWnd As Long) As Long
'releases the device context(DC) of a given handle
Private Declare Function ReleaseDC Lib "user32" _
(ByVal hWnd As Long, ByVal hDC As Long) As Long
0
 

Author Comment

by:jamesxi
ID: 6451322
The code I just gave works just fine when the curser is over the desktop screen. However, when I open up a computer game to test the function with, it will work incorrectly. When my curser is over position 20, it will actually get the value of a nearby pixel for example 28, 44(?). So my question is, why is it not getting the pixel I tell it to get, and how will it get the pixel I want it to get?
0
 

Author Comment

by:jamesxi
ID: 6451345
Well, since my question has changed and this message is so long I'll just delete this and start a new question.
0
 
LVL 6

Expert Comment

by:pierrecampe
ID: 6452011
jamesxi
the code given to you by Feng Jian Yu will work and it will work always because it does not get the device context of a particular window it gets the device context of the screen
but regarding your comment:
>When my curser is over position
20, it will actually get the value of a nearby pixel for example 28, 44(?). So my question is, why is
it not getting the pixel I tell it to get, and how will it get the pixel I want it to get?<

how do you know the position of mouse cursor ?
what i mean is the GetCursorPos api returns the position of the cursors hotspot and how do you know where the cursors hot spot is ?
especially is the cursor of that game the standard arrow ?
might it just be possible you think the cursors hotspot is at say 20,20 when it really is at say 23,21
did you ask the color of a specific pixel on the screen and did you count the pixels just to make sure ?
as far as my experience goes the method by Feng Jian Yu will give correct results no matter what window the cursor is over
but then again my experience does ofcource not include every possible hardware combination,
0
 
LVL 2

Expert Comment

by:JanusFury
ID: 6454944
I've done a lot of work with GetPixel, and I know exactly what's going on.
Using GetPixel on a location OUTSIDE of the edge of an hDC returns -1. That means you're trying to sample from outside your hDC. To get an hDC from a picture, you have to create a new hDC of your own in memory, and copy the picture onto that hDC. Or you can just put the picture in a picturebox - that'll work too.

If you want to sample directly from the screen, you have to retrieve the hDC of the screen. But then, if someone moves the mouse over your form or picturebox, the mouse coordinates you get won't be correct. use GetCursorPos for that.

Are you trying to get pixels while a fullscreen game is open?
0
 

Expert Comment

by:Linguar
ID: 6454946
Wow, long topic,

Well I can say that there are many ways other then Get/Set Pixel, by directly accessing the array of the image by using GetDIBits, but that's a bit complicated.
I'm sure my friend Janus (Kevin) will drop by this one.

Later,

Linguar
0
 

Expert Comment

by:Linguar
ID: 6454950
Woah, speak of the devil, he got in before me even :)
0
 
LVL 2

Expert Comment

by:JanusFury
ID: 6454954
This should do the trick:

Public Declare Function GetDesktopWindow Lib "user32" () As Long
Public Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Public Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hDC As Long) As Long
Public Declare Function GetCursorPos Lib "user32" Alias "GetCursorPos" (lpPoint As POINTAPI) As Long
Public Type POINTAPI
   x As Long
   y As Long
End Type

Public Function getColorUnderCursor() as Long
Dim mousePoint as POINTAPI
Dim mouseX As Long
Dim mouseY As Long
Dim deskWnd As Long, deskDC As Long
deskWnd = GetDesktopWindow
deskDC = GetDC(deskWnd)
Call GetCursorPos(mousePoint)
mouseX = mousePoint.x
mouseY = mousePoint.y
getColorUnderCursor = GetPixel(deskDC, mouseX, mouseY)
Call ReleaseDC(deskWnd, deskDC)
End Sub
0
 
LVL 6

Expert Comment

by:pierrecampe
ID: 6455281
correct
and if i remember it correct jamesxi was the first to post that code
so jamesxi since you were the first to post the solution give the points to yourself :-)
0
 
LVL 2

Expert Comment

by:JanusFury
ID: 6457500
Yes james, you were on the right track the whole time. :)
0
 

Author Comment

by:jamesxi
ID: 6466361
I restarted the question since I knew most people just wouldn't bother reading through the whole thing. Sure enough, someone was able to see the problem. The problem is that you have to specify the position in the window to grab the pixel at, NOT the screen. Luckily their is an API function that does this for me (the ScreenToClient function). The reason I was getting a negative 1 sometimes is that certain objects on a window simply do not work with the GetPixel function. To correct that you have to do some weird BitBlt trick that is illustrated at the BlackBeltVB site (http://blackbeltvb.com/free/GETPIXEL.ZIP)

In addition to the code I already have this declare is needed:
Private Declare Function ScreenToClient Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long

Modified getcolor routine:

Public Sub getColorOverCurser(ByRef red As Integer, ByRef green As Integer, ByRef blue As Integer)
   'The function that works!:
   Dim objHandle As Long 'wnd handle for object under curser
   Dim dcHandle As Long 'dc handle for object under curser
   Dim pixVal As Long 'the getpixel function should set
   Dim xLoc As Long
   Dim yLoc As Long
   
   Call GetCursorPos(curPoint)
   xLoc = curPoint.X
   yLoc = curPoint.Y
   
   objHandle = WindowFromPoint(xLoc, yLoc) 'gets object handle from given coord
   dcHandle = GetDC(objHandle) 'gets dc handle from given object
   
   
   'Converts screen coordinates to window coordinates
   ScreenToClient objHandle, curPoint
   xLoc = curPoint.X
   yLoc = curPoint.Y
   
   pixVal = GetPixel(dcHandle, xLoc, yLoc)
   
   red = pixVal Mod &H100  'get red
   pixVal = pixVal \ &H100  'process formula
   green = pixVal Mod &H100 'get green
   pixVal = pixVal \ &H100  'process formula
   blue = pixVal Mod &H100 'get blue
   
   Call ReleaseDC(objHandle, dcHandle) 'releases dc handle

End Sub

Sorry that I stopped responding but I thought I actually deleted the question, but here it is a few days later still alive. Thanks to all for helping me out and especially to PaulHews who figured out the solution.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 7205384
Hi jamesxi,
It appears that you have forgotten this question. I will ask Community Support to close it unless you finalize it within 7 days. I will ask a Community Support Moderator to:

    Refund points and save as a 0-pt PAQ.

jamesxi, Please DO NOT accept this comment as an answer.
EXPERTS: Post a comment if you are certain that an expert deserves credit.  Explain why.
==========
DanRollins -- EE database cleanup volunteer
0
 
LVL 5

Accepted Solution

by:
Netminder earned 0 total points
ID: 7240876
Per recommendation, points refunded and question closed.

Netminder
CS Moderator
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now