Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

EM_CHARFROMPOS

140 views
Skip to first unread message

Leslie Milburn

unread,
Jul 4, 2005, 11:57:01 AM7/4/05
to
Hi all,

I am using EM_CHARFROMPOSs with a standard edit control (not a richedit) and
the index returned is a bit confusing.
Heres the Basic Code:

GetCaretPos(&CaretPos);
Index = SendMessage(hWndEdit, EM_CHARFROMPOS, NULL, MAKELONG(CaretPos.x,
CaretPos.y));

Now if the edit control contains 25/06/2005 and I do the above in response
to WM_KEYDOWN for a VK_RIGHT
what occurs is that the index is correct except when the closest character
is the '/'. This gets ignored and the index for the 0 is returned. Doing
other tests I am finding that spaces and punctuation are being ignored under
many circumstances.

So my question is - am I reading the documentation incorrectly. The
Documentation says the index for the closest character and to me a backslash
is a character. But perhaps they mean alphanumeric characters ?

Can anyone enlighten me please.
Leslie.


John Carson

unread,
Jul 4, 2005, 1:54:05 PM7/4/05
to
"Leslie Milburn" <CD...@NOSPAM.bigpond.com> wrote in message
news:uvI8EELg...@TK2MSFTNGP12.phx.gbl

> Hi all,
>
> I am using EM_CHARFROMPOSs with a standard edit control (not a
> richedit) and the index returned is a bit confusing.
> Heres the Basic Code:
>
> GetCaretPos(&CaretPos);
> Index = SendMessage(hWndEdit, EM_CHARFROMPOS, NULL,
> MAKELONG(CaretPos.x, CaretPos.y));
>
> Now if the edit control contains 25/06/2005 and I do the above in
> response to WM_KEYDOWN for a VK_RIGHT
> what occurs is that the index is correct except when the closest
> character is the '/'. This gets ignored and the index for the 0 is
> returned.

You mean the 0 preceding the 6? So the index jumps ahead?

> Doing other tests I am finding that spaces and punctuation
> are being ignored under many circumstances.
>
> So my question is - am I reading the documentation incorrectly. The
> Documentation says the index for the closest character and to me a
> backslash is a character. But perhaps they mean alphanumeric
> characters ?

No, they mean all characters.

> Can anyone enlighten me please.
> Leslie.

The index is given by the LOWORD of the return value. You should also use
MAKELPARAM rather than MAKELONG.

I get all character positions without a problem. If you could give a
compileable code sample illustrating the problem plus information on the OS
version you are using, then perhaps we will be able to help more.

--
John Carson

Leslie Milburn

unread,
Jul 5, 2005, 12:50:14 AM7/5/05
to
Hi John,

"John Carson" <jcarson_n...@netspace.net.au> wrote in message


>>
> > Now if the edit control contains 25/06/2005 and I do the above in
> > response to WM_KEYDOWN for a VK_RIGHT
> > what occurs is that the index is correct except when the closest
> > character is the '/'. This gets ignored and the index for the 0 is
> > returned.
>
> You mean the 0 preceding the 6? So the index jumps ahead?

Yes thats correct. It then corrects itself for the next character.

> I get all character positions without a problem. If you could give a
> compileable code sample illustrating the problem plus information on the
OS
> version you are using, then perhaps we will be able to help more.

I knocked together a quick and nasty, code is below:

Test Results:
CharFromPos returns wrong result on Win98SE (4.10.2222A) and
WinMe (version 4.90.3000).
It returns the correct value on WinXP - SP1A


The Resource File
----------------------------------------------
cm0back DIALOG LOADONCALL MOVEABLE DISCARDABLE 18, 9, 428, 247
STYLE WS_POPUP | DS_MODALFRAME | WS_BORDER | WS_CAPTION | WS_SYSMENU |
WS_VISIBLE
CAPTION "EM_CHARFROMPOS"
FONT 8, "Arial"
BEGIN
CONTROL "Edit Field", IDC_STATIC1, "Static", WS_CHILD | WS_VISIBLE |
SS_LEFT, 49, 28, 52, 12
CONTROL "", IDC_EDIT, "Edit", WS_CHILD | WS_VISIBLE | WS_BORDER |
WS_TABSTOP | ES_LEFT, 108, 26, 142, 13
CONTROL "Info", IDC_STATIC2, "Static", WS_CHILD | WS_VISIBLE | SS_LEFT,
20, 55, 57, 12
CONTROL "", IDC_EDIT2, "Edit", WS_CHILD | WS_VISIBLE | WS_BORDER |
WS_VSCROLL | WS_TABSTOP | ES_AUTOVSCROLL | ES_MULTILINE | ES_LEFT, 60, 53,
335, 133
CONTROL "Exit", IDCANCEL, "Button", WS_CHILD | WS_VISIBLE | WS_TABSTOP
| BS_LEFTTEXT | BS_PUSHBUTTON, 191, 209, 56, 13
END
--------------------------------------------------

The C Code........................

LRESULT CALLBACK EditFieldProc(HWND hWnd,
UINT uMessage,
WPARAM wParam,
LPARAM lParam);

static WNDPROC oldproc;
static HWND hWndInfo;

HINSTANCE hInstance;
char szAppName[30];

BOOL CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInst,
HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,
int nCmdShow)
{
MSG msg;
HWND hWndMain;

WNDCLASS wndclass;
hInstance = hInst;
lstrcpy(szAppName, "cmsback");

if(NULL == (hWndMain = CreateDialog(hInstance,
MAKEINTRESOURCE(cm0back),
NULL,
MainWndProc)))
{
MessageBox(NULL, "Unable to display main dialog", "System Error",
MB_OK);
return FALSE;
}

ShowWindow(hWndMain, nCmdShow);
UpdateWindow(hWndMain);

while(GetMessage(&msg, NULL, 0, 0))
if(!IsDialogMessage(hWndMain, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

BOOL CALLBACK MainWndProc(HWND hWnd,
UINT
uMessage,
WPARAM wParam,
LPARAM lParam)
{
WORD CtlId;
WORD Notify;
HWND CtlWnd;

switch(uMessage)
{
case WM_INITDIALOG :
{
HWND hWndEdit;

hWndEdit = GetDlgItem(hWnd, IDC_EDIT);
hWndInfo = GetDlgItem(hWnd, IDC_EDIT2);

/* Subclass the control. */
oldproc = (WNDPROC)SetWindowLong(hWndEdit,
GWL_WNDPROC,

(LONG)EditFieldProc);
}
return TRUE;

case WM_COMMAND :
#ifdef WIN32
CtlId = LOWORD(wParam);
Notify = HIWORD(wParam);
CtlWnd = (HWND)lParam;
#else
CtlId = wParam;
Notify = HIWORD(lParam);
CtlWnd = (HWND)LOWORD(lParam);
#endif
if(!CtlWnd)
{ // Process Menu Commands
switch(CtlId) // Determine which Menu ID
{
}
}
else
{
switch(CtlId)
{
case IDCANCEL :
{
PostMessage(hWnd, WM_CLOSE, 0, 0);
}
break;
}
}
break;

case WM_CLOSE :

DestroyWindow(hWnd);
return TRUE;

case WM_DESTROY :

PostQuitMessage(0);
break;

default :
return FALSE;
}
return FALSE;
}

LRESULT CALLBACK EditFieldProc(HWND hWnd, UINT uMessage, WPARAM wParam,
LPARAM lParam)
{
switch (uMessage)
{
case WM_KEYDOWN:
{
if (wParam == VK_RIGHT)
{
WORD StartPos, EndPos;
LONG CursorPos, Pos;
POINT CaretPos;
char Buffer[250];

/* Get the Caret Position. */
GetCaretPos(&CaretPos);

/* Get the Index of the Caret. */
CursorPos = SendMessage(hWnd,
EM_CHARFROMPOS,
0,
MAKELPARAM(CaretPos.x, CaretPos.y));

/* Get the Current Selection. */
Pos = SendMessage(hWnd, EM_GETSEL, 0, 0);

/* Extract the Start and End Positions. */
StartPos = LOWORD(Pos);
EndPos = HIWORD(Pos);

/* Construct the Info. */
wsprintf(Buffer,
"StartPos = <%d>\r\n"
"EndPos = <%d>\r\n"
"CharfromPos = <%d>\r\n",
StartPos,
EndPos,
CursorPos);

/* Display the Info. */
SetWindowText(hWndInfo, Buffer);
}
}
break;

}

return CallWindowProc(oldproc, hWnd, uMessage, wParam, lParam);
}

-------------------------------------------------


John Carson

unread,
Jul 5, 2005, 6:02:19 AM7/5/05
to
"Leslie Milburn" <CD...@NOSPAM.bigpond.com> wrote in message
news:uikTJ0Rg...@tk2msftngp13.phx.gbl

>
> I knocked together a quick and nasty, code is below:
>
> Test Results:
> CharFromPos returns wrong result on Win98SE (4.10.2222A) and
> WinMe (version 4.90.3000).
> It returns the correct value on WinXP - SP1A

I don't have Win98SE installed, but I did run your code on WinME (version
4.90.3000, just like you report) and I get incrementation by 1 for every
character as I press the right arrow key. Further, the three measures of
position in your second edit field always show the same value. I have also
tested other punctuation and it works fine. I am about out of ideas
regarding how to reproduce the problem. Perhaps your version of WinME
doesn't have the latest updates, notwithstanding that the version number is
the same as mine.

> LRESULT CALLBACK EditFieldProc(HWND hWnd, UINT uMessage, WPARAM
> wParam, LPARAM lParam)
> {
> switch (uMessage)
> {
> case WM_KEYDOWN:
> {
> if (wParam == VK_RIGHT)
> {
> WORD StartPos, EndPos;
> LONG CursorPos, Pos;
> POINT CaretPos;
> char Buffer[250];
>
> /* Get the Caret Position. */
> GetCaretPos(&CaretPos);
>
> /* Get the Index of the Caret. */
> CursorPos = SendMessage(hWnd,
> EM_CHARFROMPOS,
> 0,
> MAKELPARAM(CaretPos.x,
> CaretPos.y));

The character index is given by the LOWORD of the return value from
SendMessage, but this isn't making a difference in this case.

>
> /* Get the Current Selection. */
> Pos = SendMessage(hWnd, EM_GETSEL, 0, 0);
>
> /* Extract the Start and End Positions. */
> StartPos = LOWORD(Pos);
> EndPos = HIWORD(Pos);
>
> /* Construct the Info. */
> wsprintf(Buffer,
> "StartPos = <%d>\r\n"
> "EndPos = <%d>\r\n"
> "CharfromPos = <%d>\r\n",
> StartPos,
> EndPos,
> CursorPos);
>
> /* Display the Info. */
> SetWindowText(hWndInfo, Buffer);
> }
> }
> break;
>
> }
>
> return CallWindowProc(oldproc, hWnd, uMessage, wParam, lParam);
> }


--
John Carson


John Carson

unread,
Jul 5, 2005, 8:38:59 AM7/5/05
to
OK. I can now reproduce the problem on WinME. I normally have large fonts
selected (120 DPI) rather than the default small fonts (96 DPI). I changed
to small fonts and now have the problems that you complained about. Note
that I get the same problem with the letter 'l', so it does not appear to be
an issue of punctuation; it appears to be just a matter of how wide the
character is.

Windows XP appears to work flawlessly in all cases. WinME (and I presume
Win98SE) appear to be inaccurate either in positioning the caret relative to
characters or in measuring the position of the caret relative to charcters.
There seem to be only 1-3 pixels in it. You can play around replacing

MAKELPARAM(CaretPos.x, CaretPos.y)

with

MAKELPARAM(CaretPos.x-n, CaretPos.y)

for various n. No n value appears to work correctly for every case.

It is not obvious how one might work around this. What are you using it for?

--
John Carson


Leslie Milburn

unread,
Jul 5, 2005, 9:15:16 AM7/5/05
to
Hi John,

"John Carson" <jcarson_n...@netspace.net.au> wrote in message

> I don't have Win98SE installed, but I did run your code on WinME (version


> 4.90.3000, just like you report) and I get incrementation by 1 for every
> character as I press the right arrow key. Further, the three measures of
> position in your second edit field always show the same value.

Thanks for testing.

Assuming you just hit the right arrow key (without holding shift) they
should all display the same value. Sometimes the CharfromPos value goes out
of sync by 1 depending upon the content of the edit box.


> tested other punctuation and it works fine. I am about out of ideas
> regarding how to reproduce the problem. Perhaps your version of WinME
> doesn't have the latest updates, notwithstanding that the version number
is
> the same as mine.

I will keep testing but I have started to think about alternatives as I need
to support older vesion of Windows for the minute.

Leslie.


Leslie Milburn

unread,
Jul 5, 2005, 9:33:07 AM7/5/05
to
Hi John,

"John Carson" <jcarson_n...@netspace.net.au> wrote in message

news:ego0P7Vg...@TK2MSFTNGP15.phx.gbl...


> OK. I can now reproduce the problem on WinME. I normally have large fonts
> selected (120 DPI) rather than the default small fonts (96 DPI). I changed
> to small fonts and now have the problems that you complained about. Note
> that I get the same problem with the letter 'l', so it does not appear to
be
> an issue of punctuation; it appears to be just a matter of how wide the
> character is.

Thats great news, glad to see I am not going mad.

> Windows XP appears to work flawlessly in all cases. WinME (and I presume
> Win98SE) appear to be inaccurate either in positioning the caret relative
to
> characters or in measuring the position of the caret relative to
charcters.
> There seem to be only 1-3 pixels in it. You can play around replacing
>
> MAKELPARAM(CaretPos.x, CaretPos.y)
>
> with
>
> MAKELPARAM(CaretPos.x-n, CaretPos.y)
>
> for various n. No n value appears to work correctly for every case.
>
> It is not obvious how one might work around this. What are you using it
for?

Well I really needed to know exactly where the caret is in relation to the
data entered or alternatively I needed to know at any point in time the
exact offset of the anchor position when selecting text. It would have been
useful if EM_GETSEL returned the selection range in the direction the User
has selected (left to right or right to left) rather than always the
smallest offset first.

Given my test results on Win9x, I decided not to fully trust the value from
EM_CHARFROMPOS, but rather use it as a direction flag in conjunction with
the Start and End Pos. I have managed to come up with an algorithm that is
working quite nicely but it has made the code more complex, oh well you
can't have everything.

Anyway, at least its on record for others because I googled and got nothing
on this specific issue, surprising really. Mind you its the first time in 15
years of windows programming I have needed it myself.

Thanks for your help.
Leslie.


John Carson

unread,
Jul 5, 2005, 11:04:54 AM7/5/05
to
"Leslie Milburn" <CD...@NOSPAM.bigpond.com> wrote in message
news:%23qqDVYW...@TK2MSFTNGP14.phx.gbl

> "John Carson" <jcarson_n...@netspace.net.au> wrote in message
> news:ego0P7Vg...@TK2MSFTNGP15.phx.gbl...
>> It is not obvious how one might work around this. What are you using
>> it for?
>
> Well I really needed to know exactly where the caret is in relation
> to the data entered or alternatively I needed to know at any point in
> time the exact offset of the anchor position when selecting text. It
> would have been useful if EM_GETSEL returned the selection range in
> the direction the User has selected (left to right or right to left)
> rather than always the smallest offset first.
>
> Given my test results on Win9x, I decided not to fully trust the
> value from EM_CHARFROMPOS, but rather use it as a direction flag in
> conjunction with the Start and End Pos. I have managed to come up
> with an algorithm that is working quite nicely but it has made the
> code more complex, oh well you can't have everything.

For what it is worth, some testing suggests that the reverse message
EM_POSFROMCHAR is accurate. Accordingly, one workaround (subject to further
testing) is as follows:

A. Find char index using EM_CHARFROMPOS.

B. Find caret pos using EM_POSFROMCHAR and char index calculated in A.

C. If caret pos in B. does not agree with starting caret pos, then char pos
is more than the true value, so reduce char pos by 1 (to be extra sure, you
can keep adjusting char pos until caret pos computed using EM_POSFROMCHAR
agrees with start value, though it would be prudent to place a bound on the
number of iterations allowed for this effort).

> Anyway, at least its on record for others because I googled and got
> nothing on this specific issue, surprising really. Mind you its the
> first time in 15 years of windows programming I have needed it myself.

Yes. I have found before that bugs can remain undetected for a very long
time in little used areas of Windows programming.


--
John Carson

Leslie Milburn

unread,
Jul 6, 2005, 9:39:21 AM7/6/05
to

"John Carson" <jcarson_n...@netspace.net.au> wrote in message
>
> For what it is worth, some testing suggests that the reverse message
> EM_POSFROMCHAR is accurate. Accordingly, one workaround (subject to
further
> testing) is as follows:

Thanks John, I'll keep this fact in mind.

Leslie.


0 new messages