Secrets of the RichInk control - revealed! (mostly, anyway)

M

Mark Erikson

For a while now, I've been interested in the capabilities of the
RichInk control. The lack of a rich edit control for the PocketPC has
been commented on frequently in this group, and as Pocket Word shows,
it does have some capabilities. Unfortunately, like many other
PocketPC-related things, it's rather poorly documented.

I recently saw a mention of some undocumented messages being used (a
usenet-wide search for richink and em_getstyle will turn up the
source). I began searching for any other references to EM_GETSTYLE and
EM_SETSTYLE, and eventually found the SendMessage parameters in a
project called CeLib over at codeproject.com. That, combined with some
time spent using the CE Remote Spy on Pocket Word, was enough to get me
going.

Over the last few days, I've put together lots of trial-and-error
tests, large quantities of memory dumps, and a lot of other testing,
and I'm extremely pleased to announce that I can now duplicate most of
the formatting that Pocket Word does, including: bold / italic /
underline / strikethrough / highlighting, colored fonts, changing the
font, font sizing, and paragraph justification.

Having reached this point, I'd like to share my results with the rest
of the world, as well as hopefully get some assistance decoding some of
the last few sections.


So, here's what I've found:

The RichInk control has several undocumented messages. The ones I'm
focusing on are EM_GETSTYLE (WM_USER + 212) and EM_SETSTYLE (WM_USER +
213). For both messages, WPARAM is 0 and LPARAM is a pointer to a
stream of bytes. I'm assuming that somewhere in Microsoft's code
there's a definition that breaks those bytes into an actual structure,
but at this point I'm just dealing with it as a byte array.

The byte array is approximately 125 bytes long. At this point, I'm
just going to paste in my notes, since it'll be easier that way. Feel
free to skip to the bottom if you don't want to know the gory details.

Notes file begins:
4 bytes: unknown integer. changes between 5 if no selection and 1 if
selection length > 0
64 bytes: 32 Unicode characters for the font name
1 byte: Flag bit. Normally 0, 8 if monospaced font?
1 byte: unknown, normally blank
1 byte: Integer for font size
1 byte: unknown, normally blank
1 byte: Integer for text color. Uses the color table output in an RTF
file by the RichInk control
3 bytes: Unknown, normally blank
1 byte: some sort of a flag. Always 4 unless bold is turned on, in
which case it's 7
7 bytes: unknown, normally blank
1 byte: a bitmasked flag. appears that 0 is normal, 1 means
strikethrough, 2 means underlined, 4 means highlight, 8 means italic
1 byte: a flag. appears that 8 means bold is on, 4 means highlight
-- so... what do the other missing flags mean for these two bytes?
3 bytes: unknown, normally blank
1 byte: Controls the justification. 0 is normal, 2 is centered, 1 is
right.
6 bytes: unknown, normally blank
1 byte: unknown, always 115
1 byte: unknown, always 12
6 bytes: unknown, normally blank
2 bytes: counter of some sort (presumably a 4-byte integer). Resets at
the end of each row.
4 bytes: unknown, value usually changes with each row. Usually follows
the following pattern:
176 1 0 0
104 1 0 0
32 1 0 0
216 0 0 0
144 0 0 0
72 0 0 0
0 0 0 0
184 255 255 255
184 254 255 255
184 253 255 255
..
..
..

However, this is not true if, say, the entire file is blank lines, in
which case the whole thing stays at 176 1 0 1

4 bytes: unknown, normally blank
1 byte: unknown. Value has been seen as 72, 144, 86, 162, and 81.
Bears some relation to end of lines and style changes
3 bytes: unknown, normally blank
1 byte: Flag byte. Normally 255. If the selection overlaps formatting
regions, 251 means different background highlighting, 247 means
different italics, 253 if different underlining, 245 if different
italics and different underlining, 229 if the font
size/italics/bold/underline changes
- Bits: 2 for underlining, 4 for highlighting, 8 for italics, 16 for
font size change, 32 for font change
1 byte: Normally 127. More selection overlap info. If the overlap
contains bold, this is 119.
- Bits: 8 for bold
1 byte: 5 if all of the selection has the same format, 4 if the
selection covers different colors, 1 if the selection covers different
bolding



If anyone would like to experiment with this, I've zipped up my C# test
project, sample RTF files, and memory dump spreadsheets (CSV and
OpenOffice SXC) and uploaded it to
http://www.isquaredsoftware.com/index.php?file=RichInkTest.zip . It's
completely uncommented, but hopefully readable enough to show what's
going on.

I'd definitely appreciate hearing other people's thoughts and any
further investigation results. In particular, I can't yet duplicate
Pocket Word's ability to format a selection that overlaps two different
formats (ie, if half the selection is bold and half isn't, Pocket Word
can toggle the entire thing - right now nothing happens for me). I'd
love to know how to do that. Also, I'm not sure what most of the bytes
between 107 and 122 really do.

Hopefully, this'll help people actually start doing some useful things
with the RichInk control. Enjoy!

Mark Erikson
http://www.isquaredsoftware.com
Mark Erikson
http://www.isquaredsoftware.com
 
M

Mark Erikson

Hah... I had an epiphany a few minutes ago regarding my inability to
set the style for a selection that overlaps two formatting regions.
The last three bytes are reverse flags where the bits are set if that
type of formatting is the same throughout the selection, and UN-set if
that type of formatting is different. It finally occurred to me that
if I get the style and the bit that corresponds to the format I'm
setting is a zero, then all I have to do is change it to a one to tell
the control that all the selection has the same type of that format...
and it worked!

Lemme give an example here:

internal enum DifferenceByte3 : byte
{
Color = 1,
Bold = 4,
};

private void SetColor()
{
byte newColorIndex = 4; // red
byte[] bytes = GetSelectionStyle();
bytes[72] = newColorIndex;

//byte 123 is the last of three reverse byte flags
int differentColors = bytes[122] & (int)DifferenceByte3.Color;
if(differentColors == 0)
{
bytes[122] |= (byte)DifferenceByte3.Color;
}

SetSelectionStyle(bytes);
}

So... yeah, I think I can pretty much do anything I want with this
control now :) As I said, hopefully other people will find this
useful, especially since I haven't seen any of this documented anywhere
else.

Mark Erikson
http://www.isquaredsoftware.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top