//---------------------------------------------------------------------------- // ObjectWindows // (C) Copyright 1991, 1994 by Borland International, All Rights Reserved // // Implementation of class TApplication. This defines the basic behavior // for ObjectWindows applications. //---------------------------------------------------------------------------- #pragma hdrignore SECTION #include #include #include #include #include #if defined(SECTION) && SECTION != 1 DIAG_DECLARE_GROUP(OwlApp); // General Application diagnostic group #endif #if !defined(SECTION) || SECTION == 1 DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlApp, 1, 0); // // Static members for initialization // HINSTANCE TApplication::InitHInstance; HINSTANCE TApplication::InitHPrevInstance; string TApplication::InitCmdLine; int TApplication::InitCmdShow; // // Global GetWindowPtr() message id used for registered message // uint _OWLDATA GetWindowPtrMsgId = 0; // // Constructor for use in OwlMain(). Gets members from statics set earlier by // a call to InitWinMainParams() in Owl's WinMain. // TApplication::TApplication(const char far* name, TModule*& gModule, TAppDictionary* appDict) : TModule(name, InitHInstance, InitCmdLine.c_str()), XBase(0), XState(0), DocManager(0), Dictionary(appDict ? appDict : &::OwlAppDictionary) { // Copy over values that were stashed in static members before this instance // was constructed. // hPrevInstance = InitHPrevInstance; nCmdShow = InitCmdShow; MainWindow = 0; HAccTable = 0; BreakMessageLoop = false; BWCCOn = Ctl3dOn = false; BWCCModule = Ctl3dModule = 0; Running = false; CondemnedWindows = 0; CmdLine = InitCmdLine; Dictionary->Add(this); gModule = this; } // // Constructor for use in user defined WinMain() when all the args are // available // TApplication::TApplication(const char far* name, HINSTANCE instance, HINSTANCE prevInstance, const char far* cmdLine, int cmdShow, TModule*& gModule, TAppDictionary* appDict) : TModule(name, instance, cmdLine), XBase(0), XState(0), DocManager(0), Dictionary(appDict ? appDict : &::OwlAppDictionary) { hPrevInstance = prevInstance; nCmdShow = cmdShow; MainWindow = 0; HAccTable = 0; BreakMessageLoop = false; BWCCOn = Ctl3dOn = false; BWCCModule = Ctl3dModule = 0; Running = false; CondemnedWindows = 0; CmdLine = cmdLine; Dictionary->Add(this); gModule = this; } // // // TApplication::~TApplication() { DeleteCondemned(); // Unregister ourselves from the Ctl3d DLL and/or the BWCC DLL if they are // loaded. // if (Ctl3dModule) { bool FAR PASCAL(*Ctl3dUnregister)(HANDLE); (FARPROC)Ctl3dUnregister = Ctl3dModule->GetProcAddress("Ctl3dUnregister"); if (Ctl3dUnregister) Ctl3dUnregister(*this); delete Ctl3dModule; } if (BWCCModule) { bool FAR PASCAL(*bwccIntlTerm)(void); (FARPROC)bwccIntlTerm = BWCCModule->GetProcAddress("BWCCIntlTerm"); if (bwccIntlTerm) bwccIntlTerm(); delete BWCCModule; } // Delete the main window if still present, may be destroyed but not deleted // Set MainWindow to 0 to prevent calling ::PostQuitMessage // TWindow* mainWindow = SetMainWindow(0); if (mainWindow) { mainWindow->Destroy(); delete mainWindow; } delete (TStreamableBase*)DocManager;// cast to avoid ref to docmgr if not used // Remove ourselves from the application dictionary that we are in // Dictionary->Remove(this); delete XBase; // remove any exception copy } // // Handle initialization for the first executing instance of the OWL // application // void TApplication::InitApplication() { } // // Handle initialization for each executing instance of the OWL // application // // This implementation creates and displays the main window // void TApplication::InitInstance() { InitMainWindow(); if (MainWindow) { MainWindow->SetFlag(wfMainWindow); MainWindow->Create(); MainWindow->Show(nCmdShow); } else THROW( TXInvalidMainWindow() ); } // // Initialize the application's main window // // Default main window title is the same as the applications // void TApplication::InitMainWindow() { SetMainWindow(new TFrameWindow(0, GetName())); } // // Handle termination for each executing instance of the application // int TApplication::TermInstance(int status) { return status; } // // Set (or reset) the main window. Returns, but does not destroy the // previous main window. // TFrameWindow* TApplication::SetMainWindow(TFrameWindow* window) { if (MainWindow) MainWindow->ClearFlag(wfMainWindow); TFrameWindow* oldMainWindow = MainWindow; MainWindow = window; if (MainWindow) MainWindow->SetFlag(wfMainWindow); return oldMainWindow; } // // Sets (or resets) the document manager, returns the previous one if present // TDocManager* TApplication::SetDocManager(TDocManager* docManager) { TDocManager* oldDocManager = DocManager; DocManager = docManager; return oldDocManager; } #if defined(BI_PLAT_WIN32) // // overrides TEventHandler::Dispatch() to handle multi-thread synchonization // LRESULT TApplication::Dispatch(TEventInfo& info, WPARAM wp, LPARAM lp) { TApplication::TAppLock Lock(*this); return TModule::Dispatch(info, wp, lp); } int TApplication::TAppMutex::NotWIN32s = !( (::GetVersion()&0x80000000) && (::GetVersion()&0xFF) < 4); #endif // // default idle action is to forward the action to the main window. // bool TApplication::IdleAction(long idleCount) { if (MainWindow) return MainWindow->IdleAction(idleCount); return 0; } // // Run this application, return when finished // // Initializes instances, creating and displaying their main window (calls // InitApplication for the first executing instance and calls InitInstance for // all instances). Runs the application's message loop. Each of the virtual // functions called are expected to throw an exception if there is an error. // int TApplication::Run() { int status; TRY { if (!MainWindow) { if (!hPrevInstance) InitApplication(); InitInstance(); } Running = true; status = MessageLoop(); } CATCH( (TXOwl& x) {status = x.Unhandled(this, 0);}) CATCH( (xmsg& x) {status = Error(x, 0);}) CATCH( (Bad_cast& x) {status = Error(xmsg(string(typeid(x).name())), 0);} ) CATCH( (Bad_typeid& x) {status = Error(xmsg(string(typeid(x).name())), 0);} ) MSG msg; while (::PeekMessage(&msg,0,0,0,PM_NOYIELD|PM_REMOVE) && msg.message != WM_PAINT) ; // flush queue Running = false; return TermInstance(status); } // // Start this application and return immediately // // Initializes instances, creating and displaying their main window (calls // InitApplication for the first executing instance and calls InitInstance for // all instances). Each of the virtual functions called are expected to throw an // exception if there is an error. Does not run message loop. // int TApplication::Start() { int status = 0; TRY { if (!hPrevInstance) InitApplication(); InitInstance(); } CATCH( (TXOwl& x) {status = x.Unhandled(this, 0);}) CATCH( (xmsg& x) {status = Error(x, 0);}) CATCH( (Bad_cast& x) {status = Error(xmsg(string(typeid(x).name())), 0);} ) CATCH( (Bad_typeid& x) {status = Error(xmsg(string(typeid(x).name())), 0);} ) return status; } // // Called after each message is pulled from the queue, and before it is // dispatched. Return true if the message was handled completely here. // bool TApplication::ProcessAppMsg(MSG& msg) { // start with the window that the event was destined for and allow it // and its parent (and its parent...) an opportunity to preprocess the // event // for (HWND hWnd = msg.hwnd; hWnd; hWnd = ::GetParent(hWnd)) { TWindow* win = GetWindowPtr(hWnd); if (win && win->PreProcessMsg(msg)) return true; } // for compatability with OWL 1.0, check the application's accelerator // table if it is being used // // NOTE: we should only support this for one rev... // if (HAccTable && MainWindow) return ::TranslateAccelerator(MainWindow->HWindow, HAccTable, &msg); return false; } // // Called after each message dispatch when TApplication's message loop is not // being used. // void TApplication::PostDispatchAction() { DeleteCondemned(); ResumeThrow(); MSG msg; if (!::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) IdleAction(0); } // // Lowlevel message loop: retrieves and processes messages from the OWL // application's message queue until it is empty // // calls ProcessAppMsg() to allow special pre-handling of the message // bool TApplication::PumpWaitingMessages() { MSG msg; bool foundOne = false; while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { foundOne = true; if (msg.message == WM_QUIT) { BreakMessageLoop = true; MessageLoopResult = msg.wParam; ::PostQuitMessage(msg.wParam); // make sure all loops exit break; } // Let the app preprocess the message. If it is not eaten, then translate // it, & dispatch it. If no hwnd, then first find/dispatch it directly to // the app (for PostAppMessage() functionality) // if (!ProcessAppMsg(msg)) { ::TranslateMessage(&msg); if (!msg.hwnd) { TEventInfo cmdEventInfo(msg.message, msg.wParam); if (Find(cmdEventInfo)) { Dispatch(cmdEventInfo, msg.wParam, msg.lParam); return true; } else { TEventInfo eventInfo(msg.message); if (Find(eventInfo)) { Dispatch(eventInfo, msg.wParam, msg.lParam); return true; } } } ::DispatchMessage(&msg); DeleteCondemned(); ResumeThrow(); } } return foundOne; } // // Suspend throw functions store away a caught exception to allow foreign code // to be re-entered. Call ResumeThrow() to rethrow the exception, if any, upon // return from the foreign code. // void TApplication::SuspendThrow(xalloc& x) { XString = x.why(); XSize = x.requested(); XState |= xsAlloc; } void TApplication::SuspendThrow(xmsg& x) { XString = x.why(); XState |= xsMsg; } void TApplication::SuspendThrow(TXBase& x) { delete XBase; // remove any previous exception XBase = x.Clone(); XState |= xsBase; } void TApplication::SuspendThrow(int flag) { XState |= (flag & (xsBadCast | xsBadTypeid | xsUnknown)); } void TApplication::ResumeThrow() { if (XState) { if (XState & xsBase) { XState &= ~xsBase; XBase->Throw(); // must be deleted later } if (XState & xsAlloc) { XState &= ~xsAlloc; THROW( xalloc(XString,XSize) ); } if (XState & xsMsg) { XState &= ~xsMsg; THROW( xmsg(XString) ); } if (XState & xsUnknown) { XState &= ~xsUnknown; THROW( xmsg(string()) ); } if (XState & xsBadCast) { XState &= ~xsBadCast; THROW( Bad_cast() ); } if (XState & xsBadTypeid) { XState &= ~xsBadTypeid; THROW( Bad_typeid() ); } } } // // General message loop: retrieves and processes messages from the OWL // application's message queue until BreakMessageLoop becomes true // // Calls IdleAction() when there are no messages // int TApplication::MessageLoop() { long idleCount = 0; MessageLoopResult = 0; while (!BreakMessageLoop) { TRY { if (!IdleAction(idleCount++)) ::WaitMessage(); // allow system to go idle if (PumpWaitingMessages()) // pumps any waiting messages idleCount = 0; } CATCH( (TXOwl& x) { MessageLoopResult = x.Unhandled(this, IDS_OKTORESUME); if (MessageLoopResult != 0) { ::PostQuitMessage(MessageLoopResult); break; } }) CATCH( (xmsg& x) { MessageLoopResult = Error(x, 0, IDS_OKTORESUME); if (MessageLoopResult != 0) { ::PostQuitMessage(MessageLoopResult); break; } }) CATCH( (Bad_cast& x) { MessageLoopResult = Error(xmsg(string(typeid(x).name())), 0, IDS_OKTORESUME); if (MessageLoopResult != 0) { ::PostQuitMessage(MessageLoopResult); break; } }) CATCH( (Bad_typeid& x) { MessageLoopResult = Error(xmsg(string(typeid(x).name())), 0, IDS_OKTORESUME); if (MessageLoopResult != 0) { ::PostQuitMessage(MessageLoopResult); break; } }) } BreakMessageLoop = false; return MessageLoopResult; } // // Default event handling simply defers to the DocManager if it has been // installed // bool TApplication::Find(TEventInfo &eventInfo, TEqualOperator equal) { return DocManager ? DocManager->Find(eventInfo, equal) : false; } // // Determines whether the application can be closed. // Makes sure the MainWindow can close & doc manager can close. // bool TApplication::CanClose() { TEventInfo eventInfo(WM_OWLCANCLOSE); return (!MainWindow || MainWindow->CanClose()) && (!DocManager ||!DocManager->Find(eventInfo) || DocManager->Dispatch(eventInfo, 0, 0)); } // // Oportunity to preprocess the main window's menubar before it is installed. // Normally delegated to the doc manager to install a file menu as needed // void TApplication::PreProcessMenu(HMENU fmenu) { TEventInfo eventInfo(WM_OWLPREPROCMENU); if (DocManager && DocManager->Find(eventInfo)) { DocManager->Dispatch(eventInfo, (WPARAM)fmenu, 0); MainWindow->DrawMenuBar(); } } // // Condemn a window to be deleted the at the next available safe time. // Adds the window to a normal single linked list // // Condemned windows should be removed if they are destructed in the mean time // thru some other mechanism (i.e. stack, aggregate, etc) // void TApplication::Condemn(TWindow* win) { TRACEX(OwlApp, 1, "Condemning window: " << *win); win->SetParent(0); win->SetNext(CondemnedWindows); CondemnedWindows = win; } // // Remove a condemned window from the list. // void TApplication::Uncondemn(TWindow* win) { if (win && CondemnedWindows) { TWindow* w = 0; if (CondemnedWindows != win) for (w = CondemnedWindows; w->Next() != win; w = w->Next()) if (!w->Next()) return; TRACEX(OwlApp, 1, "Uncondemning window: " << *win); if (w) w->SetNext(win->Next()); else CondemnedWindows = win->Next(); } } // // Walk the condemned window list & delete each window. Assumes that the // windows were constructed using 'new' // void TApplication::DeleteCondemned() { while (CondemnedWindows) { TRACEX(OwlApp, 1, "Deleting condemned window: " << *CondemnedWindows); TWindow* next = CondemnedWindows->Next(); delete CondemnedWindows; CondemnedWindows = next; } } TApplication::TXInvalidMainWindow::TXInvalidMainWindow() : TXOwl(IDS_INVALIDMAINWINDOW) { } TApplication::TXInvalidMainWindow::~TXInvalidMainWindow() { } TApplication::TXInvalidMainWindow* TApplication::TXInvalidMainWindow::Clone() { return new TXInvalidMainWindow(*this); } void TApplication::TXInvalidMainWindow::Throw() { THROW( *this ); } #endif //---------------------------------------------------------------------------- #if !defined(SECTION) || SECTION == 2 struct TEnumInfo { HWND ModalWnd; // The window being made modal if needed short Count; // Count of windows in Wnds below HWND* Wnds; // list of windows that were disabled }; static TEnumInfo* stackTop = 0; // points to topmost enuminfo in BeginModal calls // // Enum[Thread/Task]Windows callback. Counts or disables given window based on // whether or not window list has been allocated yet. // bool CALLBACK __export DisableWnds(HWND wnd, TEnumInfo far* ei) { if (!(::GetWindowLong(wnd, GWL_STYLE) & WS_CHILD)) { if (wnd != ei->ModalWnd && ::IsWindowEnabled(wnd)) { if (!ei->Wnds) { ei->Count++; // no buffer yet, we are just counting } else { *(ei->Wnds++) = wnd; ::EnableWindow(wnd, false); } } } return true; } // // Terminate the modal state initiated by BeginModal. Needs topmost ei block, // and cleans the block up as needed inorder to be safe to be called twice. // static void termModal(TEnumInfo& ei) { // // Re-enable window(s) that are disabled in BeginModal() // if (ei.Wnds) { for (HWND* wnd = ei.Wnds; *wnd; wnd++) ::EnableWindow(*wnd, true); delete[] ei.Wnds; ei.Wnds = 0; } else { if (ei.ModalWnd && IsWindow(ei.ModalWnd)) { ::EnableWindow(ei.ModalWnd, true); ei.ModalWnd = 0; } } } // // Go modal and enter a message loop until a quit message goes by. // the flag values determine how window is used: // MB_APPLMODAL - window is the owner to disable (if 0, none are disabled) // MB_TASKMODAL - window is the window to make modal, // all other top level windows are disabled // MB_SYSTEMMODAL - window is the window to make system modal // returns -1 on errors // int TApplication::BeginModal(TWindow* window, int flags) { TEnumInfo ei = { 0, 0, 0 }; TEnumInfo* lastStackTop = stackTop; // keep last stackTop to restore later stackTop = &ei; // point stackTop to topmost ei // Set modal state // if (flags & MB_TASKMODAL) { if (window) ei.ModalWnd = window->HWindow; // don't disable the modal window if exists // count windows to disable // #if defined(BI_PLAT_WIN32) if (!EnumThreadWindows(GetCurrentThreadId(), (WNDENUMPROC)DisableWnds, (LPARAM)(TEnumInfo far*)&ei)) return -1; #else if (!EnumTaskWindows(GetCurrentTask(), (WNDENUMPROC)DisableWnds, (LPARAM)(TEnumInfo far*)&ei)) return -1; #endif // Allocate list of windows to disable, disable windows that are // enabled and then stuff them into the list. // HWND* wnds = ei.Wnds = new HWND[ei.Count + 1]; memset(ei.Wnds, 0, sizeof(HWND)*(ei.Count + 1)); #if defined(BI_PLAT_WIN32) EnumThreadWindows(GetCurrentThreadId(), (WNDENUMPROC)DisableWnds, (LPARAM)(TEnumInfo far*)&ei); #else EnumTaskWindows(GetCurrentTask(), (WNDENUMPROC)DisableWnds, (LPARAM)(TEnumInfo far*)&ei); #endif ei.Wnds = wnds; // restore alloc'd pointer since enumerator bumps it } #if defined(BI_PLAT_WIN16) else if (flags & MB_SYSTEMMODAL) window->SetSysModalWindow(); #endif else if (window) { ei.ModalWnd = window->HWindow; // remember who to re-enable later window->EnableWindow(false); } // Enter message loop, saving & restoring the current status & getting the // returned result. // int result; TRY { result = MessageLoop(); } CATCH( (...) { termModal(ei); stackTop = lastStackTop; RETHROW; }) stackTop = lastStackTop; termModal(ei); // just in case termModal was missed in EndModal // return the result from the modal window's EndModal call // return result; } // // Cause the current modal message loop to break and have it return a result // Re-enable the disabled windows here, if the EnumInfo is available. // void TApplication::EndModal(int result) { MessageLoopResult = result; BreakMessageLoop = true; if (stackTop) termModal(*stackTop); } #endif //---------------------------------------------------------------------------- #if !defined(SECTION) || SECTION == 3 // // Predefined DLLs that TApplication knows how to find. // #if defined(BI_PLAT_WIN32) const char BwccDllName[] = "BWCC32.DLL"; const char Ctl3dDllName[] = "CTL3D32.DLL"; #elif defined(BI_PLAT_WIN16) const char BwccDllName[] = "BWCC.DLL"; const char Ctl3dDllName[] = "CTL3DV2.DLL"; #endif // // Load the BWCC DLL if needed & set the BWCC on flag according to 'enable' // Library is not free'd on disable to reduce re-loads if enabling on the fly // void TApplication::EnableBWCC(bool enable, uint language) { if (enable) { if (!BWCCModule) { BWCCModule = new TModule(BwccDllName, true); bool FAR PASCAL(*bwccIntlInit)(uint); (FARPROC)bwccIntlInit = BWCCModule->GetProcAddress("BWCCIntlInit"); if (bwccIntlInit) bwccIntlInit(language); bool FAR PASCAL(*bwccRegister)(HINSTANCE); (FARPROC)bwccRegister = BWCCModule->GetProcAddress("BWCCRegister"); if (bwccRegister) bwccRegister(GetInstance()); } BWCCOn = true; } else BWCCOn = false; } // // enable or disable the use of the CTL3D DLL. Loads it if needed. // void TApplication::EnableCtl3d(bool enable) { // // If we are running Win4.0 or greater, then ctl3d is unnecessary // #if defined(BI_PLAT_WIN32) if ((::GetVersion()&0xFF) >= 4) #else if ((::GetVersion()&0xFF) >= 3 && ((::GetVersion()>>8)&0xFF) >= 95) #endif return; // // Load the Ctl3d DLL if needed & register our instance // if (enable) { if (!Ctl3dModule) { Ctl3dModule = new TModule(Ctl3dDllName, true); bool FAR PASCAL(*ctl3dRegister)(HANDLE); (FARPROC)ctl3dRegister = Ctl3dModule->GetProcAddress("Ctl3dRegister"); if (ctl3dRegister) ctl3dRegister(*this); else { delete Ctl3dModule; Ctl3dModule = 0; return; // could not register--don't change Ctl3dOn flag } } } Ctl3dOn = enable; } // // enable or disable CTL3D's use of auto-subclassing. Turn on autosubclassing // before creating a non-owl dialog to make it 3d, & turn it off immediatly // after. // void TApplication::EnableCtl3dAutosubclass(bool enable) { if (Ctl3dEnabled()) { if (enable) { bool FAR PASCAL(*ctl3dRegister)(HANDLE); (FARPROC)ctl3dRegister = Ctl3dModule->GetProcAddress("Ctl3dRegister"); if (ctl3dRegister) { ctl3dRegister(*this); bool FAR PASCAL(*ctl3dAutoSubclass)(HANDLE); (FARPROC)ctl3dAutoSubclass = Ctl3dModule->GetProcAddress("Ctl3dAutoSubclass"); if (ctl3dAutoSubclass) ctl3dAutoSubclass(*this); } } else { bool FAR PASCAL(*Ctl3dUnregister)(HANDLE); (FARPROC)Ctl3dUnregister = Ctl3dModule->GetProcAddress("Ctl3dUnregister"); if (Ctl3dUnregister) Ctl3dUnregister(*this); } } } #endif //---------------------------------------------------------------------------- #if !defined(SECTION) || SECTION == 4 IMPLEMENT_STREAMABLE1(TApplication, TModule); void* TApplication::Streamer::Read(ipstream& is, uint32 /*version*/) const { TApplication* o = GetObject(); if (o != ::Module) is >> *::Module; // set reference to OWL module return o; } void TApplication::Streamer::Write(opstream& os) const { TApplication* o = GetObject(); if (o != ::Module) os << *::Module; // write out reference to OWL module, no data written } #endif // SECTION