Wish to switch to twips

     I have a shiny new API call returning x, y mouse
coordinates in pixels, or at least in something not twips.
Twips is what I need.

(I'll try to do it right this time):

  I have no access to class functions. If a Windows function
is needed, it has to be API. The constant values for any required arguments are also needed. I have no way of knowing how difficult this might be. If it involves SetMapMode, I can't see how I can get it done. In any case, I'll monitor the points accordingly. It's not important enought to my app
for me to be spending my sleeping hours on it, though,
so if it's real tricky, I won't bother.

 Nietod may have some ideas on this.
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Answer coming.
I'm not sure how I got the honor of being singled out but...

Converting to twips is easy.  

given a DC handle "DCHnd" and a mouse X coordinate "X"

int Res = GetDeviceCaps(DCHnd,LOGPIXELSX); // Resolution
int XTwips = X*1440/Res; // Position in TWIPS.

Note if the horizontal resolution is different than the vertical resolution you should use LOGPIXELSY to calculate the Y coordinate.  However, they are usually the same so you can probably just use the one value to convert both.


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Just thought of something, you don't have a device context in this case, but you as you may or may not know, you can create a screen DC just using

PMI ACP® Project Management

Prepare for the PMI Agile Certified Practitioner (PMI-ACP)® exam, which formally recognizes your knowledge of agile principles and your skill with agile techniques.

philcAuthor Commented:
Would you happen to know the values corresponding to
philcAuthor Commented:
     I ' m not going to pursue this problem any more. There are too many glitches showing up. The formula you provided just did not work. I don't know if that's because I was mistaken in assuming that pixels were being reported by GetCursorPosition. Suspiciously if I multiply X * 14.4 I get the right result. But it doesn't work for y. (As I'm sure you know, 14.4 is
1/100 of the number of twips that corresponds to an inch).

       Other complications are that GetCursorPosition reports with integers which isn't accurate enough for doing conversions. GetCursorPosition is also too slow in my current environment.

 I obtained information from Microsoft on other areas I needed.
e.g. the values to supply to GetDeviceCaps, 8 and 10. And the prototype for GetActiveWindow. As I mentioned in the question, this problem isn't crucial enough for the kinds of headaches it's beginning to return. And I don't know enough Windows programming to play with it with any hope of a reasonable and reasonably quick result. I'll leave this open for a while in
case you want to comment. Incidentally, GetKeyState is working fine.

I think you are giving up too easy!  I'm willing to try to make it work.

The formula should work.  The cursor coordinates are returned in pixels.  

If you don't want to work in integers, you can convert the integer coordinates to floating point before doing the conversion.  However, this is not necessary if you do the math in the appropriate order  (first multiply then divide, my formula did.)

Why do you want the constants cooresponding to LOGPIXELSX and y?  why can't you use the constants?  Not working in C?

If you do want to make it work, what is going wrong?
What do you mean that GetCursorPos() is too slow in your environment?  It should be extremely fast as it is simply returning two integers that windows stores in memory.  You should be able to perform it tens or hundreds of thousands of times a second.  How fast do you need?
philcAuthor Commented:
     No, I'm not working in C, I'm working in Access Basic, so
I don't have the files where the constants are defined.

 The numbers that are being returned by GetCursorPosition
do not correspond (after conversion) with the numbers returned by the built in OnMouseDown.

  I want to use a stand alone procedure to handle OnMouseMove,
i.e. one that's not bound to the form. That's why I'm not
using the built in Event Procedure. The Event Procedure
returns single precision floating point for x and y,
and does so very quickly. It needs to be quick for drawing
purposes. GetCursorPos APPEARS to slow down the drawing
to screen in comparison. This may be partially because of
the need to convert to twips first. But I stress that I'm
working with older equipment. Although this application will
be implemented on fast machines, I am holding myself to the
standard set by the system.
      I can't explain why the formula
isn't working. I believe I have checked it rigourously.

     My current screen resolution is 640 x 480. And I wanted to ask you about this. You said that the horizontal resolution is usually the  same as vertical. Are you referring to newer systems? My familiarity is with resolutions such as 800 X 600, the above, and the SVGA resolution which I can't put exact numbers to right now, but in all cases the resolution is different for horizontal and vertical. This may not be important,but on the other hand maybe I'm missing something fundamental.

int XTwips = X*1440/Res

Example : ( 3 mouse clicks)

x returned by OnMouseMove             =  4125
GetCursorPos.x (before conversion)    =  284
Converted from Pixels to Twips        =  639

x returned by OnMouseMove             =  4125
GetCursorPos.x (before conversion)    =  284
Converted from Pixels to Twips        =  639

x returned by OnMouseMove             =  4125
GetCursorPos.x (before conversion)    =  284
Converted from Pixels to Twips        =  639

Here's the code for above:

(ThisPosxy as pointapi)

Call GetCursorPos(ThisPosxy)

Debug.Print "x returned by OnMouseMove         =  " & x
Debug.Print "GetCursorPos.x (before conversion)=  " & ThisPosxy.x
Debug.Print "Converted from Pixels to Twips    =  " &_

CDbl(ThisPosxy.x) * 1440 / 640

(640 = horizontal resolution as returned by GetDeviceCaps.)

     I checked to make sure  that the frame of reference was valid, in other words Pixel one exists, (roughly) in the same place on screen as Twip one.I even tried using the vertical resolution in case I was suffering from some kind of unusual
brain disease, and I couldn't tell the two apart. I still may be
missing something fundamental, but as you can see, I don't know what. I've been at it pretty hard and sometimes what's really needed is to stop and think for awhile. (I'll try anything!)

  Besides the obvious problem above, if I convert an integer to
floating point, am I not converting numbers that have already been rounded off, i.e. isn't inaccuracy already built in with the numbers returned by GetCursorPos?

I'm not inclined to give up at all, let alone easily, but my feeling was that I may be trying to stretch the capabilities of what I'm working with too far, in which case I'd be wasting your time and my own, something I'd like to avoid.

Actually, I tend to like a challenge, but that's my problem. If
you're still on board though, I'm all ears.

Gosh a book!  just some points as I read through it...

first of all, GetCursorPos points are relative to top-left corner of screen.  WM_MOUSEMOVE, WM_LBUTTONDOWN, etc are relative to the client area of the window receiving the message.  You can use ClientToScreen() or ScreenToClient() to convert.

The word "Resolution" is used in different ways, mostly in an attempt to make things more incomprehesible  than they already are.  The resolution in my example was pixel densify, or pixels per inch.  The resolution you discus is the total number of pixels in a direction or the physical dimension of the screen measured in pixels (rather than inches or twips, etc.)  Make sense.  I'll try to avoid the word resolution in the future.

The conversion I propose could be done many thousands of times a second on a 8086.  It is not what is slowing things down.

In your sample the X returned by MOUSEMOVE message is in the 4000's  That must be converted to TWIPs already.  Right?  Otherwise it is 4000 pixels from the left edge of the window's client area.  That's a big window...  If it is in TWIPs did you do the conversion or does Access Basic do it for you?  If access basic is doing it for you and does not provide a ClientToScreen() that works in TWIPs you are going to have to make one.

Wait a second, you don't want to divide by 640.  Thats the wrong resolution.  You used the wrong constant for GetDeviceCaps().

Darn.  I have to go now.  I will get back to you.  Probably tonight.  If not tommorrow morning.  Bye.
False alarm.  I have a few more minutes.

Get cursor position returns the pixel that the mouse hot spot is on.  You can't have fractional pixels so you don't need floating point.  That is, the mouse can't be 10.5 pixels from the left edge of the screen.  You could never draw it there.  Since twips are much smaller than pixels (on present day monitors), you can express pixel coordinates in twips using integers with very good accuracy.  Is pixel density (the number of pixels per inch) increases this will be a problem.  However, basically it hasn't increased at all in the last 10 years.  But if you want to be safe use floating point.  It is probably unnecessary but the only harm is a slight loss in speed and a little extra memory usage.

Now I do have to go.
philcAuthor Commented:
I'll need a little time to digest this.
I'm back.  Just let me sum up here.

Get rid of the 640 figure.  You want to use LOGPIXELSX = 88 and LOGPIXELSY == 90.  Those are the values to pass to GetDeviceCaps(), not the numbers to use in the calculation.

If you need more help, I need to know how you want the final coordinates expressed, that is in TWIPs, but from what location?

If you need to use the coordinates returned from WM_MOUSE (or related messages)  how are they being returned for you?  (In standard windows it is in pixels from the top left corner of the client area, but I suspect Access Basic is converting this for you.)
philcAuthor Commented:
     OK, I've fed the right numbers into GetDeviceCaps,
and things look to be working according to the way you
indicated. I have to be careful of my terminology here, cause
I'm not 100 per cent sure of it. What I need is the twip x y
location for the particular window I'm working with. That is,
NOT from the edge of the screen, but from the edge of whatever
dialog box or window I happen to be working with regardless of
its position relative to edge of the screen. If the window
happened to be 2 inches wide, 2880 twips, then the area I'm
concerned with is THAT 2 inch area, and everything is to be
relative to that. Access Basic does do this automatically so
that in a 2 inch window, if the mouse is one inch along it
horizontally, Access will return 1440 (Access returns in
twips) for x, and that's what I need. I've already tested with the proper numbers, and GetCursorPos converted appears to be returning coordinates, (I believe just as you said), from the edge of the screen.

  I'll check in first about 7 P.M. my time, (2 P.M. east
coast U.S., 11 A.M. west coast) Feb 19

I think I understand you.  But maybe not.  You mentioned the width of the window several times.  That doesn't realy matter, right?  If the mouse is 1 inch from the left edge of the window you want x to be 1440 twips regardless of whethor or not the window is 2 inches wide or 3 inches wide.  Right?

I'll asume so.  Also I'll assume we're talking about the client area of the window, not the window (frame) area.  (If you need the frame, its the same solution with an adjustment.)

All you need to do is adjust the coordinates returned from GetCursorPos() to be relative to the window's client area with ScreenToClient().  The adjusted position will still be in pixels, but relative to the top-left corner of the window's client area not the screen.  Then convert to twips as before.

Now I don't know basic, but it would be something like

(ThisPosxy as pointapi)

Call GetCursorPos(ThisPosxy)
Call ClientToScreen(WndHnd,ThisPosxy)

CDbl(ThisPosxy.x) * 1440 / GetDeviceCaps(LOGPIXELSX)
CDbl(ThisPosxy.y) * 1440 / GetDeviceCaps(LOGPIXELSY)

Hope this helps.

philcAuthor Commented:
I'll give it a go.
philcAuthor Commented:
The answer to that is yes and also regardless of where
the window is located on the screen, so that the point
of reference is entirely the active window, not
including the frame. I hate to shock you, but wait til
you see...



Execution begins:



1. Before ScreenToClient         TPy =  97              - Pixels
2. y returned by (Access)OnMouseDown =  45  (Desired)   - Twips
3. GetCursorPos.y (before conversion)=  59  (After STC) - Pixels
4. Converted from Pixels to Twips    =  885 (Result)    - Twips



1. Before ClientToScreen           TPy  =  97    
2. y returned by (Access)OnMouseDown    =  45
3. GetCursorPos.y (before conversion)   =  135  After CTS
4. Converted from Pixels to Twips       =  2025

Execution ends:

Execution begins:   (Window moved down):



1. Before STC                     TPy =  207              -Pixels
2. y returned by (Access)OnMouseDown  =  45   (Desired)   -Twips
3. GetCursorPos.y (before conversion) =  169  (After STC) -Pixels
4. Converted from Pixels to Twips     =  2535 (Result)    -Twips




1. Before CTS                       TPy =  207
2. y returned by (Access)OnMouseDown    =  45
3. GetCursorPos.y (before conversion    =  245   After CTS
4. Converted from Pixels to Twips       =  3675

Execution ends:


Let me explain:

Line one in each SECTION is the unadjusted, unconverted, raw
GetCursorPos.y number.

Line two is what Access Basic returns for y
(the DESIRED Number, in TWIPS)

Line three for SECTION A and C is the figure returned
for GetCursorPos.y by ScreenToClient.

Line three for SECTION B and D is the figure returned
for GetCursorPos.y by ClientToScreen.

Line four is the TWIPS returned by GetCursorPos AFTER
all calls and conversions.

  Sections A and B are results from  OnMouseDown with
the active window near the top of the screen. For C
and D I moved the window down.

A and B report on the same execution, as do C and D.

  To repeat, Sections A and C ABOVE represent numbers that result
from calls to ScreenToClient, while B and D reprsent numbers
that result from calls to ClientToScreen,

ScreenToClient, as is to be expected produces a
lower number for GetCursorPos.y after it's called, while
ClientToScreen produces a larger one.

(Line one TPy for each section is GetCursorPos.y BEFORE
ScreenToClient, or ClientToScreen is called:


Line three is GetCursorPos.y AFTER the call to
either ScreenToClient or ClientToScreen. )

In all cases the final result for twips is still way too

  I'm speculating that the issue revolves around identifying
the correct window client area. What appears to be
happening above is that the ScreenToClient call is returning
numbers for the Access application window. ClientToScreen is
converting to the overall screen.

 I have another window inside the Access application
window. That's the one I'm clicking in. And the result
is as you see above. But having said all this,
I don't see why a click inside the active window wouldn't
give you the handle of the active window. Then again,
I did say this was speculation.

  If you look at the numbers above carefully, you'll
see that the returned values do indicate two context
levels, while it seems that the one I want is a third.

 As I mentioned before, I'm not big on Windows
programming. GetActiveWindow may not be appropriate
in this situation, (although it sure sounds right).

 Also, there are prototypes that need to be declared in
Access Basic, and for API calls these aren't always
easy to find. So some assumptions were made for
ClientToScreen and ScreenToClient. These calls
appear to be working however.

Well, I did say that the road could and probably
would be bumpy. I'm not panicing, and I'm not in any big
rush, so....whatever.  

Re: Call ClientToScreen(WndHnd,ThisPosxy)

I used GetActiveWindow for WndHnd


philcAuthor Commented:
A thought: Could IsZoomed be a factor?
allright.  I'm not sure what to say.

First of all.  You only need ScreenToClient() not ClientToScreen().  This because you are given coordinates relative to the screen and want to get them relative to the client area of the window.

I think the real issue here is which window.  (GetActiveWindow is not what you want.)

In typical windows programming this sort of processing is handled in a window procedure so you know which window you want to deal with.  I'm not sure how you are handling it, but I suspect it is not a window procedure.  Is that right?  Can you explain to me (1) the code design, i.e. where the code "is" and what it is doing, who calls it ect.  (2) The window design.  That is what windows do you have to work with.

Just had a thought.  If you can't find a window any other way, (if your code isn't associated with a window) you can use GetWindowFromPoint() to get the window under the mouse.

it returns a window handle and takes a POINT as a parameter. (not a point pointer)  Pass it the point as returned from GetCursorPos().  (That is, wefore converting to client or TWIPS.)  That gives you the window to use when converting to client.  The convert to twips.  That should be what you need.
philcAuthor Commented:
 Fooling around with  GetWindowFromPoint() could make for a nice
hobby, but here's what I wrote before seeing your latest

       That's it done. Because the regular edition of
Access is not what you'd call rich in API tools, I
just had a brain cloud and forgot that forms in Access
actually have an hwnd property, meaning you can refer
to that property directly, thusly: forms!myform.hwnd, simple
as that. What GetActiveWindow actually does remains a
mystery, what it doesn't seem to do is return the handle
to the active window, but I admit to a certain naivete
in these matters and I just might not know what active
window means. There is a 15 Twip disparity being returned
but it is consistent and simply requires adding it on.
I don't know what this fifteen twips is, it doesn't seem
enough for a window frame. Anyway, thanks for the assistance.
You can keep that last set of comments from me, show it
to your grand kids some day as the reason why you chucked
programming and went back to your first love, snowboarding
or something. Thanks again,

You may want to test on different screen pixel densities (I was going to say resolutions) to see if the 15 pixel offset stays constant.  That is, change your monitor from 640X480 to 800X600 or 1024X768 and test again.  If it changes you're not quite there yet.

What I suspect it is 1 pixel difference that ends up becoming an X twips difference (depending on pixel density).  If that is the case you need to make the adjustment before converting to twips to have it work on all pixel densities.  That is, add or subtract one and then convert.

A quick mathematcal check just seemed to show this is the case.  At 96 pixels per inch (typical pixel density for a 12 inch display) you get exactly 15 twips per pixel.  I don't beleive in coincidence.  
FYI the active window is the top-level window that has the focus or has a discendant window that has the focus.  GetActiveWindow() was probably the parent (or grand parent etc.) of the window you wanted.
philcAuthor Commented:
 96 IS the number, and this looks like the piece that comes
after the penultimate piece in the puzzle. Much obliged...

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.