C++/VB - New essay: Character function table generator

Asked By Joseph M. Newcomer
14-Jul-08 04:06 AM
A couple weeks ago I posted a comparison of how functions such as islower, CharLower, etc.
work between the C library and the raw API.  I had planned to generalize the rather simple
little console program I had written to accept locales, but decided that was truly ugly.

So I decided to use HTMLView, and chose as my starting point the HTMLEditorView example
from the MSDN.  I modified it to produce the table using a variety of locales.

The only problem was that the code was an embarrassment.  Note the code I wrote, but the
basic HTMLEditorView code, which is so poorly written that I would give it a failing grade
if it had been handed in as a semester project.  It violates pretty much every criterion
that exists for good modularization, scattering random code everywhere; the view knows the
name of the variable in the mainframe that holds the menu bar, and the absolute offset
into the menu bar where a menu item is found.  Give me a break!  This code was so abysmal
that I would not release anything I wrote which included this code, because the code
teaches directly AGAINST best practice.  So I spent the last couple weeks rewriting it (an
hour or two a day, fit in among my other projects, such as those that generate revenue).

It has a wonderful collection of anti-patterns illustrating worst-practice scenarios.

I am not totally happy with the result, which is not as good as I might have done from
scratch, but it is now at least acceptable in terms of modularization and interfaces.

A piece of code this bad should be an embarrassment to Microsoft as well.

The program, and my comments on the poor practices, can be found on

http://www.flounder.com/charfunc.htm
joe
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
HTMLEditorView
(1)
HTMLEditView
(1)
DLLScreenCrap
(1)
HTMLView
(1)
CallWIndowProc
(1)
DocumentRequests
(1)
CDocument
(1)
CharLower
(1)
  Joseph M. Newcomer replied...
14-Jul-08 03:52 PM
Two bugs were reported.  One is a syntax error that VS2003 should never have left through,
but it was trivial.

The other was that it crashes when reading certain files, and the correspondent sent me
the files that cause the crash.

I found that in one case I got the same crash, which was caused when the address of the
the "old window function" had an address of the form 0xFFFFnnnn (I forget what nnnn was)
but it is clear that this is a totally bogus address.  Interestingly enough, if I had ever
read one file successfully, it did *not* crash, but merely failed to display anything. The
original HTMLEditView example did not crash, but merely failed to display anything.

I determined that by removing the <!DOCTYPE ...> line at the front of the file, these
problems went away both in the original Microsoft code (which now displayed things) and in
my code (which either crashed or refused to display anything).  This suggests that there
is a deep problem in the HTML control itself, rather than being an artifact of my rewrite.
joe


Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
  Ashot Geodakov replied...
14-Jul-08 11:15 PM
There's a fine print in the page of that sample that says, "This sample code
is provided to illustrate a concept and should not be used in applications
or Web sites, as it may not illustrate the safest coding practices.
Microsoft assumes no liability for incidental or consequential damages
should the sample code be used for purposes other than as intended."
  Joseph M. Newcomer replied...
15-Jul-08 12:45 AM
That's a clever way of saying "The code enclosed in this example is crap, cobbled together
by amateur programmers and hacked until it compiles and more-or-less works, except in
those cases we decided weren't worth worrying about, or didn't think about testing, where
it will fall flat on its face.  It is used to show an idea without the slightest
consideration for good design, your training or learning experience.  It should not be
trusted further than you can throw an antique mainframe.  Under no circumstances should
this crap piece of code be used for an example of anything realistic."

If that's what it is saying, what good is it?

So why don't they write good code in the first place?  It is poor teaching methodology to
show code this poor and let people use it as a model.  Remember that people who don't know
best practice will think that code like this *is* best practice "because it was written by
Microsoft".

I'm a teacher, and I insist on good models at all levels.  There is no excuse for writing
code this poor and then try to justify it with a weasly disclaimer.

Unfortunately, I've had clients who have taken examples like this and used them as models
and created unmaintainable messes, and I get to pick up the pieces.  In one case, a very
expensive project died because the programmer used the multithreaded socket code as a
model of how to write a program, and they couldn't afford my price to rewrite it from
scratch (which was the only way to salvage the resulting mess).  There is fundamental
responsibility here to do the best possible job.  To do otherwise is to fail to meet
pedagogical responsibilities.
joe

On Mon, 14 Jul 2008 20:15:57 -0700, "Ashot Geodakov" <a_geodakov@nospam.hotmail.com>

Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
  Hans-J. Ude replied...
15-Jul-08 02:36 AM
I tried to find the article so I searched google and found the same
statement in another article:

http://msdn.microsoft.com/en-us/library/7a51wcfx.aspx

I haven't looked at that one but maybe they should rename the project
into "DLLScreenCrap Sample".

Hans
  Joseph M. Newcomer replied...
15-Jul-08 11:00 AM
Note that "safe" code and "good" code are not always the same.  The code may be perfectly
safe, but nonetheless be complete crap relative to how we try to teach good programming
style.  Or code can be quite elegant, except for that nasty little buffer overrun
situation.

The problem is that someone who is approaching a task for the first time, and who has not
had much instruction in good programming methodology, looks at one of these pieces of code
and says "Aha!  I see now how to access the main frame from a view!" or "Now I see how the
mainframe can call methods of a view!" which is the wrong answer.  The correct issue is
how to achieve clean interfaces and abstraction.  So when they get these examples that
connect every class to every other class and everything includes everything else, they
don't have the judgment to realize that what they are being show profoundly poor examples
of programming.

I had the same experience when I learned Windows programming from Petzold's books.  After
I mastered the parts of the API, I kept saying "There's something wrong here; I haven't
written code this bad in 20 years.  Why is it that Windows seems like it is a retrograde
technology?"  I finally figured out what was wrong with Petzold's examples: they were
hacked until they worked.  There were no module boundaries, no concept of interface, no
concept of abstraction.   For example, code at some low-level would reach up, grab the
main menu, index into it a fixed distance, and enable/disable an item.  Of course, the
correct solution was to ignore all of this, and create a WM_INITMENUPOPUP handler. Petzold
never mentioned the windowsx.h macros, which make raw Win32 programming so much easier.
And so on.  The MSDN example I'm critiqueing here is an example of this same approach:
hack the include structure until it compiles, and design be damned.  Modularity?
Abstraction?  What do *those* matter?  All we need to do is hack something together and
hold it out as an example of how to program.

This is profoundly irresponsible.
joe


Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
  Geoff replied...
15-Jul-08 12:27 PM
Disclaimers (to satisfy lawyers and protect corporate interests) aside, a
sample program should be refined enough to represent a best practices
example of good code, both from a structural and a security perspective,
precisely because it WILL be used as a basis for learning programming or
for building application code. This is Joe's point and I have to agree with
it. Sample code should simply be the best, most correct way to program the
example, not just thrown together.

The problem with Joe's message is his ego gets in the way. He's so enamored
of his own programming skill and style that he offends the reader with his
scathing wit and criticism of other people's work. Net result, all pain, no
gain. You have to concentrate so hard on ignoring the condescension that it
becomes difficult to read the message. Maybe he's more entertaining in
person, I don't know. The tone of his writing leaves a lot to be desired.

One example of BAD practice in Joe's critique is the "clever" (his word)
use of comment delimiting of the CDocument class DocumentRequests
enumeration. I find that particularly silly and embedding them into the
comments makes it harder, not easier to read. One should never be clever,
one should be direct and to the point. Following that commenting style
leads to tedious repetition of copy-pasted comments as he illustrates in
his example. It might look fine in the IDE if you choose the right syntax
highlighting, but it looks ugly in black and blue. Incidentally, the
example enumeration cited thankfully does not appear in his CharFunc
project. One is left guessing whether he is holding this up as a bad
example or a clever one. A case of do as I say, not as I do?
  James Juno replied...
15-Jul-08 12:44 PM
I haven't seen Joe's code comments.  But per his tone in this newsgroup,
he doesn't know me and I don't care if he stomps me down to the
eye-level of a termite.  Who cares?  His skills are proven and his
posts, goldmines of information.  He's prolific and knowledgeable.  Why
take anything personally from an internet poster if they don't know you
personally?  Besides, his mugshot at this website impresses me as
someone rife with sarcasm (sorry, Joe, if I'm misreading you).  When he
rails on a poster here, I imagine a sarcastic smile on his face as the
smoke rises from his keyboard. ;)

I want him to understand that his time spent here is much appreciated.
It's free software consulting!

-JJ
  Ashot Geodakov replied...
15-Jul-08 04:44 PM
I read your essay and agreed with it completely. However, I think you are
wasting your breath. It's clear that you are a better programmer than a
Microsoft's intern. They don't have 40 years of experience like you do.
They'll get there eventually. :)

I usually use their samples to find that particular piece of code, and throw
away the rest of the garbage. That's all their samples are for. The
disclaimer is absolutely correct about this.
  Joseph M. Newcomer replied...
15-Jul-08 11:57 PM
And that's why the senior people at Microsoft should be spending time correcting this code
before it escapes.  The issue is not an incompetent intern; the issue is that code written
by an incompetent intern is held out as an example of how to build a system.  This is a
management failure.  People don't become competent until you train them.  There was no
attempt at training here, and no responsibility was taken for quality of code.  THAT's my
objection!

You obviously have the taste to recognize crap when you see it.  Far, far too many people
do not, and therefore they assume that the code they are seeing represents the accepted
technique for accomplishing the goals.  I find code like this in all kinds of programs I
get, and when I challenge the code, I'm told "But we got that directly from a Microsoft
example!" which is said in the same tone of voice as "But that is what is Writ In The Holy
Scrolls!"  I've had to demonstrate some of the failure modes before I was authorized to
fix the code!
joe

On Tue, 15 Jul 2008 13:44:41 -0700, "Ashot Geodakov" <a_geodakov@nospam.hotmail.com>

Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
  Giovanni Dicanio replied...
16-Jul-08 06:04 PM
I had the opportunity to meet Joe in person this year, and I sincerely say
that Joe is a *very nice* person!
(He is also a good artist - I put safely in a place of mine a precious
circular token he gave me, on which token he drew a flounder fish ;)

Well, his knowledge of MFC is *encyclopedic*: he is a living encyclopedia.
And you can speak with him also about different stuff than MFC, e.g. NUMA
and advanced hardware architectures, or German stuff, etc.

It's a pleasure to listen to him in person.
(Well... and he also can speak slowly when the listener is a
non-English-native person ;)

Even if you may not agree sometimes on his tone on some posts of him here,
he certainly knows a lot, and he makes his knowledge and advices available
for everyone of us here, for *free* (and his web site is a goldmine of
information - when I need something for MFC I usually go there to search,
too).

Giovanni
Create New Account
help
int i; UINT ret; pt.x = (short)LOWORD(lParam); pt.y = (short)HIWORD(lParam); ret = CallWindowProc(ctp-> wpOldProc, hwnd, WM_NCHITTEST, wParam, lParam); / / If the mouse is in the caption, then check not / / paint our window caption. . . SetWindowLong(hwnd, GWL_STYLE, dwStyle & ~WS_VISIBLE); / / Do the default thing. . ret = CallWindowProc(ctp-> wpOldProc, hwnd, msg, wParam, lParam); / / Restore the original style SetWindowLong(hwnd, GWL_STYLE, dwStyle); / / Paint ctp-> buttons[i].fPressed = TRUE; / / ctp-> fMouseDown = TRUE; / / / / SetCapture(hwnd); / / / / RedrawNC(hwnd); / / / / return 0; / / } / / } / / } / / / / return CallWindowProc(ctp-> wpOldProc, hwnd, msg, wParam, lParam); / / } / / / / / / / / / / Left-button UP. Coords are CLIENT relative / / / / / / static LRESULT y)); / / } / / / / ctp-> buttons[ctp-> iActiveButton].fPressed = FALSE; / / ctp-> fMouseDown = FALSE; / / / / RedrawNC(hwnd); / / / / return 0; / / } / / / / return CallWindowProc(ctp-> wpOldProc, hwnd, WM_LBUTTONUP, wParam, lParam); / / } / / / / static LRESULT Caption_MouseMove(CustomCaption *ctp, HWND hwnd, WPARAM wParam buttons[ctp-> iActiveButton].fPressed) / / { / / ctp-> buttons[ctp-> iActiveButton].fPressed ^ = 1; / / RedrawNC(hwnd); / / } / / / / return 0; / / } / / / / return CallWindowProc(ctp-> wpOldProc, hwnd, WM_MOUSEMOVE, wParam, lParam); / / } / / Replacement window procedure static LRESULT CALLBACK NewWndProc(HWND hwnd lParam); case WM_PAINT: return Caption_NCPaint(ctp, hwnd, (HRGN)wParam); } / / call the old window procedure return CallWindowProc(oldproc, hwnd, msg, wParam, lParam); } / / / / Insert a button into specified window's titlebar / / BOOL WINAPI
is not sent / / although TTN_POP is sent if(nmhdr-> code = = TTN_GETDISPINFO) { nmtt = (NMTTDISPINFO *)nmhdr; curIndex = CallWindowProc(defProc, hwnd, LB_GETCURSEL, (WPARAM)0, (LPARAM)0); CallWindowProc(defProc, hwnd, LB_GETTEXT, (WPARAM) curIndex, (LPARAM)selText); strcpy(nmtt-> szText, selText); SetWindowPos(hwndTip, HWND_TOPMOST, 0 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); return 0; } } break; } return CallWindowProc(defProc, hwnd, message, wParam, lParam); } LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM Thanks, - -Anurag. Win32 UI Discussions CreateWindowExA (1) PostQuitMessage (1) RegisterClassEx (1) GetStockObject (1) CreateWindowEx (1) CallWindowProc (1) This link may give you clues: http: / / www.codeguru.com / cpp / controls / combobox / tooltips
Discussions Visual Studio (1) MyControlCtrlNewWndProc (1) MyControlOldWndProc (1) MyControl.Create (1) TrappeOldWndProc (1) MyControlCreate (1) CallWindowProc (1) SetWindowLong (1) Add a WM_SIZE message handler in your derived-from-CWnd class. Use MyControlCtrlNewWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) { switch(Message) { case WM_SIZE : LRESULT result = CallWindowProc( (WNDPROC)TrappeOldWndProc, hWnd, NULL, wParam, lParam); / / Do realign stuff. . . return result; break; } / / Call default function return CallWindowProc((WNDPROC)MyControlOldWndProc, hWnd, Message, wParam, lParam); } What are you thinking of this solution ? On Thu
call Clipboard.GetText and paste only the allowable characters if you want. Don't call CallWindowProc() so the message is discarded. Also, you can suppress Ctrl+V by setting KeyAscii = 0 Long, ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long Public Declare Function CallWindowProc Lib "user32" Alias _ ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As As Long Select Case Msg Case WM_PASTE: TextBoxWindowProc = 0 ' Discard the message Case Else TextBoxWindowProc = CallWindowProc(oldWindowProc, hWnd, Msg, _ wParam, lParam) End Select End Function If you have supressed the
As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long WindowProc = CallWindowProc(PrevProc, hwnd, uMsg, wParam, lParam) . . . . . . . . . End Function But dont't work. . . Thanx . . . Sorry . . . my english Discussions WPF (1) AccessibleObjectFromWindow (1) AccessibleObjectFromPoint (1) CallWindowProcA (1) SetWindowLongA (1) AllAPI (1) WindowFromPoint (1) CallWindowProc (1) hi Rafael, I have two suggestions. For one, it looks like you are setting