helpuser.cpp

Go to the documentation of this file.
00001 // $Id: helpuser.cpp 1729 2006-08-30 12:48:48Z luke $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 /*
00099 
00100     helpuser.cpp
00101 
00102     Routines to invoke the platform's help system for a given Camelot object or
00103     topic reference.
00104 
00105 */
00106 
00107 #include "camtypes.h"
00108 
00109 //#include <io.h>           // for FileExists
00110 #include <stdlib.h>
00111 #include "camelot.h"
00112 //#include "mainfrm.h"
00113 //#include "dialogop.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 //#include "errorbox.h"
00115 
00116 #include "helpuser.h"
00117 #include "helptabs.h"
00118 //#include "xshelpid.h"         // for the _R(IDH_TEST_PAGE)
00119 #include "product.h"            // for the PRODUCT_BASENAME
00120 //#include "resdll.h"
00121 //#include "helpdownload.h"
00122 
00123 //#include "simon.h"                // for the _R(IDS_HELP) button label string
00124 
00125 //#include <htmlhelp.h>         // for html help
00126 #include "keypress.h"
00127 
00128 
00129 // Code version.
00130 DECLARE_SOURCE("$Revision: 1729 $");
00131 
00132 
00133 // We need to use the correct filename parsing functions, depending on whether we are
00134 // a C/ASCII/ANSI or a Unicode build.  Note that under Win32 all exported functions
00135 // are specified in the ANSI character set, even in Unicode builds.
00136 #undef SPLITPATH
00137 #undef MAKEPATH
00138 #undef GETSHORTPATHNAME
00139 
00140 #ifdef UNICODE
00141     // Wide-character versions.
00142     #define SPLITPATH           (_wsplitpath)
00143     #define MAKEPATH            (_wmakepath)
00144     #define GETSHORTPATHNAME    ("GetShortPathNameW")
00145 #else
00146     // C/ASCII/ANSI versions.
00147     #define SPLITPATH           (_tsplitpath)
00148     #define MAKEPATH            (_tmakepath)
00149     #define GETSHORTPATHNAME    ("GetShortPathNameA")
00150 #endif
00151 
00152 
00153 // DialogOps derived from this class are "tabbed", and require special processing.
00154 #undef  TABBED_DIALOG_CLASS
00155 #define TABBED_DIALOG_CLASS     (CC_RUNTIME_CLASS(DialogTabOp))
00156 
00157 
00158 // This is the window class name for push buttons.
00159 #undef  BUTTON_CLASS
00160 #define BUTTON_CLASS            (TEXT("BUTTON"))
00161 
00162 
00163 // This determines the maximum time, in seconds, the app will wait on shutdown for the
00164 // NT launcher to pass a quit message to the 16-bit help engine on Windows NT.
00165 #define NTLAUNCHER_TIMEOUT      (3)
00166 
00167 
00168 
00170 //  Implementation.
00171 
00172 // These store the full paths to the help-file
00173 static String_256       achzHelpPath;
00174 
00175 PORTNOTE("help", "Help function unimplemented!")
00176 #if !defined(EXCLUDE_FROM_XARALX)
00177 static TCHAR achzMoviesHelpPath[_MAX_PATH];
00178 // static TCHAR achzStubPath[_MAX_PATH];
00179 
00180 #ifdef STANDALONE
00181 static TCHAR achzSpecPath[_MAX_PATH];
00182 #endif
00183 
00184 // This holds a handle to our message filter hook that traps F1 being pressed in dialogs.
00185 static HHOOK hF1Hook = NULL;
00186 #endif
00187 
00188 // This is set to TRUE if we use the help at all.  It reminds us to shut the help engine
00189 // down when we quit.
00190 static BOOL fHaveUsedHelp = FALSE;
00191 
00192 #ifdef STANDALONE
00193 static BOOL fHaveUsedSpecHelp = FALSE;
00194 #endif
00195 
00196 // This remembers that last format message resource ID passed to MakeMsg.  If we have to
00197 // provide help on an error box with a "error ID" of zero, we use this value instead,
00198 // hoping that it contains the ID of the string that was used to format the message.
00199 static UINT32 nNextMessageHelpContext = 0;
00200 
00201 // This flag prevents a bad-install error message being shown repeatedly.
00202 // static BOOL fNoNTLauncherMsgShown = FALSE;
00203 
00204 
00205 
00206 /********************************************************************************************
00207 >   static DWORD LookupDialogTopic(LPCTSTR lpcszLookupClass, UINT32 nPageResID)
00208 
00209     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00210     Created:    11/5/95
00211     Inputs:     lpcszLookupClass            the run-time class name of the dialog to find
00212                                             on-line help about. Can be null - in which case
00213                                             we just check the PageID
00214                 nPageResID                  the resource ID of the current page, if we
00215                                             want help on a 'tabbed' dialog
00216     Returns:    The index ID of the appropriate help topic, or zero if there isn't one.
00217     Purpose:    Private helper function that finds the help topic associated with "named"
00218                 dialogs, ie. those dialogs that are managed by a specialised C++ class, not
00219                 error or warning dialogs.
00220     SeeAlso:    HelpUser
00221 ********************************************************************************************/
00222 
00223 static DWORD LookupDialogTopic(LPCTSTR lpcszLookupClass, UINT32 nPageResID)
00224 {
00225     // Check we're not being passed junk.
00226 //  ERROR3IF(lpcszLookupClass == NULL, "No dialog class in LookupDialogTopic");
00227         
00228     // Scan through the whole table.
00229     for (DialogHelpTuple* ptpl = atplDialogTopics;
00230          ptpl->lpcszDialogClass != NULL;
00231          ptpl++)
00232     {
00233         // If the class-names & page ID's match then return the associated topic index.
00234         if ((lpcszLookupClass == NULL || ::camStricmp(ptpl->lpcszDialogClass, lpcszLookupClass) == 0) &&
00235             ptpl->nPageResID == nPageResID)
00236         {
00237             return ptpl->dwTopicIndex;
00238         }
00239     }
00240 
00241     // Couldn't find such a dialog class.
00242     return 0;
00243 }
00244 
00245 
00246 
00247 /********************************************************************************************
00248 >   static DWORD LookupOperationTopic(LPCTSTR lpcszOpName)
00249 
00250     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00251     Created:    23/5/95
00252     Inputs:     lpcszOpName             the OPTOKEN value of the Operation to look up help
00253                                         for
00254     Returns:    The index ID of the appropriate help topic, or zero if there isn't one.
00255     Purpose:    Private helper function that finds the help topic associated with
00256                 Camelot operations, eg. those things exposed in menus!
00257     SeeAlso:    HelpUser
00258 ********************************************************************************************/
00259 
00260 static DWORD LookupOperationTopic(LPCTSTR lpcszOpName)
00261 {
00262     // Check for junk.
00263     ERROR3IF(lpcszOpName == NULL, "No valid OpToken in LookupOperationTopic");
00264 
00265     // Scan through the whole table.
00266     for (OpHelpTuple* ptpl = atplOpTopics;
00267          ptpl->lpcszToken != NULL;
00268          ptpl++)
00269     {
00270         // If the token values match then we've found our help topic.
00271         if (::camStricmp(ptpl->lpcszToken, lpcszOpName) == 0)
00272         {
00273             return ptpl->dwTopicIndex;
00274         }
00275     }
00276 
00277     // No help topic, so sorry.
00278     return 0;
00279 }
00280 
00281 
00282 
00283 /********************************************************************************************
00284 >   static DWORD LookupMessageTopic(UINT32 nMessageID)
00285 
00286     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00287     Created:    11/5/95
00288     Inputs:     nMessageID          the resource identifier of the message displayed in an
00289                                     error or warning dialog
00290     Returns:    The index ID of the appropriate help topic, or zero if there isn't one.
00291     Purpose:    Private helper function that finds the help topic associated with the given
00292                 message, generally diaplayed in an error or warning dialog.
00293     SeeAlso:    HelpUser
00294 ********************************************************************************************/
00295 
00296 static DWORD LookupMessageTopic(UINT32 nMessageID)
00297 {
00298 #ifndef STANDALONE
00299     // If we have no message ID then use the last one passed to MakeMsg.
00300     if (nMessageID == 0) nMessageID = nNextMessageHelpContext;
00301 
00302     // Start at the beginning of the table, naturally . . .
00303     MsgHelpTuple* ptpl = atplMsgTopics;
00304     DWORD dwHelpTopic;
00305 
00306     // The table is terminated by a zero topic index.
00307     while ((dwHelpTopic = *ptpl++) != 0)
00308     {
00309         // Each sub-table is terminated by a zero message ID.
00310         while (*ptpl != 0)
00311         {
00312             // If one of the following matches the message then return the help topic.
00313             if (*ptpl++ == nMessageID) return dwHelpTopic;
00314         }
00315 
00316         // Skip over the terminating message ID.
00317         ptpl++;
00318     }
00319 #endif
00320     // No help topic for this message, so sorry.
00321     return 0;
00322 }
00323 
00324 
00325 /********************************************************************************************
00326 >   static BOOL FakeHelpButtonClick(HWND hwndDialog)
00327 
00328     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00329     Created:    31/5/95
00330     Inputs:     hwndDialog          the dialog box to fake a help button click within
00331     Returns:    TRUE if the fake click was possible, FALSE otherwise (maybe the dialog
00332                 doesn't have a help button?)
00333     Purpose:    Searches through the child windows of the given dialog, looking for a push
00334                 button with the label "Help".  If it finds one then the routine posts a
00335                 "faked" click message for the button, so help is invoked.
00336     SeeAlso:    F1HookProc
00337 ********************************************************************************************/
00338 
00339 PORTNOTE("help", "Help function unimplemented!")
00340 #if !defined(EXCLUDE_FROM_XARALX)
00341 static BOOL FakeHelpButtonClick(HWND hwndDialog)
00342 {
00343     // Make sure we've been passed a genuine window handle.
00344     if (!::IsWindow(hwndDialog)) return FALSE;
00345 
00346     // Get the text of a "help" button.
00347     String_256 strHelpLabel(_R(IDS_HELP));
00348 
00349     // Search through all child windows of the given dialog, looking for a push-button
00350     // with the label "Help".
00351     for (HWND hwndChild = ::GetWindow(hwndDialog, GW_CHILD);
00352          hwndChild != NULL;
00353          hwndChild = ::GetWindow(hwndChild, GW_HWNDNEXT))
00354     {
00355         // Find out the window class of the child window.
00356         TCHAR achzClassName[256];
00357         ::GetClassName(hwndChild, achzClassName, 256);
00358 
00359         // If it is a button then examine the label.
00360         if (camStricmp(achzClassName, BUTTON_CLASS) == 0)
00361         {
00362             // It is a button.  Get its label.
00363             TCHAR achzButtonLabel[256];
00364             ::GetWindowText(hwndChild, achzButtonLabel, 256);
00365             
00366             // Does its label match the "help" label?
00367             if (camStricmp(achzButtonLabel, strHelpLabel) == 0)
00368             {
00369                 // It does!  Fake a click on it and return.
00370                 return ::PostMessage(hwndDialog,
00371                                      WM_COMMAND,
00372                                      (WPARAM) MAKEWPARAM(::GetDlgCtrlID(hwndChild), BN_CLICKED),
00373                                      (LPARAM) hwndChild);
00374             }
00375         }
00376     }
00377 
00378     // No help button found, can't do it.
00379     return FALSE;
00380 }
00381 
00382 
00383 
00384 /********************************************************************************************
00385 >   static LRESULT CALLBACK EXPORT F1HookProc(INT32 nCode, WPARAM wParam, LPARAM lParam)
00386     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00387     Created:    25/5/95
00388     Inputs:     nCode           where the message was generated, eg. a menu, or a dialog
00389                 wParam          (ignored)
00390                 lParam          contains a pointer to a MSG structure describing the event
00391     Returns:    Whatever the next hook in the chain returns.
00392     Purpose:    Called when a message is generated within the app.  Checks if the message
00393                 was from a dialog box, and if so checks if it is the F1 key being pressed.
00394                 If it is then we work out which dialog has the "focus" and simulate its
00395                 help button being clicked.
00396     SeeAlso:    InitUserHelp; DeInitUserHelp
00397 ********************************************************************************************/
00398 
00399 static LRESULT CALLBACK EXPORT F1HookProc(INT32 nCode, WPARAM wParam, LPARAM lParam)
00400 {
00401     // Check if it's the F1 key going down within a dialog box . . .
00402     LPMSG lpmsg = (LPMSG) lParam;
00403     BOOL fHandleOK = ::IsWindow(lpmsg->hwnd);
00404     if (nCode == MSGF_DIALOGBOX && lpmsg->message == WM_KEYDOWN && lpmsg->wParam == CAMKEY(F1))
00405     {
00406         // Simulate the help button within the dialog being clicked, if there is one.
00407         // Empirically I have discovered that the window handle contained within the
00408         // message is that of the first child window in the dialog.
00409         if (fHandleOK) FakeHelpButtonClick(::GetParent(lpmsg->hwnd));
00410     }
00411 
00412     // Pass this event on to the next hook proc if it's valid.
00413     return (fHandleOK) ? ::CallNextHookEx(hF1Hook, nCode, wParam, lParam) : 0;
00414 }
00415 #endif
00416 
00417 
00418 /********************************************************************************************
00419 >   static BOOL RunOilHelp(LPCTSTR lpcszHelpPath, UINT32 nCommand, DWORD dwData)
00420 
00421     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00422     Created:    11/5/95
00423     Inputs:     lpcszHelpPath       string containing the path to the helpfile to display.
00424                 nCommand            the command identifier to pass to the help engine, eg
00425                                     HELP_CONTEXT or HELP_CONTENTS.
00426                 dwData              extra data to pass to the help engine, eg. the topic
00427                                     index, or zero.
00428     Returns:    TRUE if the help engine was run successfully, FALSE otherwise.
00429     Purpose:    Private helper function that runs the system's help engine, whatever that
00430                 might be, passing the given command.  On Windows this is WINHELP.EXE or
00431                 WINHLP32.EXE, on RISCOS it's get-the-manual-out time . . .
00432     SeeAlso:    HelpUser
00433 ********************************************************************************************/
00434 
00435 static BOOL RunOilHelp(LPCTSTR lpcszHelpPath, UINT32 nCommand, DWORD dwData)
00436 {
00437 #if !defined(EXCLUDE_FROM_XARALX)
00438     // Firing up the help engine can take a while, so show an hour-glass cursor.
00439     HCURSOR hOldCursor;
00440     HCURSOR hBusyCursor = ::LoadCursor(NULL, _R(IDC_WAIT));
00441     if (hBusyCursor != NULL) hOldCursor = ::SetCursor(hBusyCursor);
00442 
00443     // We always pass the handle of the main-frame window as the "owning" window.
00444     HWND hwndInvoker = GetMainFrame()->GetSafeHwnd();
00445 #endif
00446 
00447     // If we are running on a pure 32-bit platform such as Windows NT then we must fake
00448     // the WinHelp() function, as we want the 16-bit engine to be run, not WINHLP32.EXE.
00449     // The current help-file build includes references to 16-bit DLLs that seem to be
00450     // almost too much for the 32-bit engine.  We don't have to do this if we aren't
00451     // running the engine to browse a file, but simply issuing a command, such as
00452     // HELP_HELPONHELP.
00453     BOOL fOk;
00454     
00455         // Running under Chicago or Win32s, or the helpfile parameter is NULL, so run the
00456         // "normal" engine.  Here we should really "thunk" (translate) the 32-bit HWND
00457         // to a 16-bit HWND, I think?
00458 //      TRACEUSER( "JustinF", _T("Help being invoked normally\n"));
00459 
00460 
00461         fOk = TRUE;
00462         if(nCommand != HELP_QUIT)
00463         {
00464             wxString strHelpFileName(lpcszHelpPath);
00465             wxString Context = _T("");
00466             if (dwData)
00467             {
00468                 Context = PCTSTR(String_256( dwData ));
00469                 if (_T("") != Context)
00470                     // so that the string table contains a bit less, the ::/xarax/ and .htm
00471                     // are here, because they are common to every HTML help path.
00472                     strHelpFileName += _T("xarax/") + Context + _T(".htm");
00473             }
00474 
00475             CCamApp::LaunchWebBrowser( strHelpFileName );
00476         }
00477 
00478 #if !defined(EXCLUDE_FROM_XARALX)
00479     // Get some slightly useful information if it all goes horribly wrong.
00480 #ifdef _DEBUG
00481     if (!fOk) TRACEUSER( "Ollie", _T("RunOilHelp failed - last error: %lu\n"),
00482                                         (UINT32) ::GetLastError());
00483 #endif
00484 
00485     // Undo the hour-glass cursor and return a success code.
00486     if (hBusyCursor != NULL) ::SetCursor(hOldCursor);
00487 #endif
00488 
00489     return fOk;
00490 }
00491 
00492 
00493 
00494 /********************************************************************************************
00495 >   BOOL MakeShortPath(LPTSTR lpszPath, size_t cchMaxLen)
00496 
00497     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00498     Created:    2/6/95
00499     Inputs:     lpszPath        the full path to shorten.  The shortened version will be
00500                                 "outputed" into this same buffer.
00501                 cchMaxLen       the size of the above buffer
00502     Outputs:    lpszPath        contains the shortened path
00503     Returns:    TRUE if successful, FALSE otherwise.
00504     Purpose:    Special function to work around an ommission in Win32s, which does not
00505                 include the GetShortPathName function, even though Win32s is supposed to
00506                 export ALL Win32 functions.  This version does nothing under Win32s, which
00507                 shortens pathnames automatically (?), under other versions of Windows it
00508                 dynamically links to the function in the kernel32 library, thus avoiding
00509                 an explicit link to the function which would prevent the app loading.
00510     Errors:     -
00511     SeeAlso:    -
00512 ********************************************************************************************/
00513 
00514 BOOL MakeShortPath(LPTSTR lpszPath, size_t cchMaxLen)
00515 {
00516 PORTNOTETRACE("help", "Help function unimplemented!");
00517 #if !defined(EXCLUDE_FROM_XARALX)
00518     // Under Win32s we don't want to do this, because (i) Win32s does it anyway;
00519     // and (ii) the bloody GetShortPathName function isn't supported because they
00520     // forgot it (a serious bug, Mr Gates!)
00521     if (IsWin32s() && !IsWin32c()) return TRUE;
00522 
00523     // Now we have some aggro.  Because GetShortPathName isn't recognised as a Win32
00524     // function by Win32s, we must NOT have any explicit references to it in the program,
00525     // or the app won't load under Win32s.  Instead, we will try to dynamically link to it.
00526     HMODULE hlib = ::GetModuleHandle(TEXT("KERNEL32"));
00527     if (hlib == NULL)
00528     {
00529         TRACEUSER( "Ollie", _T("MakeShortPath: GetModuleHandle failed (error: %lu)\n"),
00530                                 (UINT32) ::GetLastError());
00531         return FALSE;
00532     }
00533 
00534     // OK, we've loaded the relevant library.  Now try to link to the function it contains.
00535     typedef DWORD (WINAPI *GSPNFUNC)(LPCTSTR, LPTSTR, DWORD);
00536     GSPNFUNC lpfn = (GSPNFUNC) ::GetProcAddress(hlib, GETSHORTPATHNAME);
00537     if (lpfn == NULL)
00538     {
00539         TRACEUSER( "Ollie", _T("MakeShortPath: GetProcAddress failed (error: %lu)\n"),
00540                                 (UINT32) ::GetLastError());
00541         return FALSE;
00542     }
00543 
00544     // Now call the GetShortPathName function and return a success code.
00545     DWORD dwResult = (*lpfn)(lpszPath, lpszPath, cchMaxLen);
00546     return dwResult != 0 && dwResult < cchMaxLen;
00547 #else
00548     return FALSE;
00549 #endif
00550 }
00551 
00552 
00553 
00554 /********************************************************************************************
00555 >   static BOOL ShowHelp(UINT32 nCommand, DWORD dwData)
00556 
00557     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00558     Created:    11/6/95
00559     Inputs:     nCommand            the command to pass to the help engine, eg. HELP_CONTENTS
00560     Returns:    TRUE if successful.
00561     Purpose:    Called to display the given topic in the Xara Studio general help file.
00562                 Makes a note if help is run successfully that we have to shut it down when
00563                 we quit.
00564 ********************************************************************************************/
00565 
00566 static BOOL ShowHelp(UINT32 nCommand, DWORD dwData)
00567 {
00568     BOOL fResult = RunOilHelp(achzHelpPath, nCommand, dwData);
00569     if (!fHaveUsedHelp && fResult) fHaveUsedHelp = TRUE;
00570     return fResult;
00571 }
00572 
00573 
00574 
00575 
00577 //  Interface.
00578 
00579 /********************************************************************************************
00580 >   BOOL HelpUser(const DialogOp& DlgOp)
00581 
00582     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00583     Created:    11/5/95
00584     Inputs:     DlgOp               reference to a (constant) dialog operation to display
00585                                     help about
00586     Returns:    TRUE if help was successfully provided, FALSE if not.
00587     Purpose:    Public function that finds the help topic associated with the given dialog
00588                 operation and runs the system help engine to display the topic.
00589     SeeAlso:    RunOilHelp; LookupDialogTopic
00590 ********************************************************************************************/
00591 
00592 BOOL HelpUser(const DialogOp& DlgOp)
00593 {
00594     // Work out which page within the dialog is visible, if appropriate.  We begin by
00595     // assuming this isn't relevant.
00596     UINT32 nPageResID = 0;
00597     if (DlgOp.IsKindOf(TABBED_DIALOG_CLASS))
00598     {
00599         // Work out which is the active (top-most) page within the tabbed dialog.
00600         wxWindow* pWnd = (wxWindow*) DlgOp.WindowID;
00601         if (pWnd != NULL)
00602         {
00603             // We got the window handle, get its MFC CWnd analogue.
00604             wxBookCtrlBase* pSheet = DialogManager::GetBookControl( pWnd );
00605             if (pSheet != NULL)
00606             {
00607                 // Ask it for the resource ID of its currently active page.
00608                 nPageResID = (UINT32) pSheet->GetCurrentPage()->GetId();
00609             }
00610 #ifdef _DEBUG
00611             else
00612             {
00613                 TRACEUSER( "Ollie", _T("Null OurPropSheet pointer in HelpUser\n"));
00614             }
00615 #endif
00616         }
00617 #ifdef _DEBUG
00618         else
00619         {
00620             TRACEUSER( "Ollie", _T("Null DialogOp window handle in HelpUser\n"));
00621         }
00622 #endif
00623     }
00624 
00625     // Get the run-time class name etc of the dialog.
00626     LPCTSTR lpcszDialogClass = DlgOp.GetRuntimeClass()->m_lpszClassName;
00627 
00628     // Look-up the class name/page ID in our list of help topics.  If we can't find it
00629     // then we return a failure code.
00630     DWORD dwHelpIndex = LookupDialogTopic(lpcszDialogClass, nPageResID);
00631     if (dwHelpIndex == 0)
00632     {
00633         TRACEUSER( "Ollie", _T("Can't find help topic for %s dialog (page ID %lu)\n"),
00634                                 (LPTSTR) lpcszDialogClass, (UINT32) nPageResID);
00635         return FALSE;
00636     }
00637 
00638     // Show this topic in the help system and return a success code.
00639     return ShowHelp(HELP_CONTEXT, dwHelpIndex);
00640 }
00641 
00642 
00643 
00644 /********************************************************************************************
00645 >   BOOL HelpUser(const CDialog& dlg)
00646 
00647     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00648     Created:    11/5/95
00649     Inputs:     dlg         the MFC dialog that requires help
00650     Returns:    TRUE if help was successfully provided, FALSE if not.
00651     Purpose:    Public function that finds the help topic associated with the given MFC
00652                 dialog and runs the system help engine to display the topic.
00653     SeeAlso:    RunOilHelp; LookupDialogTopic
00654 ********************************************************************************************/
00655 
00656 BOOL HelpUser(const wxDialog& dlg)
00657 {
00658     // Look-up the class name/page ID in our list of help topics.  If we can't find it
00659     // then we return a failure code.
00660     DWORD dwHelpIndex = LookupDialogTopic(dlg.GetClassInfo()->GetClassName(), 0);
00661     if (dwHelpIndex == 0)
00662     {
00663         TRACEUSER( "Ollie", _T("Can't find help topic for the %s MFC dialog\n"),
00664                                 (LPCTSTR) dlg.GetClassInfo()->GetClassName());
00665         return FALSE;
00666     }
00667 
00668     // Show this topic in the help system and return a success code.
00669     return ShowHelp(HELP_CONTEXT, dwHelpIndex);
00670 }
00671 
00672 
00673 
00674 /********************************************************************************************
00675 >   BOOL HelpUser(const OpDescriptor& opdesc)
00676 
00677     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00678     Created:    11/5/95
00679     Inputs:     opdesc          the OpDescriptor of the Operation to provide help for
00680     Returns:    TRUE if help was successfully provided, FALSE if not.
00681     Purpose:    Public function that finds the help topic associated with the given
00682                 OpDescriptor and runs the system help engine to display the topic.
00683     SeeAlso:    RunOilHelp; LookupOperationTopic
00684 ********************************************************************************************/
00685 
00686 BOOL HelpUser(const OpDescriptor& opdesc)
00687 {
00688     // Check if a help topic is already recorded within the OpDescriptor.  If it isn't
00689     // then we will have to look it up instead.
00690 /*
00691     //  NB. all the help topic ID's within the OpDescriptors are wrong, so ignore them!
00692     DWORD dwHelpIndex = ((OpDescriptor&) opdesc).GetHelpId();
00693     if (dwHelpIndex == 0) dwHelpIndex = LookupOperationTopic(opdesc.Token);
00694 */
00695     DWORD dwHelpIndex = LookupOperationTopic(opdesc.Token);
00696     if (dwHelpIndex == 0)
00697     {
00698         TRACEUSER( "Ollie", _T("Can't find help topic for the %s OpDescriptor\n"),
00699                                 (LPCTSTR) opdesc.Token);
00700         return FALSE;
00701     }
00702 
00703     // Show the topic we have found.
00704     return ShowHelp(HELP_CONTEXT, dwHelpIndex);
00705 }
00706 
00707 
00708 
00709 /********************************************************************************************
00710 >   BOOL HelpUser(UINT32 nMessageID)
00711 
00712     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00713     Created:    11/5/95
00714     Inputs:     nMessageID          the resource identifier of the message to display
00715                                     help about
00716     Returns:    TRUE if help was successfully provided, FALSE otherwise
00717     Purpose:    Public function that finds the help topic associated with the given
00718                 message and runs the system help engine to display the topic.
00719     SeeAlso:    RunOilHelp; LookupMessageTopic
00720 ********************************************************************************************/
00721 
00722 BOOL HelpUser(UINT32 nMessageID)
00723 {
00724     // Look-up the message ID in our list of help topics.  If we can't find it
00725     // then return a failure code.
00726     DWORD dwHelpIndex = LookupMessageTopic(nMessageID);
00727     if (dwHelpIndex == 0)
00728     {
00729         TRACEUSER( "Ollie", _T("Can't find help topic for message 0x%lX\n"),
00730                                 (UINT32) nMessageID);
00731         return FALSE;
00732     }
00733 
00734     // Show this topic in the help system and return a success code.
00735     return ShowHelp(HELP_CONTEXT, dwHelpIndex);
00736 }
00737 
00738 /********************************************************************************************
00739 
00740 >   BOOL HelpUserPropertyPage(UINT32 PageID);
00741 
00742     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 
00743     Created:    7/5/97
00744     Inputs:     PageID      ResourceID of the currently active page
00745     Returns:    TRUE if help was successfully provided, FALSE otherwise
00746     Purpose:    Public function that finds the help topic associated with the given
00747                 property page. This is required due to the new way the tabbed dialogs work
00748                 (via MFC).
00749 
00750 ********************************************************************************************/
00751 
00752 BOOL HelpUserPropertyPage(UINT32 PageID)
00753 {
00754     DWORD dwHelpIndex = LookupDialogTopic(NULL, PageID);
00755     return (HelpUserTopic(dwHelpIndex));
00756 }
00757 
00758 /********************************************************************************************
00759 
00760   > BOOL HelpUserTopic(DWORD dwHelpIndex)
00761 
00762     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00763     Created:    11/7/96
00764     Inputs:     nMessageID          the resource identifier of the message to display
00765                                     help about
00766     Returns:    TRUE if help was successfully provided, FALSE otherwise
00767     Purpose:    Public function that finds the help topic associated with the given
00768                 message and runs the system help engine to display the topic.
00769 
00770 ********************************************************************************************/
00771 
00772 BOOL HelpUserTopic(DWORD dwHelpIndex)
00773 {
00774     if (dwHelpIndex == 0)
00775         return FALSE;
00776     
00777     // Show this topic in the help system and return a success code.
00778     return ShowHelp(HELP_CONTEXT, dwHelpIndex);
00779 }
00780 
00781 
00782 /********************************************************************************************
00783 >   BOOL _HelpUser(LPCTSTR lpcszClassName, UINT32 nSubTopic = 0)
00784 
00785     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00786     Created:    23/5/95
00787     Inputs:     lpcszClassName              the class name of the object to run help for
00788                 nSubTopic                   which sub-topic for the object to display
00789                                             (by default, no sub-topic)
00790     Returns:    TRUE if the help system is started successfully.
00791     Purpose:    Public function that finds the help topic associated with the given
00792                 object and runs the system help engine to display it.  This is a
00793                 "bodgey" direct-access function for invoking help in those tricky cases,
00794                 such as the print-setup dialog, that do not have any Camelot object
00795                 directly associated with them.
00796     SeeAlso:    HelpUser; LookupDialogTopic; RunOilHelp
00797 ********************************************************************************************/
00798 
00799 BOOL _HelpUser(LPCTSTR lpcszClassName, UINT32 nSubTopic /* = 0 */)
00800 {
00801     DWORD dwHelpIndex = LookupDialogTopic(lpcszClassName, nSubTopic);
00802     if (dwHelpIndex == 0)
00803     {
00804         TRACEUSER( "Ollie", _T("Can't find raw help topic for %s (sub %lu)\n"),
00805                                     lpcszClassName, nSubTopic);
00806         return FALSE;
00807     }
00808 
00809     return ShowHelp(HELP_CONTEXT, dwHelpIndex);
00810 }
00811 
00812 
00813 
00814 /********************************************************************************************
00815 >   BOOL HelpContents()
00816 
00817     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00818     Created:    12/5/95
00819     Returns:    TRUE if successful.
00820     Purpose:    Runs the system help engine, displaying the "Contents" page.
00821     Errors:     -
00822     SeeAlso:    HelpUser; HelpSearch; HelpUsingHelp
00823 ********************************************************************************************/
00824 
00825 BOOL HelpContents()
00826 {
00827 #ifndef STANDALONE
00828 
00829     // If F1 was pressed, popup help in the context of the current tool. Use the tool's OpToken (of 
00830     // the form "TOOL<ToolId>") to look-up its help page. Fixes #10489
00831     if (KeyPress::IsKeyPressed(CAMKEY(F1)))
00832     {
00833         String OpToken;
00834         OpToken._MakeMsg( _T("TOOL%u"), Tool::GetCurrentID() );
00835         DWORD dwHelpIndex = LookupOperationTopic(OpToken);
00836         return ShowHelp(HELP_CONTEXT, dwHelpIndex);
00837     }
00838 
00839     return ShowHelp(HELP_FINDER, 0);
00840 
00841 #else // STANDALONE
00842     // On the viewer go directly to the contents page on all OS's
00843     #ifdef WEBSTER
00844         return ShowHelp(HELP_CONTEXT, _R(IDH_Contents));
00845     #else //WEBSTER
00846         return ShowHelp(HELP_CONTEXT, _R(IDH_Misc_Contents));
00847     #endif // WEBSTER
00848 #endif // STANDALONE
00849 }
00850 
00851 
00852 
00853 /********************************************************************************************
00854 >   BOOL HelpUsingHelp()
00855 
00856     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00857     Created:    12/5/95
00858     Returns:    TRUE if successful.
00859     Purpose:    Runs the system help engine, displaying the system's instructions for
00860                 using it.
00861     SeeAlso:    HelpUser; HelpContents; HelpSearch
00862 ********************************************************************************************/
00863 
00864 BOOL HelpUsingHelp()
00865 {
00866     return RunOilHelp(NULL, HELP_HELPONHELP, 0);
00867 }
00868 
00869 
00870 
00871 /********************************************************************************************
00872 >   BOOL HelpUsingTools()
00873 
00874     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00875     Created:    12/5/95
00876     Returns:    TRUE if successful.
00877     Purpose:    Runs the system help engine, displaying the help on tools.
00878     SeeAlso:    HelpUser; HelpContents; HelpSearch
00879 ********************************************************************************************/
00880 
00881 BOOL HelpUsingTools()
00882 {
00883     return ShowHelp(HELP_CONTEXT, _R(IDH_Misc_Tools));
00884 }
00885 
00886 
00887 
00888 /********************************************************************************************
00889 >   BOOL HelpUsingGalleries()
00890 
00891     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00892     Created:    12/5/95
00893     Returns:    TRUE if successful.
00894     Purpose:    Runs the system help engine, displaying the help on galleries.
00895     SeeAlso:    HelpUser; HelpContents; HelpSearch
00896 ********************************************************************************************/
00897 
00898 BOOL HelpUsingGalleries()
00899 {
00900     return ShowHelp(HELP_CONTEXT, _R(IDH_Overview_Galleries));
00901 }
00902 
00903 
00904 
00905 /********************************************************************************************
00906 >   BOOL HelpOnlineDemos()
00907 
00908     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00909     Created:    12/5/95
00910     Returns:    TRUE if successful.
00911     Purpose:    Runs the system help engine, displaying the on-line demos help page.
00912     SeeAlso:    HelpUser; HelpContents; HelpSearch
00913 ********************************************************************************************/
00914 
00915 BOOL HelpOnlineDemos()
00916 {
00917 PORTNOTETRACE("help", "Help function unimplemented!");
00918 #if !defined(EXCLUDE_FROM_XARALX)
00919     return RunOilHelp(achzMoviesHelpPath, 0, 0);
00920 #else
00921     return FALSE;
00922 #endif
00923 }
00924 
00925 
00926 
00927 /********************************************************************************************
00928 >   BOOL HelpTechnicalSupport()
00929 
00930     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00931     Created:    1/11/95
00932     Returns:    TRUE if successful.
00933     Purpose:    Runs the system help engine, displaying the tech support help page.
00934     SeeAlso:    HelpUser; HelpContents; HelpSearch
00935 *******************************************************************************************/
00936 
00937 BOOL HelpTechnicalSupport()
00938 {
00939 #ifdef WEBSTER
00940     return FALSE;
00941 #else
00942     return ShowHelp(HELP_CONTEXT, _R(IDH_Misc_Tech_Support));
00943 #endif
00944 }
00945 
00946 
00947 
00948 /********************************************************************************************
00949 >   BOOL CanHelpUser(UINT32 nMessageID)
00950 
00951     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00952     Created:    11/5/95
00953     Inputs:     nMessageID          the resource identifier of the message that is being
00954                                     enquired about
00955     Returns:    TRUE if a help topic descrbing this message exists, FALSE otherwise.
00956     Purpose:    Public function to query whether a help topic exists for a given message.
00957                 Depending on this the caller may display a help button in a message box,
00958                 or may not etc.
00959     SeeAlso:    LookupMessageTopic; InformGeneral
00960 ********************************************************************************************/
00961 
00962 BOOL CanHelpUser(UINT32 nMessageID)
00963 {
00964     // Just return TRUE if a help topic for the message exists.
00965     return LookupMessageTopic(nMessageID) != 0;
00966 }
00967 
00968 
00969 
00970 /********************************************************************************************
00971 >   void SetNextMsgHelpContext(UINT32 nMessageID)
00972 
00973     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00974     Created:    15/5/95
00975     Inputs:     nMessageID              the last message format string passed to MakeMsg
00976     Purpose:    Remembers the last format string passed to MakeMsg.  If a call is made to
00977                 InformWarning, InformError etc and no string resource ID is passed then we
00978                 have a problem using the string resource as an index into the help file.
00979                 This remembers that last one, which we use if the "error ID" is zero.
00980     SeeAlso:    StringBase::MakeMsg
00981 ********************************************************************************************/
00982 
00983 void SetNextMsgHelpContext(UINT32 nMessageID)
00984 {
00985     nNextMessageHelpContext = nMessageID;
00986     //TRACEUSER( "Andy", _T("\tSetNextMsgHelpContext(%d)\n"), nMessageID);
00987 }
00988 
00989 
00990 
00991 /********************************************************************************************
00992 >   UINT32 GetNextMsgHelpContext()
00993 
00994     Author:     Andy_Hills (Xara Group Ltd) <camelotdev@xara.com>
00995     Created:    22/11/00
00996     Inputs:     none
00997     Returns:    help context
00998     Purpose:    Gets the last help context set by SetNextMsgHelpContext
00999     SeeAlso:    used by ScreenView::OnActivateView
01000 ********************************************************************************************/
01001 
01002 UINT32 GetNextMsgHelpContext()
01003 {
01004     return nNextMessageHelpContext;
01005 }
01006 
01007 
01008 
01009 /********************************************************************************************
01010 >   BOOL InitUserHelp()
01011 
01012     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01013     Created:    11/5/95
01014     Returns:    TRUE if successful.
01015     Purpose:    Initialises the help system.  This should generally be called before just
01016                 about everything else, so help is available for startup problems.
01017     SeeAlso:    DeInitUserHelp
01018 ********************************************************************************************/
01019 
01020 // Forward references to helper functions
01021 BOOL InitHelpPath(BOOL bMainHelp);
01022 BOOL HelpFileExists(LPTSTR FileName);
01023 
01024 BOOL InitUserHelp()
01025 {
01026 #if !defined(EXCLUDE_FROM_XARALX)
01027     // If we have any deferred file copies, deal with them now...
01028     HelpDownloadOp::DoDeferredFileCopy();
01029 #endif
01030 
01031     // init main help file:
01032     BOOL bOK = InitHelpPath(TRUE);
01033 
01034     // init movies help file
01035     bOK = bOK && InitHelpPath(FALSE);
01036 
01037 #if !defined(EXCLUDE_FROM_XARALX)
01038     // Install a message filter hook to trap F1 being pressed in dialogs etc.  We don't need
01039     // one for menus as our "custom menu code" (ha ha ha) does this already.
01040     hF1Hook = ::SetWindowsHookEx(WH_MSGFILTER, F1HookProc, NULL, ::GetCurrentThreadId());
01041     ERROR3IF(hF1Hook == NULL, "Couldn't set F1 key hook in InitUserHelp");
01042 
01043     // Success!?!
01044     return hF1Hook != NULL;
01045 #else
01046     return bOK;
01047 #endif
01048 }
01049 
01050 
01051 // --------------------------------------------------------------------------------
01052 BOOL InitHelpPath(BOOL bMainHelp)
01053 {
01054     if( !bMainHelp )
01055     {
01056         PORTNOTETRACE("help", "InitHelpPath does not support Movie path yet");
01057     }
01058 
01059     // Get the locale id
01060     wxString    strLocale( setlocale( LC_MESSAGES, NULL ), wxConvUTF8 );
01061     INT32       ordSep = strLocale.Find( _T('_' ) );
01062     if ( -1 != ordSep )
01063         strLocale = strLocale.Left( ordSep );
01064     TRACEUSER( "jlh92", _T("Locale = %s\n"), PCTSTR(strLocale) );
01065     
01066     // Locale C is considered a synonym for en
01067     if( strLocale == _T("C") )
01068         strLocale = _T("en");
01069 
01070     // Check the help dir exists, if not bomb out
01071     wxString    strHelpPath( (PCTSTR)CCamApp::GetResourceDirectory() );
01072     strHelpPath += _T("/doc/");
01073     TRACEUSER( "jlh92", _T("Using filter discovery directory \"%s\"\n"), PCTSTR(strHelpPath + strLocale) );
01074     if( wxDir::Exists( strHelpPath + strLocale ) )
01075         strHelpPath += strLocale + _T("/");
01076     else
01077     {
01078         if( wxDir::Exists( strHelpPath + _T("en") ) )
01079             strHelpPath += _T("en/");
01080 #if defined(_DEBUG)
01081         else
01082         {
01083             // We'll try default location under debug to make life easier
01084             strHelpPath = _T("/usr/share/xaralx/doc/en/");
01085             TRACEUSER( "jlh92", _T("Try = \"%s\"\n"), PCTSTR(strHelpPath) );
01086         }
01087 #endif
01088     }
01089 
01090     achzHelpPath = strHelpPath;
01091     PORTNOTE( "help", "We should check and report non-existant help directory at some point" )
01092     return TRUE; // wxDir::Exists( strHelpPath );
01093 }
01094 
01095 
01096 /********************************************************************************************
01097 >   BOOL DeInitUserHelp()
01098 
01099     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01100     Created:    11/5/95
01101     Returns:    TRUE if successful.
01102     Purpose:    Shuts down the help system.  This should be called as late as possible, so
01103                 help is available for app shut-down problems.  Note that MFC will call
01104                 WinHelp(HELP_QUIT) for us when the main frame window is destroyed.
01105     SeeAlso:    InitUserHelp
01106 ********************************************************************************************/
01107 
01108 BOOL DeInitUserHelp()
01109 {
01110 PORTNOTETRACE("help", "Help function unimplemented!");
01111 #if !defined(EXCLUDE_FROM_XARALX)
01112     // Tell the help engine we've finished using the help file(s).
01113     // NB. KNWON BUG: this doesn't do the job on Windows NT, leaving the helpfiles open.
01114     // As yet I have no idea why - it is as per the docs and works on Win32s & Chicago.
01115     if (fHaveUsedHelp)
01116     {
01117         TRACEUSER( "Ollie", _T("Closing general helpfile\n"));
01118         ShowHelp(HELP_QUIT, 0);
01119     }
01120 
01121 #ifdef STANDALONE
01122     // Same if we ran the special helpfile.
01123     if (fHaveUsedSpecHelp)
01124     {
01125         TRACEUSER( "Ollie", _T("Closing special helpfile\n"));
01126         RunOilHelp(achzSpecPath, HELP_QUIT, 0);
01127     }
01128 #endif
01129 
01130     // Remove our F1 message hook.
01131     return hF1Hook == NULL || ::UnhookWindowsHookEx(hF1Hook);
01132 #else
01133     return TRUE;
01134 #endif
01135 }
01136 
01137 
01138 
01139 /********************************************************************************************
01140 >   BOOL ShowHelpSpec()
01141 
01142     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01143     Created:    11/6/95
01144     Returns:    TRUE if successful.
01145     Purpose:    Used by the viewer to display the Xara Studio special help file.  Makes a
01146                 note if help is run successfully that we have to shut it down when we
01147                 quit.
01148 ********************************************************************************************/
01149 
01150 #ifdef STANDALONE
01151 
01152 BOOL ShowHelpSpec()
01153 {
01154 PORTNOTETRACE("help", "Help function unimplemented!");
01155 #if !defined(EXCLUDE_FROM_XARALX)
01156     BOOL fResult = RunOilHelp(achzSpecPath, HELP_CONTENTS, 0);
01157     if (!fHaveUsedSpecHelp && fResult) fHaveUsedSpecHelp = TRUE;
01158     return fResult;
01159 #else
01160     return FALSE;
01161 #endif
01162 }
01163 
01164 #endif  // STANDALONE

Generated on Sat Nov 10 03:48:37 2007 for Camelot by  doxygen 1.4.4