123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699 |
- // c_applic.cpp
- // The "application" part of my program. This is concerned with
- // initial creation of windows and the capture of any command-line
- // or other options.
- //
- // Copyright (C)/©/¸ Codemist Ltd, 1995-2002
- /*
- * This code may be used and modified, and redistributed in binary
- * or source form, subject to the "CCL Public License", which should
- * accompany it. This license is a variant on the BSD license, and thus
- * permits use of code derived from this in either open and commercial
- * projects: but it does require that updates to this code be made
- * available back to the originators of the package.
- * Before merging other code in with this or linking this code
- * with other packages or libraries please check that the license terms
- * of the other material are compatible with those of this.
- */
- /* Signature: 59c7129b 10-Oct-2002 */
- #include "cwin.hpp"
- extern "C" {
- extern int Lstop(int a, int b);
- }
- //
- // Windows enters my code at WinMain, but with MFC I arrive via all sorts
- // of jolly initialisation code. To support old code I read the command
- // line that invoked me, and parse it into words which I store in argv[],
- // much as per the regular C startup process.
- //
-
- char programName[64];
- char *cwin_full_program_name;
- static int argc;
- static char **argv;
- static int set_up_argv()
- // This sets up argc and argv[] as expected for a regular C application.
- // It arranges that argv[0] is an unqualified name, forced into upper case.
- // Ie argv[0] does not have a path-name on the front of it or any ".EXE"
- // suffix after it.
- // I return a flag that indicates whether "--" was found among the arguments.
- // (and now I will return the same flag if "-f" was among the arguments)
- {
- int doubledashFound = 0;
- int i = 0, c, len = 0;
- char *w = GetCommandLine();
- // The string I obtained there may be in UniCode, but I will suppose that it
- // does not contain any funny characters. In particular I will demand
- // that this module is compiled with Unicode mapped onto ordinary 8-bit
- // chars.
- char *w1 = w, *argbuf;
- // I scan the command line once to assess its length. I treat any item
- // that STARTS with a double-quote mark as running on until the following
- // double quote (even if there are blanks in the way), and in that case I
- // remove the quotes before passing on to the user's program. Something
- // like this appears to be essential for dealing with Windows-95 with
- // its long filenames: it puts the first item on the command line (the name
- // of the program that is being executed) in double quotes in case it is long
- // and in case it has embedded whitespace, and unless I strip those quotes
- // later on bits of code crash. Note now the subtle distinction between
- // -W "yy"
- // and -W"yy"
- // where -W is some option that user code tries to interpret. In the first
- // case the quotes are gobbled up and removed here, in the second they
- // remain for the user to see. Note that
- // -W"yy is here"
- // returns three words, two of which have embedded quote marks. It is probably
- // impossible to guarantee to win all cases here!
- do
- { while ((c = *w++) == ' ' || c == '\t');// Blank at start of an item
- if (c == 0) break;
- i++; // Count of words
- if (c == '"') // items in double quotes?
- { c = *w++;
- while (c != 0 && c != '"') c = *w++, len++;
- if (c == '"') c = *w++;
- }
- else while (c != 0 && c != ' ' && c != '\t') c = *w++, len++;
- } while (c != 0);
- // Now I can allocate space for the argument vector and a copy of the data.
- // I grab a little more space than I am going to use as a matter of caution.
- argv = (char **)malloc((i+1)*sizeof(char *));
- argbuf = (char *)malloc(i+len);
- argc = 0;
- if (argv==NULL || argbuf==NULL) return 0;
- // Re-scan the command line copying characters into buffers
- w = w1;
- do
- { while ((c = *w++) == ' ' || c == '\t');
- if (c == 0) break;
- argv[argc++] = argbuf;
- if (c == '"') // I strip the quotes while I tokenise
- { c = *w++;
- while (c != 0 && c != '"') *argbuf++ = (char)c, c = *w++;
- if (c == '"') c = *w++;
- }
- else while (c != 0 && c != ' ' && c != '\t')
- *argbuf++ = (char)c, c = *w++;
- *argbuf++ = 0;
- if (argv[argc-1][0] == '-' &&
- (argv[argc-1][1] == '-' ||
- argv[argc-1][1] == 'f' ||
- argv[argc-1][1] == 'F')) doubledashFound = 1;
- } while (c != 0);
- // Put a NULL pointer at the end of argv[], just to be safe
- argv[argc] = NULL;
- // Now I want to trim argv[0] so that even if it started with a full
- // path or with an extension (eg. "\bin\csl.exe") it is passed on trimmed
- // down to just its root (eg. "csl" in the above case). This string will
- // be left in programName too.
- w = w1 = argv[0];
- cwin_full_program_name = NULL;
- while ((c = *w++) != 0)
- { if (c == '\\') w1 = w;
- // I take the view that if argv[0] contains a ":" character then it can be
- // presumed to be a fully rooted file name, including a drive specification.
- // In such cases I will use it when I want the full name of the executable
- // I am running. Well I will also require in that case that it should end
- // in a ".exe" suffix. This final test is certainly needed under Windows
- // NT 4.0 when one launches CSL from a command line but specifying
- // a drive to find it on. What I want is the text
- // "D:\xxxx.exe"
- else if (c == ':' && *w=='\\')
- { i = strlen(w)-4;
- if (i > 0 && w[i]=='.' &&
- tolower(w[i+1])=='e' &&
- tolower(w[i+2])=='x' &&
- tolower(w[i+3])=='e')
- cwin_full_program_name = argv[0];
- }
- }
- if (*w1 == 0) w1 = "CWIN"; // Final char of argv[0] was '\': use default
- w = programName;
- while ((c = *w1++) != 0 && c != '.') *w++ = (char)toupper(c);
- *w = 0;
- argv[0] = programName;
- if (cwin_full_program_name == NULL)
- // Now I would like to get a full path to the program name... The
- // SearchPath function looks first in the directory from which the
- // application was fetched, and provided that the ".exe" extension
- // I specify here is correct the file really ought to be located!
- { int nameLength = SearchPath(NULL, programName, ".EXE", 0, argbuf, &w);
- // There is one critically important case where "SearchPath" will fail here,
- // and that is when the program has been started from a debugger and the
- // real name of the program is just not available. In that case tough
- // luck, you will have to make resources available by some means NOT
- // dependent on the program name or the directory it lives in. Maybe in some
- // cases with DOS extenders the program will appear to have been loaded from
- // a directory distinct from the one that the obvious ".EXE" file lives in.
- // In those cases I had better hope that argv[0] gave me a completely
- // rooted file name.
- cwin_full_program_name = (char *)malloc(nameLength+1);
- if (cwin_full_program_name == NULL)
- cwin_full_program_name = "cwin.exe";
- else
- { if (SearchPath(NULL, programName, ".EXE",
- nameLength+1, cwin_full_program_name, &w) == 0)
- cwin_full_program_name = "cwin.exe";
- }
- }
- return doubledashFound;
- }
- CTheApp theApp;
- CString mainWindowClass;
- UINT clipboardformat;
- BOOL CTheApp::InitInstance()
- {
- // I find the explanations about m_nCmdShow and GetStartupInfo jolly
- // confusing! However the code as given here will be tested with CSL launched
- // from a command line with
- // start csl ...
- // start /min csl ...
- // start /max csl ...
- // and start csl -- logfile.log
- //
- // The last of these ought to start CSL minimised even if /min or
- // /max is given as well.
- //
- // Initial testing is on NT. Next I will need to try Windows 95. The
- // issue of win32s (on Windows 3.1x) will be gently ignored now.
- int nShow = m_nCmdShow;
- #ifdef __WATCOM_CPLUSPLUS__
- #if __WATCOM_CPLUSPLUS__ > 1060
- // Oh calamity. The following 3 lines seem necessary to make the initial
- // window behave properly, but when I inserted them I had reports that the
- // code would not link on a system with just the previous version of
- // Watcom C. While I investigate this I will try to disable this facility
- // unless I have version 11.0 installed, and maybe this will allow us to
- // keep moving forward.
- STARTUPINFO su;
- GetStartupInfo(&su);
- if (su.dwFlags & 1) nShow = su.wShowWindow;
- #endif
- #endif
- // I will grab information out of the registry as soon as the application
- // is started.
- SetRegistryKey("Codemist"); // Use registry rather than ".ini" file
- int left = GetProfileInt("MainWindow", "ScreenLeft", -1000000);
- int width = GetProfileInt("MainWindow", "ScreenWidth", -1000000);
- int top = GetProfileInt("MainWindow", "ScreenTop", -1000000);
- int height = GetProfileInt("MainWindow", "ScreenHeight", -1000000);
- int fsize = GetProfileInt("MainWindow", "FontSize", 0);
- int fweight= GetProfileInt("MainWindow", "FontWeight", 0);
- int linel = GetProfileInt("MainWindow", "LineLength", -1000000);
- CString fname(GetProfileString("MainWindow", "FontName", "Courier New"));
- int doubledashFound = set_up_argv();
- mainWindow = NULL;
- mainWindowClass = ::AfxRegisterWndClass(CS_DBLCLKS,
- LoadStandardCursor(IDC_ARROW),
- (HBRUSH)(COLOR_WINDOW+1),
- LoadIcon("CWIN"));
- /*
- * I introduce a private clipboard format here. It will be just like
- * simple text (to start with) except that certain control characters
- * will be used to separate off the places that prompt strings occus. This
- * can be exploited in PASTE operations so that prompts issued by this
- * system do not get re-entered when previous input is copies and pasted.
- */
- clipboardformat = RegisterClipboardFormat("Codemist Text");
- /*
- * clipboardformat is left zero if anything went wrong, so in such cases
- * I must not attempt to use it.
- */
- if ((mainWindow = new CMainWindow()) == NULL) return FALSE;
- m_pMainWnd = mainWindow;
- CClientDC dc(mainWindow);
- mainWindow->windowFonts.InitFont(&dc, (LPCTSTR)fname, fweight, fsize);
- // If there was "--" given as an argument I start off with the window
- // minimized. This is because I then expect an application to use this
- // flag to enable output to a file rather than to the screen.
- WINDOWPLACEMENT wp;
- mainWindow->GetWindowPlacement(&wp);
- // Here I will see where the window is about to be placed, and adjust its
- // width (and maybe its left hand side) in an attempt to make the client
- // are just big enough for 80 columns. I am a bit unhappy about the
- // calculation here using system metrics, and have added in one more
- // CXBORDER as a fudge to bring experimental reality on MY system into
- // line. Hope it is OK on other systems and configurations too.
- // The "+5" on the end is an attempt to leave room for a caret to the right
- // of the last sensible character on a line...
- if (left!=-1000000 && width!=-1000000 &&
- top!=-1000000 && height!=-1000000 &&
- linel!=-1000000)
- { mainWindow->SetWindowPos(NULL, left, top, width, height,
- SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOZORDER);
- cwin_linelength = linel;
- }
- else
- { int screenWidth = GetSystemMetrics(SM_CXSCREEN);
- RECT *wr = &wp.rcNormalPosition;
- int left = wr->left;
- int cwidth = 80*mainWindow->windowFonts.HCourier.across['X'] +
- 3*GetSystemMetrics(SM_CXBORDER) +
- 2*GetSystemMetrics(SM_CXFRAME) +
- GetSystemMetrics(SM_CXVSCROLL) + 5;
- // Try to get the whole window onto the screen.
- if (left + cwidth > screenWidth)
- { left = screenWidth - cwidth;
- if (left < 0) left = 0;
- }
- mainWindow->SetWindowPos(NULL,
- left, wr->top,
- cwidth, (wr->bottom - wr->top),
- SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOZORDER);
- cwin_linelength = 80;
- WriteProfileInt("MainWindow", "ScreenLeft", left);
- WriteProfileInt("MainWindow", "ScreenWidth", cwidth);
- WriteProfileInt("MainWindow", "ScreenTop", wr->top);
- WriteProfileInt("MainWindow", "ScreenHeight", wr->bottom-wr->top);
- WriteProfileInt("MainWindow", "LineLength", cwin_linelength);
- }
- mainWindow->ShowWindow(doubledashFound ? SW_SHOWMINNOACTIVE : nShow);
- mainWindow->UpdateWindow();
- return TRUE;
- }
- class CenteredDialogBox : public CDialog
- {
- public:
- void CreateAndDisplay(HGLOBAL h);
- };
- void CenteredDialogBox::CreateAndDisplay(HGLOBAL h)
- {
- InitModalIndirect(h);
- DoModal();
- }
- // In-store dialog-box templates need some of their strings in 16-bit
- // Unicode form. This code stretches out a simple string. It also round
- // the length of the data written to a multiple of 8 bytes, which seems to
- // be an unpublished (?) requirement for the dialog box template structures.
- static LPWORD WidenString(LPWORD p, char *q)
- {
- int n = 0;
- while ((*p++ = *q++) != 0) n++;
- if (n & 1) *p++ = 0;
- return p;
- }
- // The following function fills in details about one control within a
- // dialog box template.
- static LPWORD PlantDlgItem(LPWORD p3, int x, int y, int cx, int cy,
- int id, DWORD style, int type, char *text)
- {
- LPDLGITEMTEMPLATE p2 = (LPDLGITEMTEMPLATE)p3;
- p2->x = (short)x; p2->y = (short)y; p2->cx = (short)cx, p2->cy = (short)cy;
- p2->id = (WORD)id;
- p2->style = style;
- p3 = (LPWORD)(p2 + 1);
- *p3++ = 0xffff;
- *p3++ = (WORD)type;
- int n = 1;
- while ((*p3++ = *text++) != 0) n++;
- if (n & 1) *p3++ = 0;
- *p3++ = 0;
- return p3;
- }
- // I make the "ABOUT" dialog box from an in-memory template, and
- // this makes it possible to make the text that is included depend on
- // strings that the user can potentially reconfigure. The strings put here
- // are somewhat generic. Note also that if a user hits the HELP menu
- // during system start-up before the regular user code at main() has been
- // entered than the messages shown here will appear, even though later on
- // the user's properly selected messages will be the ones that show up. I
- // think that on balance I almost count that to be a positive advantage! It
- // means that the "CWIN" information and credits are at least just about
- // available to all users!
- char about_box_title[32] = "About CWIN";
- char about_box_description[32] = "The CWIN window driver";
- char about_box_rights_1[32] = "Copyright Codemist Ltd.";
- char about_box_rights_2[32] = "A C Norman 1994-6";
- void CTheApp::OnAbout()
- {
- HGLOBAL h = GlobalAlloc(GMEM_ZEROINIT, 1024);
- if (!h) return;
- LPDLGTEMPLATE p1 = (LPDLGTEMPLATE)GlobalLock(h);
- WORD *p0 = (WORD *)p1;
- p1->style = WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME;
- p1->cdit = 5;
- p1->cx = 167; p1->cy = 86;
- LONG units = ::GetDialogBaseUnits();
- int dlgx = units & 0xffff, dlgy = (units >> 16) & 0xffff;
- p1->x = (short)((4*mainWindow->clientWidth)/dlgx - p1->cx)/2;
- p1->y = (short)((8*mainWindow->clientHeight)/dlgy - p1->cy)/2;
- LPWORD p2 = (LPWORD)(p1 + 1);
- *p2++ = 0; // no menu
- *p2++ = 0; // a predefined box class
- p2 = WidenString(p2, about_box_title);
- p2 = PlantDlgItem(p2, 0, 4, 167, 8, -1,
- WS_CHILD | WS_VISIBLE | SS_CENTER, 0x0082, about_box_description);
- p2 = PlantDlgItem(p2, 0, 45, 167, 8, -1,
- WS_CHILD | WS_VISIBLE | SS_CENTER, 0x0082, about_box_rights_1);
- p2 = PlantDlgItem(p2, 0, 53, 167, 8, -1,
- WS_CHILD | WS_VISIBLE | SS_CENTER, 0x0082, about_box_rights_2);
- p2 = PlantDlgItem(p2, 74, 22, 0, 0, -1,
- WS_CHILD | WS_VISIBLE | SS_ICON, 0x0082, "CWIN");
- p2 = PlantDlgItem(p2, 66, 65, 32, 14, IDOK,
- WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 0x0080, "OK");
- GlobalUnlock(h);
- CenteredDialogBox dlg;
- dlg.CreateAndDisplay(h);
- GlobalFree(h);
- }
- // When I want to pop up a box that says "Press OK to exit" I make the
- // structure that defines the dialog box here in memory rather than putting
- // it into my resource file. The reason for taking this step is that it
- // allows to to keep the resource file as spartan and simple as possible.
- // It also provides a place for me to ensure that the dialog box is central
- // in the area that my window occupies.
- static void DoFinishBox()
- {
- HGLOBAL h = GlobalAlloc(GMEM_ZEROINIT, 1024);
- if (!h) return;
- LPDLGTEMPLATE p1 = (LPDLGTEMPLATE)GlobalLock(h);
- WORD *p0 = (WORD *)p1; //DEBUG
- p1->style = WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME;
- p1->cdit = 2;
- p1->cx = 95; p1->cy = 52;
- // I want the box to appear in the centre of where my window is. This
- // causes extra fun because of the special coordinate system used with
- // dialog boxes - I have to convert units.
- LONG units = ::GetDialogBaseUnits();
- int dlgx = units & 0xffff, dlgy = (units >> 16) & 0xffff;
- p1->x = (short)((4*theApp.mainWindow->clientWidth)/dlgx - p1->cx)/2;
- p1->y = (short)((8*theApp.mainWindow->clientHeight)/dlgy - p1->cy)/2;
- LPWORD p2 = (LPWORD)(p1 + 1);
- *p2++ = 0; // no menu
- *p2++ = 0; // a predefined box class
- *p2++ = 0; // no title
- p2 = PlantDlgItem(p2, 1, 10, 94, 12, -1,
- WS_CHILD | WS_VISIBLE | SS_CENTER, 0x0082, "Press OK to exit");
- p2 = PlantDlgItem(p2, 28, 23, 40, 14, IDOK,
- WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 0x0080, "OK");
- GlobalUnlock(h);
- CenteredDialogBox dlg;
- dlg.CreateAndDisplay(h);
- GlobalFree(h);
- }
- // Here I override the Run member of my application so that I take control
- // of the way in which the underlying window system is polled. This is
- // somewhat delicate! The code here has to be a close enough shadow of
- // what MFC does that I do not cause conflict.
- int cwin_pause_at_end;
- int CTheApp::Run() // Main running routine until application exits
- {
- // If I had not managed to open a main window then I should give up.
- if (m_pMainWnd == NULL
- // && AfxOleGetUserCtrl() // Embedding or Automation invocation?
- ) AfxPostQuitMessage(0);
- // The message handler needs to access m_msgCur which is a private member
- // of the class, so I can not use just (theApp.m_msgCur) to get at it. To
- // work around the problem I just dump a reference to it in the variable
- // msgPtr.
- //+++ This was OK with Visual C++ version 5, but by version 7 (in
- //+++ Visual Studio .NET) the m_msgCur member no longer exists, and so this
- //+++ code needs to be rebuilt! Oh dear, especially since the way it
- //+++ was breaking private visibility is an indication that the original
- //+++ version was something of a crock! ACN September 2002
- //+++ msgPtr = &m_msgCur;
- // Now the real fun! I call cwin_main() which fires up my application code
- // Remember that cwin_main() should either return to me or do a cwin_exit()
- // and it should NOT call exit().
- cwin_pause_at_end = FALSE;
- int returnCode;
- // try {
- returnCode = cwin_main(argc, argv);
- // }
- // catch (int rc) { returnCode = rc; }
- if (cwin_pause_at_end)
- { cwin_maximize();
- cwin_ensure_screen();
- DoFinishBox();
- }
- if (m_pMainWnd != NULL) delete m_pMainWnd;
- m_pMainWnd = mainWindow = NULL;
- int returnCode1 = ExitInstance();
- if (returnCode1 > returnCode) returnCode = returnCode1;
- if (m_pMainWnd != NULL) m_pMainWnd->SendMessage(WM_CLOSE);
- // Although I go to some trouble to collect a return code here I find such
- // things somewhat unhelpful under Windows, and so at the last minute I
- // check away the information and return zero.
- return 0; // returnCode;
- }
- //void cwin_exit(int r)
- //{
- // throw r;
- //}
- BEGIN_MESSAGE_MAP(CTheApp, CWinApp)
- ON_COMMAND(IDM_HELPCONTENTS, OnHelpContents)
- ON_COMMAND(IDM_HELPSEARCH, OnHelpSearch)
- ON_COMMAND(IDM_HELP_ON_HELP, OnHelpUsing)
- ON_COMMAND(IDM_ABOUT, OnAbout)
- #ifdef DEMOVERSION
- ON_COMMAND(IDM_EUPRICES, OnEUPrices)
- ON_COMMAND(IDM_WORLDPRICES, OnWorldPrices)
- ON_COMMAND(IDM_ORDERFORM, OnOrderform)
- #endif
- ON_COMMAND_RANGE(IDM_DYNAMIC_ITEMS, IDM_LAST_DYNAMIC, OnDynamic)
- END_MESSAGE_MAP()
- // At various times I will want to go back and poll the window manager
- // to ensure that mouse activity is responded to, the screen is re-drawn and
- // other applications get a share of the CPU. To do that I will arrange that
- // 'cwin_poll_window_manager()' is called from time to time in the middle of
- // whatever else I am doing. This grabs a message from the window manager
- // and dispatches it to whatever handler is relevant.
- //!! At one stage I wanted to display a clock at the top left of the
- //!! title bar. I updates this by arranging to use idle processing, and
- //!! within the idle handler I watched to see if another 5 seconds had
- //!! gone by -- if so I updates the clock. Well firstly I ought to have
- //!! had a separate thread waking up every few seconds to do this, and
- //!! secondly this causes monitoring programs to get the impression that
- //!! I am a very heavy user of the CPU. CSL in fact replaces the clock
- //!! with a message about time used and GC activity, so this ends up
- //!! pretty pointless. I will not delete the code from my source file
- //!! just yet -- it is commented out with "//!!", but I will eventually
- //!! purge it.
- //!! static void timer_processing()
- //!! {
- //!! SYSTEMTIME t1;
- //!! GetSystemTime(&t1);
- //!! //- if (t1.wHour != lastFlushTime.wHour ||
- //!! //- (t1.wMinute - lastFlushTime.wMinute)*60 +
- //!! //- (t1.wSecond - lastFlushTime.wSecond) > 3)
- //!! //- cwin_almost_ensure_screen();
- //!! if (!theApp.mainWindow->leftSetByUser)
- //!! {
- //!! // Here I arrange to update the title-bar clock about once every 5 secs. It
- //!! // seems that every second it too frequent, especially since it often flashes
- //!! // the title-bar while re-drawing it. But 10 seconds is too long and lets
- //!! // the user feel things may be stuck.
- //!! // If the user explicitly sets any value in the left part of the title bar
- //!! // then this action is disabled. I do not set titleUpdateTime at the start
- //!! // of a run but that does not matter - it will fall into line within a few
- //!! // seconds whatever its initial value (however junky) is.
- //!! if (theApp.mainWindow->titleUpdateTime.wHour != t1.wHour ||
- //!! theApp.mainWindow->titleUpdateTime.wMinute != t1.wMinute ||
- //!! theApp.mainWindow->titleUpdateTime.wSecond/5 != t1.wSecond/5)
- //!! { theApp.mainWindow->titleUpdateTime = t1;
- //!! theApp.mainWindow->titleUpdateTime.wSecond =
- //!! 5*(theApp.mainWindow->titleUpdateTime.wSecond/5);
- //!! theApp.mainWindow->cwin_display_date();
- //!! }
- //!! }
- //!! }
- //!!
- //!! // This task will busy-wait in its idle-state watching time go by and
- //!! // occasionally updating the screen etc.
- //!!
- //!! BOOL CTheApp::OnIdle(LONG lCount)
- //!! {
- //!! BOOL r = CWinApp::OnIdle(lCount);
- //!! if (!r) timer_processing();
- //!! return r;
- //!! }
- //!!
- void cwin_poll_window_manager(int waitForEvent)
- {
- // If the application has registered an idle-time handler then that gets
- // invoked until it has finished or until a real message arrives whenever
- // I call cwin_poll_window_manager(). I also process ALL the window messages
- // that have stacked up and only go back to the user when otherwise idle.
- MSG msg;
- if (!waitForEvent &&
- !::PeekMessage(&msg,
- // theApp.msgPtr,
- NULL, 0, 0, PM_NOREMOVE))
- return; // These days if there are no messages I do nothing
- // Drop through if there is a message waiting for me, so that
- // PumpMessage will not block unless I have asked for that.
- do
- { if (!theApp.PumpMessage())
- { Lstop(0, 1); // the "1" here actually means "0"!
- return;
- }
- // If the user selects CLOSE from the system menu it causes PumpMessage to
- // return FALSE, so in that case I close things down.
- } while (::PeekMessage(&msg,
- //theApp.msgPtr,
- NULL, 0, 0, PM_NOREMOVE));
- LONG lIdle = 0;
- while (AfxGetApp()->OnIdle(lIdle++)); // in case higher levels use idle!
- }
- void cwin_minimize()
- {
- WINDOWPLACEMENT wp;
- if (!::GetWindowPlacement(theApp.mainWindow->m_hWnd, &wp)) return;
- wp.showCmd = SW_SHOWMINIMIZED;
- ::SetWindowPlacement(theApp.mainWindow->m_hWnd, &wp);
- }
- void cwin_maximize()
- {
- WINDOWPLACEMENT wp;
- if (!::GetWindowPlacement(theApp.mainWindow->m_hWnd, &wp)) return;
- wp.showCmd = SW_RESTORE;
- ::SetWindowPlacement(theApp.mainWindow->m_hWnd, &wp);
- }
- void CTheApp::OnHelpContents() // Start on contents page.
- {
- WinHelp(0L, HELP_CONTENTS);
- }
- void CTheApp::OnHelpSearch()
- {
- WinHelp((DWORD)"", HELP_PARTIALKEY); // Search through keywords.
- }
- void CTheApp::OnDynamic(unsigned int commandId)
- {
- // char hah[100];
- // sprintf(hah, "Help message %d %s\n", commandId,
- // dynamic_files[commandId-IDM_DYNAMIC_ITEMS]);
- // DisplayMsg(hah);
- ::WinHelp(mainWindow->m_hWnd,
- dynamic_files[commandId-IDM_DYNAMIC_ITEMS],
- HELP_CONTENTS,
- 0);
- }
- void CTheApp::cwin_set_help_file(const char *key, const char *path)
- {
- char key1[8];
- int i;
- if (key == NULL)
- { WriteProfileInt("HelpItems", "HowMany", 0);
- for (i=0; i<dynamicCount; i++)
- { sprintf(key1, "T%.3d", i);
- WriteProfileString("HelpItems", key1, NULL);
- sprintf(key1, "P%.3d", i);
- WriteProfileString("HelpItems", key1, NULL);
- }
- return;
- }
- for (i=0; i<dynamicCount; i++)
- { if (strcmp(key, dynamic[i]) == 0) break;
- }
- if (i == dynamicCount) // not found
- { if (path == NULL) return;
- else
- { dynamic[dynamicCount] = key;
- dynamic_files[dynamicCount++] = path;
- }
- }
- else
- { if (path == NULL)
- { dynamicCount--;
- for (;i<dynamicCount; i++)
- { dynamic[i] = dynamic[i+1];
- dynamic_files[i] = dynamic_files[i+1];
- }
- }
- else dynamic_files[i] = path;
- }
- WriteProfileInt("HelpItems", "HowMany", dynamicCount);
- for (i=0; i<dynamicCount; i++)
- { sprintf(key1, "T%.3d", i);
- WriteProfileString("HelpItems", key1, dynamic[i]);
- sprintf(key1, "P%.3d", i);
- WriteProfileString("HelpItems", key1, dynamic_files[i]);
- }
- if (path == NULL)
- { sprintf(key1, "T%.3d", i);
- WriteProfileString("HelpItems", key1, NULL);
- sprintf(key1, "P%.3d", i);
- WriteProfileString("HelpItems", key1, NULL);
- }
- }
- void cwin_set_help_file(const char *key, const char *path)
- {
- theApp.cwin_set_help_file(key, path);
- }
- // DisplayMsg is used a bit like fprintf(stderr, ...) but ONLY for debugging.
- // It pops up a modal dialog box each time it is called. This is easy to
- // code, but a bit clumsy in the way it disturbs the screen.
- void
- #ifdef _MSC_VER
- __cdecl
- #endif
- DisplayMsg(char *msg, ...)
- {
- char buffer[256];
- va_list a;
- va_start(a, msg);
- vsprintf(buffer, msg, a);
- va_end(a);
- AfxMessageBox(buffer);
- }
- // End of c_applic.cpp
|