mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 06:35:42 +00:00
ac8fa47104
have relative paths. This normally works fine, unless the current working directory is other than that of the default program directory where the pref DLLs are normally located. This could happen by executing the program from a different directory, or by saving a file to a directory other than the default program directory. In order to fix this, we need to push to the program directory just prior to loading a preference COM object, and then pop back.
2634 lines
78 KiB
C++
Executable File
2634 lines
78 KiB
C++
Executable File
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "fe_proto.h"
|
|
#include "hiddenfr.h"
|
|
#include "postal.h"
|
|
#include "helper.h"
|
|
#include "prefapi.h"
|
|
#ifdef MOZ_MAIL_NEWS
|
|
#include "mailfrm.h"
|
|
#endif // MOZ_MAIL_NEWS
|
|
#include "toolbar2.h"
|
|
#include "VerReg.h"
|
|
#include "libmocha.h"
|
|
#include "java.h"
|
|
#include "ngdwtrst.h"
|
|
|
|
extern "C" {
|
|
#include "xpgetstr.h"
|
|
extern int XP_ALERT_NETCASTER_NO_JS;
|
|
extern int XP_ALERT_CANT_RUN_NETCASTER;
|
|
};
|
|
|
|
|
|
// File used to house all general purpose front end
|
|
// function which have no other specific home.
|
|
// All functions in this file should begin with FEU.
|
|
|
|
// Way to get a frame window pointer out of a context ID.
|
|
// Must be of the appropriate type (Browser, mail, any, etc).
|
|
|
|
extern char szOLEFileType[MAX_INTERNAL_OLEFORMAT][4];
|
|
|
|
CFrameWnd *FEU_FindFrameByID(DWORD dwID, MWContextType cxType)
|
|
{
|
|
// Use the frame glue to do most of the work.
|
|
CFrameGlue *pFrameGlue = CFrameGlue::FindFrameByID(dwID, cxType);
|
|
if(pFrameGlue == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
// Return the frame window of the frame glue, can be NULL.
|
|
return(pFrameGlue->GetFrameWnd());
|
|
}
|
|
|
|
// Way to get a frame window that was last active browser window.
|
|
CFrameWnd *FEU_GetLastActiveFrame(MWContextType cxType, int nFindEditor)
|
|
{
|
|
// Have the frame glue look it up.
|
|
CFrameGlue *pFrameGlue = CFrameGlue::GetLastActiveFrame(cxType, nFindEditor);
|
|
if(pFrameGlue == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
// Return the frame window as known by the glue.
|
|
return(pFrameGlue->GetFrameWnd());
|
|
}
|
|
|
|
// Way to get a frame window that was last active browser window.
|
|
CAbstractCX *FEU_GetLastActiveFrameContext(MWContextType cxType, int nFindEditor)
|
|
{
|
|
// Have the frame glue look it up.
|
|
CFrameGlue *pFrameGlue = CFrameGlue::GetLastActiveFrame(cxType, nFindEditor);
|
|
if(pFrameGlue == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
// Return the frame window as known by the glue.
|
|
return(pFrameGlue->GetMainContext());
|
|
}
|
|
|
|
CFrameWnd *FEU_GetLastActiveFrameByCustToolbarType(CString custToolbar, CFrameWnd *pCurrentFrame, BOOL bUseSaveInfo)
|
|
{
|
|
// Have the frame glue look it up.
|
|
CFrameGlue *pFrameGlue = CFrameGlue::GetLastActiveFrameByCustToolbarType(custToolbar, pCurrentFrame, bUseSaveInfo);
|
|
if(pFrameGlue == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
// Return the frame window as known by the glue.
|
|
return(pFrameGlue->GetFrameWnd());
|
|
|
|
}
|
|
|
|
// Way to get the bottommost frame of t ype cxType
|
|
CFrameWnd *FEU_GetBottomFrame(MWContextType cxType, int nFindEditor)
|
|
{
|
|
|
|
CFrameGlue *pFrameGlue = CFrameGlue::GetBottomFrame(cxType, nFindEditor);
|
|
if(pFrameGlue == NULL)
|
|
return NULL;
|
|
|
|
//Return the frame window as known by the glue.
|
|
return(pFrameGlue->GetFrameWnd());
|
|
|
|
}
|
|
|
|
// Way to get a frame window that was last active browser window.
|
|
int FEU_GetNumActiveFrames(MWContextType cxType, int nFindEditor)
|
|
{
|
|
// Have the frame glue look it up.
|
|
int nCount = CFrameGlue::GetNumActiveFrames(cxType, nFindEditor);
|
|
|
|
// Return the frame window as known by the glue.
|
|
return(nCount);
|
|
}
|
|
|
|
// Way to get the context ID out of the frame which was last active.
|
|
// Returns 0 on error.
|
|
DWORD FEU_GetLastActiveFrameID(MWContextType cxType)
|
|
{
|
|
DWORD dwRetval = 0;
|
|
|
|
// Look up the last active frame of said type.
|
|
CFrameGlue *pFrameGlue = CFrameGlue::GetLastActiveFrame(cxType);
|
|
if(pFrameGlue != NULL) {
|
|
// Must have a context.
|
|
if(pFrameGlue->GetActiveContext() != NULL) {
|
|
dwRetval = pFrameGlue->GetActiveContext()->GetContextID();
|
|
}
|
|
else if(pFrameGlue->GetMainContext() != NULL) {
|
|
dwRetval = pFrameGlue->GetMainContext()->GetContextID();
|
|
}
|
|
}
|
|
|
|
return(dwRetval);
|
|
}
|
|
|
|
//#ifndef NO_TAB_NAVIGATION
|
|
// Scroll the current MWContext so that the Rect is visible
|
|
// FEU_MakeRectVisible() is subtracted from old FEU_MakeFormVisible(),
|
|
// and is used not only for Form elements, but other Tabable
|
|
// elements, such as links.
|
|
void FEU_MakeRectVisible(MWContext *pContext, const UINT left, const UINT top, const UINT right, const UINT bottom)
|
|
{
|
|
if(pContext == NULL )
|
|
return;
|
|
|
|
if(! ABSTRACTCX(pContext) || ! ABSTRACTCX(pContext)->IsWindowContext() )
|
|
return;
|
|
|
|
LTRB Rect( left, top, right, bottom);
|
|
CPaneCX *pCX = PANECX(pContext);
|
|
int32 lX = pCX->GetOriginX();
|
|
int32 lY = pCX->GetOriginY();
|
|
BOOL bMove = FALSE;
|
|
|
|
// If the element is partially to the right of the screen, we only want to
|
|
// move enough to get it fully on the screen.
|
|
if(Rect.left < pCX->GetOriginX() + pCX->GetWidth() &&
|
|
Rect.right > pCX->GetOriginX() + pCX->GetWidth() &&
|
|
Rect.Width() < pCX->GetWidth()) {
|
|
lX += Rect.right - (pCX->GetOriginX() + pCX->GetWidth());
|
|
bMove = TRUE;
|
|
}
|
|
|
|
// If the element is partially to the bottom of the screen, we only want to
|
|
// move enough to get it fully onto the screen.
|
|
if(Rect.top < pCX->GetOriginY() + pCX->GetHeight() &&
|
|
Rect.bottom > pCX->GetOriginY() + pCX->GetHeight() &&
|
|
Rect.Height() < pCX->GetHeight()) {
|
|
lY += Rect.bottom - (pCX->GetOriginX() + pCX->GetHeight());
|
|
bMove = TRUE;
|
|
}
|
|
|
|
// If the element is not fully on the screen, then we want to move so that it
|
|
// is on the screen at whatever cost that may be.
|
|
if(Rect.left < lX || Rect.left > lX + pCX->GetWidth() || Rect.top < lY ||
|
|
Rect.top > lY + pCX->GetHeight()) {
|
|
lX = Rect.left;
|
|
lY = Rect.top;
|
|
bMove = TRUE;
|
|
}
|
|
|
|
// Move if needed.
|
|
if(bMove) {
|
|
FE_SetDocPosition(pContext, FE_VIEW, lX, lY);
|
|
}
|
|
|
|
} // FEU_MakeRectVisible(
|
|
|
|
// old version is named as FEU_MakeFormVisible()
|
|
// Scroll the current MWContext so that the child window is visible
|
|
// New version.
|
|
void FEU_MakeElementVisible(MWContext *pContext, LO_Any *pElement)
|
|
{
|
|
if( NULL == pElement)
|
|
return;
|
|
// Figure up where the form element actually lies.
|
|
LTRB Rect;
|
|
Rect.left = pElement->x + pElement->x_offset;
|
|
Rect.top = pElement->y + pElement->y_offset;
|
|
Rect.right = Rect.left + pElement->width;
|
|
Rect.bottom = Rect.top + pElement->height;
|
|
|
|
FEU_MakeRectVisible( pContext, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom) );
|
|
}
|
|
//#else /* NO_TAB_NAVIGATION */
|
|
//#endif /* NO_TAB_NAVIGATION */
|
|
|
|
// The purpose of FEU_AhAhAhAhStayingAlive is to house the one and only
|
|
// saturday night fever function; named after Chouck's idol.
|
|
// This function will attempt to do all that is necessary in order
|
|
// to keep the application's messages flowing and idle loops
|
|
// going when we need to finish an asynchronous operation
|
|
// synchronously.
|
|
// The current cases that cause this are RPC calls into the
|
|
// application where we need to return a value or produce output
|
|
// from only one entry point before returning to the caller.
|
|
//
|
|
// If and when you modify this function, get your changes reviewed.
|
|
// It is too vital that this work, always.
|
|
//
|
|
// The function only attempts to look at one message at a time, or
|
|
// propigate one idle call at a time, keeping it's own idle count.
|
|
// This is not a loop. YOU must provide the loop which calls this function.
|
|
//
|
|
// Due to the nature and order of which we process windows messages, this
|
|
// can seriously mess with the flow of control through the client.
|
|
// If there is any chance at all that you can ensure that you are at the
|
|
// bottom of the message queue before doing this, then please take those
|
|
// measures.
|
|
extern "C" void FEU_StayingAlive()
|
|
{
|
|
static long lIdleCounter = 0;
|
|
|
|
// Stage 1.
|
|
// See if there are any messages which need to be propigated.
|
|
MSG msg;
|
|
if(::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE)) {
|
|
BOOL bPumpVal = theApp.NSPumpMessage();
|
|
|
|
// If this assertion fails, then we received a WM_QUIT, and
|
|
// the user is about to receive a dialog from the OS saying
|
|
// we are not responding to the system's request to shut down.
|
|
// Nothing we can do and still accomplish what we are trying to do....
|
|
ASSERT(bPumpVal);
|
|
|
|
// Reset the idle counter.
|
|
lIdleCounter = 0;
|
|
}
|
|
else {
|
|
// Stage 2.
|
|
// Call the Apps Idle loop.
|
|
// Ignore wether or not it says it needs or does not need more idle time.
|
|
// It is wholly dependent upon wether or not there are events in the queue.
|
|
theApp.OnIdle(lIdleCounter++);
|
|
}
|
|
}
|
|
|
|
// A utility function to block returning until a context is no longer
|
|
// found in the context list.
|
|
void FEU_BlockUntilDestroyed(DWORD dwContextID)
|
|
{
|
|
TRACE("Entering FEU_BlockUntilDestroyed(%lu)\n", dwContextID);
|
|
|
|
// Loop until the context is not in the context list, meaning it
|
|
// has been destroyed.
|
|
while(CAbstractCX::FindContextByID(dwContextID) != NULL) {
|
|
// Keep the app going.
|
|
FEU_StayingAlive();
|
|
}
|
|
|
|
TRACE("Leaving FEU_BlockUntilDestroyed(%lu)\n", dwContextID);
|
|
}
|
|
|
|
//
|
|
// Dynamically open the MAPI libraries for mail posting
|
|
//
|
|
void FEU_OpenMapiLibrary()
|
|
{
|
|
BOOL bLoadOK = FALSE;
|
|
|
|
theApp.m_fnOpenMailSession = NULL;
|
|
theApp.m_fnComposeMailMessage = NULL;
|
|
theApp.m_fnUnRegisterMailClient = NULL;
|
|
theApp.m_fnShowMailBox = NULL;
|
|
theApp.m_fnShowMessageCenter = NULL;
|
|
theApp.m_fnCloseMailSession = NULL;
|
|
theApp.m_fnGetMenuItemString = NULL;
|
|
|
|
UINT fuErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX);
|
|
|
|
char * prefStr = NULL;
|
|
PREF_CopyCharPref("mail.altmail_dll",&prefStr);
|
|
theApp.m_hPostalLib = LoadLibrary(prefStr);
|
|
if (prefStr) XP_FREE(prefStr);
|
|
|
|
SetErrorMode(fuErrorMode);
|
|
#ifdef XP_WIN32
|
|
if(theApp.m_hPostalLib)
|
|
{
|
|
#else
|
|
if(theApp.m_hPostalLib > HINSTANCE_ERROR)
|
|
{
|
|
#endif
|
|
//If we don't find "ShowMailBox" then we know it's either an old or invalid dll
|
|
SHOWMAILBOX testProc = (SHOWMAILBOX)::GetProcAddress(theApp.m_hPostalLib, "ShowMailBox");
|
|
if(testProc)
|
|
{
|
|
REGISTERMAIL regProc = (REGISTERMAIL)::GetProcAddress(theApp.m_hPostalLib, "RegisterMailClient");
|
|
theApp.m_fnOpenMailSession =
|
|
(OPENMAIL)::GetProcAddress(theApp.m_hPostalLib, "OpenMailSession");
|
|
theApp.m_fnComposeMailMessage =
|
|
(COMPOSEMAIL)::GetProcAddress(theApp.m_hPostalLib, "ComposeMailMessage");
|
|
theApp.m_fnUnRegisterMailClient =
|
|
(UNREGISTERMAIL)::GetProcAddress(theApp.m_hPostalLib, "UnRegisterMailClient");
|
|
theApp.m_fnShowMailBox =
|
|
(SHOWMAILBOX)::GetProcAddress(theApp.m_hPostalLib, "ShowMailBox");
|
|
theApp.m_fnShowMessageCenter =
|
|
(SHOWMESSAGECENTER)::GetProcAddress(theApp.m_hPostalLib, "ShowMessageCenter");
|
|
theApp.m_fnCloseMailSession =
|
|
(CLOSEMAIL)::GetProcAddress(theApp.m_hPostalLib, "CloseMailSession");
|
|
theApp.m_fnGetMenuItemString =
|
|
(GETMENUITEMSTRING)::GetProcAddress(theApp.m_hPostalLib, "GetMenuItemString");
|
|
|
|
if(theApp.m_fnOpenMailSession && theApp.m_fnComposeMailMessage && theApp.m_fnUnRegisterMailClient
|
|
&& theApp.m_fnShowMailBox && theApp.m_fnShowMessageCenter && theApp.m_fnCloseMailSession
|
|
&& theApp.m_fnGetMenuItemString && regProc)
|
|
{
|
|
POSTCODE status = (*regProc) (theApp.m_pHiddenFrame->m_hWnd, "Netscape Mail System");
|
|
if(status == POST_OK)
|
|
bLoadOK = TRUE;
|
|
else
|
|
MessageBox(NULL, szLoadString(IDS_ALTMAIL_REGISTER_FAILED), szLoadString(AFX_IDS_APP_TITLE), MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
else
|
|
MessageBox(NULL, szLoadString(IDS_ALTMAIL_MISSING_FUNCTIONS), szLoadString(AFX_IDS_APP_TITLE), MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
else
|
|
MessageBox(NULL, szLoadString(IDS_ALTMAIL_OLD_DLL), szLoadString(AFX_IDS_APP_TITLE), MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
else
|
|
{
|
|
#ifdef XP_WIN16
|
|
//In Win16 the LoadLibrary returns < 32 when it fails
|
|
//and since we check m_hPostalLib != NULL throughout
|
|
//the code let's set m_hPostalLib to NULL.
|
|
theApp.m_hPostalLib = NULL;
|
|
#endif
|
|
|
|
MessageBox(NULL, szLoadString(IDS_ALTMAIL_MISSING_DLL), szLoadString(AFX_IDS_APP_TITLE), MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
|
|
if(!bLoadOK && theApp.m_hPostalLib)
|
|
{
|
|
FreeLibrary(theApp.m_hPostalLib);
|
|
theApp.m_hPostalLib = NULL;
|
|
}
|
|
}
|
|
|
|
void FEU_CloseMapiLibrary()
|
|
{
|
|
if(theApp.m_fnCloseMailSession)
|
|
(*theApp.m_fnCloseMailSession) ();
|
|
if(theApp.m_fnUnRegisterMailClient)
|
|
(*theApp.m_fnUnRegisterMailClient) ();
|
|
if(theApp.m_hPostalLib)
|
|
FreeLibrary(theApp.m_hPostalLib);
|
|
theApp.m_hPostalLib = NULL;
|
|
|
|
// call init if reload
|
|
theApp.m_bInitMapi = TRUE;
|
|
|
|
// clear out all function pointers
|
|
theApp.m_fnOpenMailSession = NULL;
|
|
theApp.m_fnComposeMailMessage = NULL;
|
|
theApp.m_fnUnRegisterMailClient = NULL;
|
|
theApp.m_fnShowMailBox = NULL;
|
|
theApp.m_fnShowMessageCenter = NULL;
|
|
theApp.m_fnCloseMailSession = NULL;
|
|
theApp.m_fnGetMenuItemString = NULL;
|
|
}
|
|
|
|
#ifdef XP_WIN16
|
|
// 16 bits needs a GetDiskFreeSpace call.
|
|
BOOL GetDiskFreeSpace(LPCTSTR lpRootPathName, LPDWORD lpSectorsPerCluster,
|
|
LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters)
|
|
{
|
|
// Init.
|
|
*lpSectorsPerCluster = 0;
|
|
*lpBytesPerSector = 0;
|
|
*lpNumberOfFreeClusters = 0;
|
|
*lpTotalNumberOfClusters = 0;
|
|
|
|
// Saftey dance.
|
|
if(lpRootPathName == NULL) {
|
|
return(FALSE);
|
|
}
|
|
unsigned uDrive = 0;
|
|
if(strlen(lpRootPathName) > 1 && lpRootPathName[1] == ':') {
|
|
// Determine what drive we're looking at.
|
|
uDrive = toupper(*lpRootPathName) - 'A' + 1;
|
|
if(uDrive < 1 || uDrive > 26) {
|
|
// Use default drive....
|
|
uDrive = 0;
|
|
}
|
|
}
|
|
|
|
// Ask for amount of free disk space.
|
|
_diskfree_t dtFree;
|
|
memset(&dtFree, 0, sizeof(dtFree));
|
|
if(_dos_getdiskfree(uDrive, &dtFree)) {
|
|
// Call failure.
|
|
return(FALSE);
|
|
}
|
|
|
|
// assign what we found out.
|
|
*lpSectorsPerCluster = dtFree.sectors_per_cluster;
|
|
*lpBytesPerSector = dtFree.bytes_per_sector;
|
|
*lpNumberOfFreeClusters = dtFree.avail_clusters;
|
|
*lpTotalNumberOfClusters = dtFree.total_clusters;
|
|
|
|
// Success.
|
|
return(TRUE);
|
|
}
|
|
#endif
|
|
|
|
// See if content length can fit on a disk.
|
|
// If not, ask the user to confirm what they want (to write anyway).
|
|
// pFileName should contain the full path information for the file.
|
|
// All failures in this code mean success, actual errors should be
|
|
// found by other code attempting to open or write the file.
|
|
// Only on user denial to write will this code return failure.
|
|
|
|
// Implemented in femess.cpp, declared in msgcom.h
|
|
extern "C" uint32 FE_DiskSpaceAvailable (MWContext *context, const char *lpszPath );
|
|
|
|
BOOL FEU_ConfirmFreeDiskSpace(MWContext *pContext, const char *pFileName, int32 lContentLength)
|
|
{
|
|
// Absence of context means success since can't confirm space with user.
|
|
if(pContext == NULL) {
|
|
return(TRUE);
|
|
}
|
|
|
|
// Absence of a valid content length means success.
|
|
if(lContentLength <= 0) {
|
|
TRACE("Invalid content length, can't check free disk space.\n");
|
|
return(TRUE);
|
|
}
|
|
|
|
DWORD dwFreeSpace = FE_DiskSpaceAvailable( pContext, pFileName );
|
|
|
|
// If the length is greater than this, we need to confirm with the user on what to do.
|
|
if(dwFreeSpace < (DWORD)lContentLength) {
|
|
// Ask the user.
|
|
CString csAsk;
|
|
csAsk.LoadString(IDS_CONFIRM_DISK_SPACE);
|
|
size_t stSize = strlen(pFileName) + csAsk.GetLength() + 10;
|
|
char *pBuffer = new char[stSize];
|
|
if(pBuffer != NULL) {
|
|
sprintf(pBuffer, csAsk, pFileName);
|
|
BOOL bRetval = FE_Confirm(pContext, pBuffer);
|
|
delete [] pBuffer;
|
|
return(bRetval);
|
|
}
|
|
}
|
|
|
|
// Let it happen.
|
|
return(TRUE);
|
|
}
|
|
|
|
#if defined(XP_WIN16)
|
|
// There is literally no 32 bit equivalent for GetFreeSystemResources.
|
|
// Usually set pString to the file name, and iDigit to the line number.
|
|
// bBox controls wether or not a trace message will be used, or a dialog box.
|
|
void FEU_FreeResources(const char *pString, int iDigit, BOOL bBox)
|
|
{
|
|
UINT uSystem = GetFreeSystemResources(GFSR_SYSTEMRESOURCES);
|
|
UINT uGdi = GetFreeSystemResources(GFSR_GDIRESOURCES);
|
|
UINT uUser = GetFreeSystemResources(GFSR_USERRESOURCES);
|
|
|
|
char aBuffer[1024];
|
|
sprintf(aBuffer, "%s:%d\n%u System\n%u GDI\n%u User\n", pString, iDigit, uSystem, uGdi, uUser);
|
|
|
|
if(bBox) {
|
|
::MessageBox(NULL, aBuffer, "Resources", MB_OK);
|
|
}
|
|
TRACE(aBuffer);
|
|
}
|
|
#endif
|
|
|
|
// Remove all trailing backslashes from the string.
|
|
char *FEU_NoTrailingBackslash(char *pBackslash) {
|
|
if(pBackslash) {
|
|
int32 lTempLen = XP_STRLEN(pBackslash);
|
|
while(lTempLen) {
|
|
lTempLen--; // Back off one for comparison of the last char.
|
|
if(*(pBackslash + lTempLen) == '\\') {
|
|
// Knock it off.
|
|
*(pBackslash + lTempLen) = '\0';
|
|
}
|
|
else {
|
|
// No more backslashes to whack on the end.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(pBackslash);
|
|
}
|
|
|
|
// Replace all occurrences of original in pStr with new
|
|
void FEU_ReplaceChar(char *pStr, char original, char replace)
|
|
{
|
|
char *pFound;
|
|
|
|
while((pFound = strchr(pStr, original)) != NULL) {
|
|
*pFound = replace;
|
|
}
|
|
}
|
|
|
|
CString FEU_EscapeAmpersand(CString str)
|
|
{
|
|
|
|
CString newStr(""), leftStr, rightStr;
|
|
int nIndex;
|
|
rightStr = str;
|
|
|
|
while((nIndex = rightStr.Find('&')) != -1)
|
|
{
|
|
leftStr = rightStr.Left(nIndex);
|
|
newStr = newStr + leftStr;
|
|
newStr = newStr + "&&";
|
|
rightStr = rightStr.Right(rightStr.GetLength() - nIndex - 1);
|
|
}
|
|
|
|
// put in everything after the last ampersand.
|
|
newStr = newStr + rightStr;
|
|
return newStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write string values to the registry in the said location.
|
|
BOOL FEU_RegistryWizard(HKEY hRoot, const char *pKey, const char *pValue)
|
|
{
|
|
if(!pKey) {
|
|
return(FALSE);
|
|
}
|
|
|
|
HKEY hKey;
|
|
LONG lResultCreate = RegCreateKey(hRoot, pKey, &hKey);
|
|
|
|
if(lResultCreate != ERROR_SUCCESS) {
|
|
return(FALSE);
|
|
}
|
|
|
|
LONG lResultValue = RegSetValue(hKey, NULL, REG_SZ,
|
|
pValue ? pValue : "",
|
|
pValue ? XP_STRLEN(pValue) + 1 : 1);
|
|
|
|
LONG lResultClose = RegCloseKey(hKey);
|
|
|
|
if(lResultValue != ERROR_SUCCESS || lResultClose != ERROR_SUCCESS) {
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
// support quoted name.
|
|
// clapse multiple space is not quoted.
|
|
int FEU_ExtractCommaDilimetedFontName(const char *pArgList, int offSetByte, char *argItem)
|
|
{
|
|
int theQuote = '\0';
|
|
int length = 0;
|
|
int isLastSpace = 0;
|
|
|
|
const char *pTraverse = pArgList + offSetByte;
|
|
*argItem = '\0';
|
|
|
|
// Handle all stupidness.
|
|
if(pTraverse == NULL || *pTraverse == '\0' || offSetByte < 0) {
|
|
return(0); // no arg found
|
|
}
|
|
|
|
// skip leading space
|
|
while(*pTraverse && isspace(*pTraverse))
|
|
pTraverse++;
|
|
|
|
// See if this arg is quoted
|
|
theQuote = '\0';
|
|
if( *pTraverse == '"' || *pTraverse == '\'' ) {
|
|
theQuote = *pTraverse++;
|
|
}
|
|
|
|
if( theQuote != '\0' ) {
|
|
// quoted arg
|
|
while( *pTraverse ) {
|
|
if( *pTraverse != theQuote ) {
|
|
*argItem++ = * pTraverse++;
|
|
length++;
|
|
if( length >= MAXFONTFACENAME -1 ) {
|
|
// overflow
|
|
*(--argItem) = '\0';
|
|
return(-1);
|
|
}
|
|
} else {
|
|
*argItem = '\0'; // terminate
|
|
pTraverse++; // skip the quote
|
|
break;
|
|
}
|
|
}
|
|
|
|
// we passed the quote, now get over the comma
|
|
// ignore any char between closing quote and comma
|
|
while( *pTraverse && *pTraverse != ',' )
|
|
pTraverse++;
|
|
|
|
if( *pTraverse == ',' )
|
|
pTraverse++;
|
|
|
|
return( pTraverse - pArgList ); // offset for next arg
|
|
|
|
}
|
|
|
|
// arg without quote
|
|
while( *pTraverse && *pTraverse != ',' ) {
|
|
if( isLastSpace && isspace(*pTraverse) ) {
|
|
pTraverse++; // clapse multiple space
|
|
continue;
|
|
} else {
|
|
isLastSpace = isspace(*pTraverse);
|
|
*argItem++ = *pTraverse++;
|
|
length++;
|
|
if( length >= MAXFONTFACENAME -1 ) {
|
|
// overflow
|
|
*(--argItem) = '\0';
|
|
return(-1);
|
|
}
|
|
}
|
|
} // while( *pTraverse )
|
|
|
|
*argItem = '\0'; // terminator
|
|
// remove trailing space
|
|
while( --length && isspace( *(--argItem) ) )
|
|
*argItem = '\0'; // terminator
|
|
|
|
|
|
if( *pTraverse == ',' )
|
|
pTraverse++;
|
|
|
|
return( pTraverse - pArgList ); // offset for next arg
|
|
}
|
|
|
|
#ifdef not_support_quoted_font_face_name
|
|
// As the function indicates.
|
|
// Allocated return values to be freed by caller.
|
|
char *FEU_ExtractCommaDilimetedString(const char *pArgList, int iArgToExtract)
|
|
{
|
|
char *pRetval = NULL;
|
|
|
|
// Handle all stupidness.
|
|
if(pArgList == NULL || iArgToExtract <= 0) {
|
|
return(pRetval);
|
|
}
|
|
|
|
// Skip to comma of the arg in question.
|
|
const char *pTraverse = pArgList;
|
|
do {
|
|
iArgToExtract--;
|
|
if(iArgToExtract) {
|
|
// Search for next comma.
|
|
pTraverse = strchr(pTraverse, ',');
|
|
if(pTraverse) {
|
|
// Go past comma.
|
|
pTraverse++;
|
|
}
|
|
}
|
|
} while(iArgToExtract && pTraverse);
|
|
|
|
if(pTraverse) {
|
|
// Skip all whitespace before the string.
|
|
while(isspace(*pTraverse)) {
|
|
pTraverse++;
|
|
}
|
|
|
|
// Copy till next comma or end of string.
|
|
// Make sure not empty.
|
|
char *pEnd = strchr(pTraverse, ',');
|
|
int iAlloc = 0;
|
|
if(pEnd == NULL) {
|
|
iAlloc = strlen(pTraverse) + 1;
|
|
}
|
|
else {
|
|
iAlloc = pEnd - pTraverse + 1;
|
|
}
|
|
|
|
// If we've something to allocate.
|
|
if(iAlloc) {
|
|
pRetval = (char *)XP_ALLOC(iAlloc);
|
|
if(pRetval) {
|
|
// clear it out.
|
|
memset(pRetval, 0, iAlloc);
|
|
|
|
// Copy over the amount -1.
|
|
strncpy(pRetval, pTraverse, iAlloc - 1);
|
|
|
|
// Walk backwards through the string, clearing off
|
|
// any space.
|
|
pEnd = pRetval + iAlloc - 2;
|
|
while(pEnd >= pRetval && isspace(*pEnd)) {
|
|
*pEnd = '\0';
|
|
pEnd--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
#endif // not_support_quoted_font_face_name
|
|
|
|
// As the function indicates.
|
|
// Allocated return values to be freed by caller.
|
|
char *FEU_ExtractCommaDilimetedQuotedString(const char *pArgList, int iArgToExtract) {
|
|
char *pRetval = NULL;
|
|
|
|
// Handle all stupidness.
|
|
if(pArgList == NULL || iArgToExtract <= 0) {
|
|
return(pRetval);
|
|
}
|
|
|
|
// Find the first argument.
|
|
// First arg will be right after the first quote.
|
|
const char *pTraverse = pArgList;
|
|
while(*pTraverse != '\"' && *pTraverse != '\0') {
|
|
pTraverse++;
|
|
}
|
|
|
|
// If we have an argument.
|
|
if(*pTraverse == '\"') {
|
|
pTraverse++;
|
|
|
|
// Okay, we need to find out where the ending comma exists.
|
|
int iQuoteLevel = 1;
|
|
const char *pQuote = pTraverse;
|
|
while(iQuoteLevel) {
|
|
// Go until we reach another quote.
|
|
while(*pQuote != '\"' && *pQuote != '\0') {
|
|
pQuote++;
|
|
}
|
|
|
|
// Did we reach a quote?
|
|
if(*pQuote == '\"') {
|
|
pQuote++;
|
|
|
|
// Assume this is an ending quote if we can find a comma before another quote.
|
|
iQuoteLevel--;
|
|
if(iQuoteLevel == 0) {
|
|
// Begin ananlysis.
|
|
const char *pComma = pQuote;
|
|
while(*pComma != '\"' && *pComma != ',' && *pComma != '\0') {
|
|
pComma++;
|
|
}
|
|
|
|
// What are we lookit at?
|
|
if(*pComma == '\"') {
|
|
// Another quote.
|
|
// Up the quote count by 2.
|
|
iQuoteLevel += 2;
|
|
}
|
|
else if(*pComma == ',') {
|
|
// We're out of here!
|
|
// Is this the first argument, though?
|
|
if(iArgToExtract != 1) {
|
|
// What they want is a different one.
|
|
// Go recursive and let them pick up where we left off.
|
|
pRetval = FEU_ExtractCommaDilimetedQuotedString(pComma + 1, iArgToExtract - 1);
|
|
}
|
|
else {
|
|
// We have the argument they want.
|
|
// Exact dimenstion of the argument are from pTraverse to pQuote - 2;
|
|
// Cathch the boundry case of "",
|
|
if(pQuote - 2 >= pTraverse) {
|
|
int iLength = pQuote - pTraverse;
|
|
pRetval = (char *)XP_ALLOC(iLength);
|
|
if(pRetval) {
|
|
memset(pRetval, 0, iLength);
|
|
|
|
int iCounter = 0;
|
|
while(pTraverse <= pQuote - 2) {
|
|
pRetval[iCounter] = *pTraverse;
|
|
pTraverse++;
|
|
iCounter++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// End of string, get out of while loop.
|
|
// However, if this is the only argument we're looking for, we may already have
|
|
// what we need.
|
|
if(iArgToExtract == 1) {
|
|
// We have the argument they want.
|
|
// Exact dimenstion of the argument are from pTraverse to pQuote - 2;
|
|
// Cathch the boundry case of "",
|
|
if(pQuote - 2 >= pTraverse) {
|
|
int iLength = pQuote - pTraverse;
|
|
pRetval = (char *)XP_ALLOC(iLength);
|
|
if(pRetval) {
|
|
memset(pRetval, 0, iLength);
|
|
|
|
int iCounter = 0;
|
|
while(pTraverse <= pQuote - 2) {
|
|
pRetval[iCounter] = *pTraverse;
|
|
pTraverse++;
|
|
iCounter++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// end of string, just get out of the while loop.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FEU_TransBlt
|
|
*
|
|
* PARAMETERS:
|
|
* pSrcDC - pointer to source DC (with selected image)
|
|
* pDstDC - pointer to destination DC (where image is to be drawn)
|
|
* ptSrc - source x,y coordinates
|
|
* ptDst - destination x,y coordinates
|
|
* nWidth - image width
|
|
* nHeight - image height
|
|
* rgbTrans - transparent (background) color = RGB(255, 0, 255)
|
|
*
|
|
* RETURNS:
|
|
* TRUE if successful.
|
|
*
|
|
* DESCRIPTION:
|
|
* This function is called to do a transparent BitBlt. The background
|
|
* or transparent color is given by rgbTrans, with the default being
|
|
* pink {RGB(255, 0, 255)}. Pixels of this color will be masked out, so
|
|
* that the image is drawn without disturbing the destination.
|
|
*
|
|
* Note that all masking operations are done in a memory DC to avoid
|
|
* flicker. pDstDC should be an actual screen DC.
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOL FEU_TransBlt(CDC * pSrcDC, CDC * pDstDC, const CPoint & ptSrc,
|
|
const CPoint & ptDst, int nWidth, int nHeight, HPALETTE hPalette,
|
|
const COLORREF rgbTrans /*= RGB(255, 0, 255)*/)
|
|
{
|
|
return FEU_TransBlt( pDstDC->m_hDC, ptDst.x, ptDst.y, nWidth, nHeight,
|
|
pSrcDC->m_hDC, ptSrc.x, ptSrc.y, hPalette, rgbTrans );
|
|
}
|
|
|
|
// More useful version that migrates more sanely from BitBlt.
|
|
|
|
BOOL FEU_TransBlt(HDC hDstDC, int nXDest, int nYDest, int nWidth, int nHeight,
|
|
HDC hSrcDC, int nXSrc, int nYSrc, HPALETTE hPalette, COLORREF rgbTrans )
|
|
{
|
|
|
|
BOOL bRtn = TRUE;
|
|
|
|
// We'll paint our bitmap using the "true mask" method for transparency.
|
|
// We assume a pre-designated color for the background (transparent) color,
|
|
// and create our monochrome mask at run time.
|
|
|
|
// Create mask for transparent blits
|
|
HPALETTE hOldPal = ::SelectPalette(hSrcDC, hPalette, FALSE);
|
|
// ::RealizePalette(hSrcDC);
|
|
HDC hMaskDC = ::CreateCompatibleDC(hDstDC);
|
|
HBITMAP hbmMask = ::CreateBitmap(nWidth, nHeight, 1, 1, NULL);
|
|
HBITMAP hOldMaskBmp = (HBITMAP) ::SelectObject(hMaskDC, hbmMask);
|
|
COLORREF rgbOldBk = ::SetBkColor(hSrcDC, rgbTrans);
|
|
::BitBlt(hMaskDC, 0, 0, nWidth, nHeight, hSrcDC, nXSrc, nYSrc, SRCCOPY);
|
|
::SetBkColor(hSrcDC, rgbOldBk);
|
|
::SelectPalette(hSrcDC, hOldPal, TRUE);
|
|
|
|
// First, copy the existing image from the destination to memory for
|
|
// flicker free painting.
|
|
HDC hMemDC = ::CreateCompatibleDC(hDstDC);
|
|
HBITMAP hbmMem = ::CreateCompatibleBitmap(hDstDC, nWidth, nHeight);
|
|
HBITMAP hOldMemBmp = (HBITMAP) ::SelectObject(hMemDC, hbmMem);
|
|
::BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDstDC, nXDest, nYDest, SRCCOPY);
|
|
|
|
// Next, blit our bitmap, the mask, then our bitmap again to the memory
|
|
// DC using the proper raster ops.
|
|
COLORREF rgbOldTxt = ::SetTextColor(hMemDC, PALETTERGB(0, 0, 0));
|
|
rgbOldBk = SetBkColor(hMemDC, PALETTERGB(255, 255, 255));
|
|
::BitBlt(hMemDC, 0, 0, nWidth, nHeight, hSrcDC, nXSrc, nYSrc, SRCINVERT);
|
|
::BitBlt(hMemDC, 0, 0, nWidth, nHeight, hMaskDC, 0, 0, SRCAND);
|
|
::BitBlt(hMemDC, 0, 0, nWidth, nHeight, hSrcDC, nXSrc, nYSrc, SRCINVERT);
|
|
::SetTextColor(hMemDC, rgbOldTxt);
|
|
::SetBkColor(hMemDC, rgbOldBk);
|
|
|
|
// Finally, blit from memory DC back to the destination
|
|
bRtn = ::BitBlt(hDstDC, nXDest, nYDest, nWidth, nHeight, hMemDC, 0, 0,
|
|
SRCCOPY);
|
|
|
|
// Cleanup
|
|
::SelectObject(hMaskDC, hOldMaskBmp);
|
|
VERIFY(::DeleteDC(hMaskDC));
|
|
VERIFY(::DeleteObject(hbmMask));
|
|
|
|
::SelectObject(hMemDC, hOldMemBmp);
|
|
VERIFY(::DeleteDC(hMemDC));
|
|
VERIFY(::DeleteObject(hbmMem));
|
|
|
|
return(bRtn);
|
|
} // END OF FUNCTION FEU_TransBlt()
|
|
|
|
// This function create because no one knows how to use SetWindowPlacement
|
|
// correctly.
|
|
void FEU_InitWINDOWPLACEMENT(HWND hWindow, WINDOWPLACEMENT *pWindowPlacement)
|
|
{
|
|
// Safety
|
|
if(!pWindowPlacement) {
|
|
return;
|
|
}
|
|
|
|
// Thrash to zero.
|
|
memset(pWindowPlacement, 0, sizeof(WINDOWPLACEMENT));
|
|
|
|
// Set the length member.
|
|
pWindowPlacement->length = sizeof(WINDOWPLACEMENT);
|
|
|
|
// Safety
|
|
if(!hWindow) {
|
|
return;
|
|
}
|
|
|
|
// Initialize the structure with the current window settings.
|
|
BOOL bGotIt = ::GetWindowPlacement(hWindow, pWindowPlacement);
|
|
ASSERT(bGotIt);
|
|
|
|
// Hacker now free to change members that need to be changed without
|
|
// thrashing other stuff too.
|
|
}
|
|
|
|
// Mouse timer handler (to handle scrolling selections).
|
|
MouseTimerData::MouseTimerData(MWContext *pContext)
|
|
{
|
|
// By default treat as a context notification.
|
|
m_pContext = pContext;
|
|
m_pType = m_ContextNotify;
|
|
}
|
|
|
|
void FEU_MouseTimer(void *vpReallyMouseTimerData)
|
|
{
|
|
// Cast.
|
|
MouseTimerData *pData = (MouseTimerData *)vpReallyMouseTimerData;
|
|
|
|
// Decide what to do by type.
|
|
if(pData->m_pType == MouseTimerData::m_ContextNotify) {
|
|
// If the left button is down, we need to set up a timer to
|
|
// call the mouse move function again so that scrolling selections
|
|
// work correctly.
|
|
// GARRETT: PANECX will want the mouse stuff.
|
|
if(XP_IsContextInList(pData->m_pContext) &&
|
|
ABSTRACTCX(pData->m_pContext) &&
|
|
ABSTRACTCX(pData->m_pContext)->IsFrameContext()) {
|
|
CWinCX *pWinCX = WINCX(pData->m_pContext);
|
|
|
|
// Don't do autoscroll if left button isn't down and isn't
|
|
// already an timout registered.
|
|
if(pWinCX->m_bLBDown && !pWinCX->m_bScrollingTimerSet) {
|
|
// Set up the timer.
|
|
MouseTimerData *pLater = new MouseTimerData(pData->m_pContext);
|
|
if(pLater) {
|
|
// Manually set to be a timer notification.
|
|
pLater->m_pType = MouseTimerData::m_TimerNotify;
|
|
|
|
// Set that the context has a scrolling timeout event.
|
|
pWinCX->m_bScrollingTimerSet = TRUE;
|
|
|
|
// Set the timer to call us back in X number milliseconds.
|
|
FE_SetTimeout(FEU_MouseTimer, (void *)pLater, 100);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Do not delete the passed in data.
|
|
// Up to the caller to do so.
|
|
}
|
|
else if(pData->m_pType == MouseTimerData::m_TimerNotify) {
|
|
// If the left button is still down, we need to act like a mouse
|
|
// move occurred on the context so scrolling selections work.
|
|
if(XP_IsContextInList(pData->m_pContext) &&
|
|
ABSTRACTCX(pData->m_pContext) &&
|
|
ABSTRACTCX(pData->m_pContext)->IsFrameContext()) {
|
|
CWinCX *pWinCX = WINCX(pData->m_pContext);
|
|
// We need to remove the previously allocated mouse data that
|
|
// we allocated ourselves.
|
|
delete pData;
|
|
|
|
if(pWinCX->m_bLBDown && pWinCX->m_bScrollingTimerSet) {
|
|
// Clear the scrolling timer flag (do before call or won't
|
|
// set another timeout).
|
|
pWinCX->m_bScrollingTimerSet = FALSE;
|
|
|
|
// This will set up another timer if needed.
|
|
BOOL bReturnImmediately = FALSE;
|
|
pWinCX->OnMouseMoveCX(pWinCX->m_uMouseFlags, pWinCX->m_cpMMove, bReturnImmediately);
|
|
if(bReturnImmediately) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/// Mouse timer handler (to handle moves outside the window.).
|
|
MouseMoveTimerData::MouseMoveTimerData(MWContext *pContext)
|
|
{
|
|
// By default treat as a context notification.
|
|
m_pContext = pContext;
|
|
}
|
|
|
|
void FEU_MouseMoveTimer(void *vpReallyMouseMoveTimerData)
|
|
{
|
|
// Cast.
|
|
MouseMoveTimerData *pData = (MouseMoveTimerData *)vpReallyMouseMoveTimerData;
|
|
if (!pData)
|
|
return;
|
|
|
|
if(XP_IsContextInList(pData->m_pContext) &&
|
|
ABSTRACTCX(pData->m_pContext) &&
|
|
ABSTRACTCX(pData->m_pContext)->IsFrameContext()) {
|
|
CWinCX *pWinCX = WINCX(pData->m_pContext);
|
|
|
|
if(!pWinCX->m_bMouseMoveTimerSet) {
|
|
// Set up the timer.
|
|
MouseMoveTimerData *pLater = new MouseMoveTimerData(pData->m_pContext);
|
|
if(pLater) {
|
|
// Set that the context has a mousemove timeout event.
|
|
pWinCX->m_bMouseMoveTimerSet = TRUE;
|
|
|
|
// Set the timer to call us back in X number milliseconds.
|
|
FE_SetTimeout(FEU_MouseMoveTimer, (void *)pLater, 200);
|
|
}
|
|
}
|
|
|
|
else {
|
|
POINT mp;
|
|
// get mouse position
|
|
::GetCursorPos(&mp);
|
|
|
|
if ((::WindowFromPoint(mp) != pWinCX->GetPane()) && !pWinCX->m_bLBDown) {
|
|
// We've moved outside the window. Stop looping the timer and
|
|
// send a simulated mousemove to the view.
|
|
delete pData;
|
|
|
|
::ScreenToClient(pWinCX->GetPane(), &mp);
|
|
|
|
BOOL bReturnImmediately = FALSE;
|
|
pWinCX->OnMouseMoveCX(pWinCX->m_uMouseFlags, mp, bReturnImmediately);
|
|
|
|
pWinCX->m_bMouseMoveTimerSet = FALSE;
|
|
}
|
|
else {
|
|
// We're still in the window. Set another timer.
|
|
FE_SetTimeout(FEU_MouseMoveTimer, (void *)pData, 200);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Context wants to have idle processing check to see if any actions
|
|
// need be taken with it.
|
|
class MWContextList {
|
|
public:
|
|
MWContext *m_pContext;
|
|
MWContextList *m_pNext;
|
|
};
|
|
MWContextList *listIdleContexts = NULL;
|
|
void *timerIdleContexts = NULL;
|
|
#define IDLETIMEOUT 50
|
|
|
|
void idleTimer(void *pNULL)
|
|
{
|
|
timerIdleContexts = NULL;
|
|
if(FEU_DoIdleProcessing()) {
|
|
timerIdleContexts = FE_SetTimeout(idleTimer, NULL, IDLETIMEOUT);
|
|
}
|
|
}
|
|
|
|
void FEU_RequestIdleProcessing(MWContext *pContext)
|
|
{
|
|
// Make sure not already in list.
|
|
MWContextList *pTraverse = listIdleContexts;
|
|
while(pTraverse) {
|
|
if(pTraverse->m_pContext == pContext) {
|
|
// Already here, don't do it.
|
|
return;
|
|
}
|
|
pTraverse = pTraverse->m_pNext;
|
|
}
|
|
|
|
// Not in list, add to tail.
|
|
MWContextList *pNewEntry = new MWContextList();
|
|
if(pNewEntry) {
|
|
MWContextList **ppNext = &listIdleContexts;
|
|
while(*ppNext) {
|
|
ppNext = &((*ppNext)->m_pNext);
|
|
}
|
|
|
|
pNewEntry->m_pNext = NULL;
|
|
pNewEntry->m_pContext = pContext;
|
|
*ppNext = pNewEntry;
|
|
}
|
|
|
|
// If we don't have a timer, then start one up.
|
|
if(timerIdleContexts == NULL) {
|
|
timerIdleContexts = FE_SetTimeout(idleTimer, NULL, IDLETIMEOUT);
|
|
}
|
|
}
|
|
|
|
BOOL FEU_DoIdleProcessing()
|
|
{
|
|
// Check our list and do one action per context at a time.
|
|
// Remove the context from the list if no known action need be
|
|
// taken with it.
|
|
MWContextList *pEntry = listIdleContexts;
|
|
if(pEntry) {
|
|
// Do NOT use else ifs. Instead use "if(bNoAction &&" everywhere
|
|
// Must set bNoAction to FALSE after an action is taken.
|
|
BOOL bNoAction = TRUE;
|
|
|
|
// Context still valid?
|
|
// Could have been blown away since it registered.
|
|
if(bNoAction && XP_IsContextInList(pEntry->m_pContext)) {
|
|
// Front end or XP context (XP not handled).
|
|
// Do not check the destroyed flag here, or contexts never
|
|
// get really freed off, instead tighten the called code.
|
|
if(bNoAction && ABSTRACTCX(pEntry->m_pContext)) {
|
|
CAbstractCX *pCX = ABSTRACTCX(pEntry->m_pContext);
|
|
|
|
// Lastly is the don't care case, abstract only.
|
|
if(bNoAction) {
|
|
// Do an interrupt if needed.
|
|
if(bNoAction && pCX->m_bIdleInterrupt == TRUE) {
|
|
bNoAction = FALSE;
|
|
pCX->Interrupt();
|
|
}
|
|
// Check for nice reloading.
|
|
if(bNoAction && pCX->GetContext()->reSize) {
|
|
bNoAction = FALSE;
|
|
pCX->NiceReload();
|
|
}
|
|
// Check for self destruct.
|
|
if(bNoAction && pCX->m_bIdleDestroy == TRUE) {
|
|
bNoAction = FALSE;
|
|
pCX->NiceDestroyContext();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Take it out of the list and free it since it's now idle.
|
|
if(bNoAction) {
|
|
// Removal from list.
|
|
listIdleContexts = pEntry->m_pNext;
|
|
// Removal from the universe.
|
|
delete pEntry;
|
|
}
|
|
}
|
|
|
|
// Return wether or not more entries exist (more time is needed).
|
|
return(listIdleContexts == NULL ? FALSE : TRUE);
|
|
}
|
|
|
|
// Function to handle client pull.
|
|
class ClientPullTimerData {
|
|
public:
|
|
MWContext *m_pContext;
|
|
URL_Struct *m_pUrl;
|
|
History_entry *m_pVerifyHistory;
|
|
int m_iFormatOut;
|
|
BOOL m_bCanInterrupt;
|
|
};
|
|
void FEU_ClientPull(MWContext *pContext, uint32 ulMilliseconds, URL_Struct *pUrl, int iFormatOut, BOOL bCanInterrupt)
|
|
{
|
|
BOOL bSetToPull = FALSE;
|
|
|
|
// Safety dance.
|
|
if(pUrl && pContext &&
|
|
ABSTRACTCX(pContext) &&
|
|
!ABSTRACTCX(pContext)->IsDestroyed()) {
|
|
CAbstractCX *pCX = ABSTRACTCX(pContext);
|
|
|
|
// If we've already got a client pull timeout for the context, we
|
|
// should clear it (only want one of these at any given time).
|
|
void *pClearMe = pCX->m_pClientPullTimeout;
|
|
if(pClearMe) {
|
|
pCX->m_pClientPullTimeout = NULL;
|
|
FE_ClearTimeout(pClearMe);
|
|
}
|
|
|
|
// Same for the timeout's argument pointer, but it can be non-null
|
|
// even when the timeout pointer was null (if FEU_ClientPullNow
|
|
// calls us directly to try again in a second, and then returns
|
|
// early without deleting pData or clearing m_pClientPullData).
|
|
// Instead of freeing it and then immediately allocating a new one,
|
|
// just reuse it, but take care further below to clear pCX's
|
|
// pointer to it before deleting it, if FE_SetTimeout fails.
|
|
ClientPullTimerData *pData =
|
|
(ClientPullTimerData *)pCX->m_pClientPullData;
|
|
if(!pData) {
|
|
// Create a new client pull structure.
|
|
pData = new ClientPullTimerData();
|
|
}
|
|
|
|
if(pData) {
|
|
// Fill in the timer data.
|
|
pData->m_pContext = pCX->GetContext();
|
|
pData->m_pUrl = pUrl;
|
|
pData->m_pVerifyHistory = pCX->GetContext()->hist.cur_doc_ptr;
|
|
pData->m_iFormatOut = iFormatOut;
|
|
pData->m_bCanInterrupt = bCanInterrupt;
|
|
|
|
// Tell the context about it.
|
|
// Register the timeout.
|
|
pCX->m_pClientPullTimeout =
|
|
FE_SetTimeout(FEU_ClientPullNow, (void *)pData, ulMilliseconds);
|
|
|
|
// Looks like this will work.
|
|
if(pCX->m_pClientPullTimeout) {
|
|
pCX->m_pClientPullData = (void *)pData;
|
|
bSetToPull = TRUE;
|
|
}
|
|
else {
|
|
pCX->m_pClientPullData = NULL;
|
|
delete pData;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!bSetToPull && pUrl) {
|
|
// Can't do client pull on this context.
|
|
NET_FreeURLStruct(pUrl);
|
|
}
|
|
}
|
|
|
|
void FEU_ClientPullNow(void *vpReallyClientPullTimerData)
|
|
{
|
|
ClientPullTimerData *pData = (ClientPullTimerData *)vpReallyClientPullTimerData;
|
|
BOOL bPulledUrl = FALSE;
|
|
|
|
// Is the context still around?
|
|
if(XP_IsContextInList(pData->m_pContext) &&
|
|
ABSTRACTCX(pData->m_pContext) &&
|
|
!ABSTRACTCX(pData->m_pContext)->IsDestroyed()) {
|
|
CAbstractCX *pCX = ABSTRACTCX(pData->m_pContext);
|
|
|
|
// There must not be more than one pull timeout pending!
|
|
XP_ASSERT(pData == pCX->m_pClientPullData);
|
|
|
|
// We are called only via FE_SetTimeout, so clear this pointer now
|
|
// before it dangles at free memory.
|
|
pCX->m_pClientPullTimeout = NULL;
|
|
|
|
// Are we on the same history entry?
|
|
if(pCX->GetContext()->hist.cur_doc_ptr == pData->m_pVerifyHistory) {
|
|
|
|
// Client pull isn't allowed to interrupt.
|
|
if(!pData->m_bCanInterrupt && XP_IsContextBusy(pCX->GetContext())) {
|
|
// Try again in a second.
|
|
FEU_ClientPull(pCX->GetContext(), 1000, pData->m_pUrl, pData->m_iFormatOut, FALSE);
|
|
|
|
// Old data, if present, freed in FEU_ClientPull.
|
|
// We can not continue, as the old data may now be gone,
|
|
// and we look at the old timer pull data further below.
|
|
return;
|
|
}
|
|
|
|
// Clear the members in the context before load,
|
|
// as they may be set again instantly and we
|
|
// get a double free below.
|
|
pCX->m_pClientPullData = NULL;
|
|
|
|
// Ask for it now.
|
|
pCX->GetUrl(pData->m_pUrl, pData->m_iFormatOut);
|
|
|
|
// Set that we've requested it.
|
|
bPulledUrl = TRUE;
|
|
}
|
|
else {
|
|
// Clear m_pClientPullData because we're about to free pData.
|
|
pCX->m_pClientPullData = NULL;
|
|
}
|
|
}
|
|
|
|
if(!bPulledUrl) {
|
|
// Free off the URL struct ourselves.
|
|
NET_FreeURLStruct(pData->m_pUrl);
|
|
}
|
|
|
|
// Free off the timer data.
|
|
delete pData;
|
|
}
|
|
|
|
// Cause the global history to be saved periodically.
|
|
void FEU_GlobalHistoryTimeout(void *pNULL)
|
|
{
|
|
// Set the next timeout.
|
|
FE_SetTimeout(FEU_GlobalHistoryTimeout, NULL, 120000UL);
|
|
|
|
// Flush it, if not first call.
|
|
if(!pNULL) {
|
|
GH_SaveGlobalHistory();
|
|
}
|
|
}
|
|
|
|
// This routine will return the handle of the pop-up menu whose first
|
|
// menu item has the specified command ID
|
|
HMENU FEU_FindSubmenu(HMENU hMenu, UINT nFirstCmdID)
|
|
{
|
|
int nCount = ::GetMenuItemCount(hMenu);
|
|
|
|
for (int i = 0; i < nCount; i++) {
|
|
HMENU hSubmenu = ::GetSubMenu(hMenu, i);
|
|
|
|
if (hSubmenu && (::GetMenuItemID(hSubmenu, 0) == nFirstCmdID))
|
|
return hSubmenu;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
char *pTipText = NULL;
|
|
|
|
// Get a resource string and extract the tooltip portion
|
|
// if a '\n' is found in the string
|
|
// USE RESULT QUICKLY!
|
|
// (String is in our temp buffer and should not be FREEd)
|
|
char * FEU_GetToolTipText( UINT nID )
|
|
{
|
|
pTipText = szLoadString(nID);
|
|
if( ! *pTipText ){
|
|
return NULL;
|
|
}
|
|
|
|
// Scan for the '\n' separating status line hints from
|
|
// the tooltip text - use latter if found
|
|
char *pTemp = pTipText;
|
|
do {
|
|
if( *pTemp == '\n' && *(pTemp+1) != '\0' ){
|
|
pTipText = pTemp+1;
|
|
// Find a second "\n" and terminate string there
|
|
char * pBreak = strchr(pTipText, '\n');
|
|
if( pBreak )
|
|
*pBreak = '\0';
|
|
break;
|
|
}
|
|
pTemp++;
|
|
} while( *pTemp != '\0' );
|
|
|
|
return pTipText;
|
|
}
|
|
|
|
|
|
char *FE_FindFileExt(char * path)
|
|
{
|
|
char *pRetval = NULL;
|
|
if(path) {
|
|
int len = strlen(path);
|
|
|
|
char *ptr = path + len - 1;
|
|
while ((*ptr != '.') && (len > 0)) {
|
|
len--;
|
|
if (len > 0) ptr--;
|
|
}
|
|
if (len > 0) {
|
|
pRetval = ptr;
|
|
}
|
|
}
|
|
return(pRetval);
|
|
}
|
|
|
|
void FE_LongNameToDosName(char* dest, char* source)
|
|
{
|
|
ASSERT(dest && source);
|
|
if(dest) {
|
|
*dest = '\0';
|
|
if(source) {
|
|
char *ext = FE_FindFileExt(source);
|
|
|
|
if (ext && (ext - source) > 8) {
|
|
// the Name is > dos file name
|
|
strncpy(dest, source, 8);
|
|
strncpy(&dest[8],ext, 4);
|
|
dest[12] = '\0';
|
|
}
|
|
else {
|
|
strcpy(dest, source);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// This function will return FALSE, if we do not want to use the default type that libnet provide.
|
|
|
|
BOOL FE_FileType(char * path,
|
|
char * mimeType,
|
|
char * encoding)
|
|
{
|
|
|
|
// try to get the extension from the end of the string.
|
|
char *ext = FE_FindFileExt(path);
|
|
if (ext) {
|
|
ext++; // move pass the '.';
|
|
|
|
NET_cdataStruct *cdata;
|
|
XP_List * list_ptr;
|
|
|
|
list_ptr = cinfo_MasterListPointer();
|
|
while((cdata = (NET_cdataStruct *) XP_ListNextObject(list_ptr)) != NULL)
|
|
{
|
|
if(cdata->ci.type && !strcasecomp(mimeType, cdata->ci.type)){
|
|
for (int i = 0; i < cdata->num_exts; i++) {
|
|
if (strcasecomp(ext, cdata->exts[i]) == 0)
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL FEU_IsConferenceAvailable(void)
|
|
{
|
|
CString install;
|
|
|
|
#ifdef WIN32
|
|
install = FEU_GetInstallationDirectory(szLoadString(IDS_CONFERENCE_REGISTRY), szLoadString(IDS_PATHNAME));
|
|
#else ifdef XP_WIN16
|
|
install = FEU_GetInstallationDirectory(szLoadString(IDS_CONFERENCE),szLoadString(IDS_INSTALL_DIRECTORY));
|
|
#endif
|
|
|
|
return (!install.IsEmpty());
|
|
}
|
|
|
|
BOOL FEU_IsCalendarAvailable(void)
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
CString calRegistry;
|
|
|
|
calRegistry.LoadString(IDS_CALENDAR_REGISTRY);
|
|
|
|
calRegistry = FEU_GetCurrentRegistry(calRegistry);
|
|
if(calRegistry.IsEmpty())
|
|
return FALSE;
|
|
CString install = FEU_GetInstallationDirectory(calRegistry, szLoadString(IDS_INSTALL_DIRECTORY));
|
|
#else
|
|
|
|
CString install = FEU_GetInstallationDirectory(szLoadString(IDS_CALENDAR), szLoadString(IDS_INSTALL_DIRECTORY));
|
|
|
|
#endif
|
|
|
|
return (!install.IsEmpty());
|
|
|
|
|
|
}
|
|
|
|
BOOL FEU_IsIBMHostOnDemandAvailable(void)
|
|
{
|
|
|
|
|
|
#ifdef _WIN32
|
|
CString ibmHostRegistry;
|
|
|
|
ibmHostRegistry.LoadString(IDS_3270_REGISTRY);
|
|
|
|
ibmHostRegistry = FEU_GetCurrentRegistry(ibmHostRegistry);
|
|
if(ibmHostRegistry.IsEmpty())
|
|
return FALSE;
|
|
|
|
CString install = FEU_GetInstallationDirectory(ibmHostRegistry, szLoadString(IDS_INSTALL_DIRECTORY));
|
|
#else
|
|
|
|
CString install = FEU_GetInstallationDirectory(szLoadString(IDS_3270), szLoadString(IDS_INSTALL_DIRECTORY));
|
|
|
|
#endif
|
|
|
|
return (!install.IsEmpty());
|
|
|
|
}
|
|
|
|
BOOL FEU_IsAimAvailable(void)
|
|
{
|
|
BOOL success = FALSE;
|
|
char szPath[_MAX_PATH + 1];
|
|
char shortPath[_MAX_PATH + 1];
|
|
|
|
CString install("");
|
|
unsigned long cbData = sizeof(szPath);
|
|
|
|
#ifdef _WIN32
|
|
CString aimRegistry;
|
|
|
|
aimRegistry.LoadString(IDS_AIM_REGISTRY);
|
|
|
|
HKEY aimKey;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, aimRegistry, 0, KEY_QUERY_VALUE, &aimKey) != ERROR_SUCCESS)
|
|
return FALSE;
|
|
|
|
success = (RegQueryValueEx(aimKey, 0, NULL, NULL, (LPBYTE) szPath, &cbData) == ERROR_SUCCESS);
|
|
|
|
GetShortPathName(szPath, shortPath, _MAX_PATH+1);
|
|
install = shortPath;
|
|
|
|
RegCloseKey(aimKey);
|
|
#endif // _WIN32
|
|
|
|
#ifdef XP_WIN16
|
|
// Do the right thing
|
|
GetPrivateProfileString("InstallRoot", "Path", "none", szPath, cbData, "aim.ini");
|
|
install = szPath;
|
|
if (install != "none")
|
|
{
|
|
success = TRUE;
|
|
install = install + "\\aim.exe";
|
|
}
|
|
#endif // XP_WIN16
|
|
|
|
if (success)
|
|
{
|
|
char szKey[_MAX_EXT + 1]; // space for '.'
|
|
char szClass[128];
|
|
LONG lResult;
|
|
LONG lcb;
|
|
|
|
// Look up the file association key which maps a file extension
|
|
// to a file class
|
|
wsprintf(szKey, ".%s", "aim");
|
|
|
|
lcb = sizeof(szClass);
|
|
lResult = RegQueryValue(HKEY_CLASSES_ROOT, szKey, szClass, &lcb);
|
|
|
|
#ifdef _WIN32
|
|
ASSERT(lResult != ERROR_MORE_DATA);
|
|
#endif
|
|
if (lResult != ERROR_SUCCESS || lcb <= 1)
|
|
{
|
|
// Configure the MIME type, download prompt, etc. etc.
|
|
NET_cdataStruct *launchData = fe_NewFileType("AOL Instant Messenger Launch",
|
|
"aim",
|
|
"application/x-aim",
|
|
install); // Create and register the file type
|
|
CHelperApp *pHelperApp = (CHelperApp *)launchData->ci.fe_data;
|
|
pHelperApp->how_handle = HANDLE_SHELLEXECUTE;
|
|
}
|
|
else
|
|
{
|
|
// The key exists but the application may be stale, i.e., it may have changed
|
|
// on us. Just write out the current path to the aimfile key.
|
|
SetShellOpenCommand("aimfile", install);
|
|
}
|
|
|
|
// Always write out the defaulticon info for Win32, since the AIM app may have moved.
|
|
#ifdef _WIN32
|
|
CString iconPath = install + ",0";
|
|
HKEY iconKey;
|
|
if (RegCreateKey(HKEY_CLASSES_ROOT, "aimfile\\DefaultIcon", &iconKey) ==
|
|
ERROR_SUCCESS)
|
|
{
|
|
RegSetValue(iconKey, "", REG_SZ, iconPath, iconPath.GetLength());
|
|
RegCloseKey(iconKey);
|
|
}
|
|
#endif // _WIN32
|
|
|
|
CString profileLaunch = theApp.m_UserDirectory + "\\launch.aim";
|
|
FILE* fp = fopen(profileLaunch, "r");
|
|
if (fp == NULL)
|
|
{
|
|
// Need to create launch.aim file in the user's dir.
|
|
fp = fopen(profileLaunch, "w");
|
|
fprintf(fp, "DWH\n");
|
|
fclose(fp);
|
|
|
|
// Need to add to personal toolbar
|
|
CString convLaunch;
|
|
WFE_ConvertFile2Url(convLaunch, profileLaunch);
|
|
CString aimName;
|
|
aimName.LoadString(ID_WINDOW_AIM);
|
|
|
|
|
|
/* MUST CONVERT AIM BOOKMARK CREATION TO AURORA (Dave H.)
|
|
BM_Entry* newBookmark = BM_NewUrl(aimName, convLaunch, NULL, NULL);
|
|
|
|
theApp.GetLinkToolbarManager().InitializeToolbarHeader();
|
|
BM_Entry* pRoot = theApp.GetLinkToolbarManager().GetToolbarHeader();
|
|
|
|
|
|
if (pRoot != NULL)
|
|
BM_PrependChildToHeader(theApp.m_pBmContext, pRoot, newBookmark);
|
|
*/
|
|
}
|
|
else fclose(fp);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
void FEU_OpenAim(void)
|
|
{
|
|
char szPath[_MAX_PATH + 1];
|
|
char shortPath[_MAX_PATH + 1];
|
|
|
|
CString install("none");
|
|
unsigned long cbData = sizeof(szPath);
|
|
|
|
#ifdef _WIN32
|
|
CString aimRegistry;
|
|
aimRegistry.LoadString(IDS_AIM_REGISTRY);
|
|
|
|
HKEY aimKey;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, aimRegistry, 0, KEY_QUERY_VALUE, &aimKey) != ERROR_SUCCESS)
|
|
return;
|
|
|
|
if (RegQueryValueEx(aimKey, 0, NULL, NULL, (LPBYTE) szPath, &cbData) == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(aimKey);
|
|
#ifdef _WIN32
|
|
GetShortPathName(szPath, shortPath, _MAX_PATH+1);
|
|
install = shortPath;
|
|
#else
|
|
install = szPath;
|
|
#endif
|
|
}
|
|
else return;
|
|
|
|
#endif // _WIN32
|
|
|
|
#ifdef XP_WIN16
|
|
// Do the right thing
|
|
GetPrivateProfileString("InstallRoot", "Path", "none", szPath, cbData, "aim.ini");
|
|
install = szPath;
|
|
if (install == "none")
|
|
return;
|
|
install = install + "\\aim.exe";
|
|
#endif // XP_WIN16
|
|
|
|
WinExec(install, SW_SHOW);
|
|
}
|
|
|
|
void FEU_OpenNetcaster(void)
|
|
{
|
|
#ifdef JAVA
|
|
|
|
if(FEU_IsNetcasterAvailable() == FALSE) {
|
|
MessageBox(NULL, XP_GetString(XP_ALERT_CANT_RUN_NETCASTER), szLoadString(AFX_IDS_APP_TITLE), MB_OK | MB_ICONEXCLAMATION);
|
|
return;
|
|
}
|
|
|
|
if(!theApp.m_pNetcasterWindow) {
|
|
Chrome netcasterChrome;
|
|
URL_Struct* URL_s, *splashURL_s;
|
|
MWContext *netcasterContext;
|
|
REGERR regErr = REGERR_FAIL;
|
|
char netcasterURL[300] = "";
|
|
char netcasterSplashURL[300] = "";
|
|
|
|
// First, get the URL
|
|
|
|
/* Due to a bug using the Windows Registry to detect Netcaster
|
|
installation with both Ratbert and Dogbert installed, we
|
|
need check the XP registry first. If success, use that. If
|
|
failure (due to a bug), use Windows. If both are installed
|
|
to unique locations and then one of them deleted, Windows
|
|
will return false, but the XP code should save our butts in
|
|
95% of the cases by returning true.
|
|
|
|
BTW, this code needs to be componentized more. Since today
|
|
is code freeze, I cut and posted code below to preserve existing
|
|
code paths. This code should be better organized for 4.03.
|
|
*/
|
|
|
|
#ifdef XP_WIN32
|
|
|
|
regErr = VR_GetPath("Netcaster/tab.htm", 300, netcasterURL);
|
|
VR_Close();
|
|
|
|
if (regErr != REGERR_OK) {
|
|
|
|
CString netcaster = "Software\\Netscape\\Netcaster\\";
|
|
|
|
netcaster = FEU_GetCurrentRegistry(netcaster);
|
|
if(netcaster.IsEmpty()) {
|
|
regErr = 3 ;
|
|
} else {
|
|
|
|
CString install = FEU_GetInstallationDirectory(netcaster, szLoadString(IDS_INSTALL_DIRECTORY));
|
|
|
|
if(install.IsEmpty()) {
|
|
regErr = 3 ;
|
|
} else {
|
|
|
|
|
|
strcpy(netcasterURL,install.GetBuffer(300));
|
|
|
|
XP_STRCAT(netcasterURL, "\\tab.htm") ;
|
|
|
|
strcpy(netcasterSplashURL,install.GetBuffer(300));
|
|
XP_STRCAT(netcasterSplashURL, "\\ncsplash.htm") ;
|
|
|
|
regErr = REGERR_OK ;
|
|
}
|
|
|
|
}
|
|
} else {
|
|
|
|
REGERR splashErr;
|
|
|
|
splashErr = VR_GetPath("Netcaster/ncsplash.htm", 300, netcasterSplashURL);
|
|
VR_Close();
|
|
|
|
if (splashErr != REGERR_OK) {
|
|
|
|
CString netcaster = "Software\\Netscape\\Netcaster\\";
|
|
|
|
netcaster = FEU_GetCurrentRegistry(netcaster);
|
|
if(!netcaster.IsEmpty()) {
|
|
|
|
CString install = FEU_GetInstallationDirectory(netcaster, szLoadString(IDS_INSTALL_DIRECTORY));
|
|
|
|
if(!install.IsEmpty()) {
|
|
|
|
strcpy(netcasterSplashURL,install.GetBuffer(300));
|
|
XP_STRCAT(netcasterSplashURL, "\\ncsplash.htm") ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
#else
|
|
regErr = VR_GetPath("Netcaster/tab.htm", 300, netcasterURL);
|
|
VR_Close();
|
|
|
|
#endif
|
|
|
|
|
|
if (regErr == REGERR_OK) {
|
|
|
|
// Now check to see if Java and JS are enabled
|
|
if (!LM_GetMochaEnabled() || !LJ_GetJavaEnabled()) {
|
|
MessageBox(NULL, XP_GetString(XP_ALERT_NETCASTER_NO_JS), szLoadString(AFX_IDS_APP_TITLE), MB_OK | MB_ICONEXCLAMATION);
|
|
return;
|
|
}
|
|
|
|
// First, bring up the splash screen, if it exists
|
|
#ifdef XP_WIN32
|
|
|
|
if (XP_STRLEN(netcasterSplashURL) > 0) {
|
|
|
|
MWContext *newContext;
|
|
|
|
memset(&netcasterChrome, 0, sizeof(Chrome));
|
|
netcasterChrome.type = MWContextBrowser;
|
|
netcasterChrome.w_hint = 400;
|
|
netcasterChrome.h_hint = 150;
|
|
netcasterChrome.l_hint = 100;
|
|
netcasterChrome.t_hint = 100;
|
|
netcasterChrome.topmost = FALSE;
|
|
netcasterChrome.z_lock = FALSE;
|
|
netcasterChrome.location_is_chrome = TRUE;
|
|
netcasterChrome.disable_commands = TRUE;
|
|
netcasterChrome.hide_title_bar = FALSE;
|
|
netcasterChrome.restricted_target = TRUE;
|
|
netcasterChrome.allow_close = TRUE;
|
|
netcasterChrome.show_bottom_status_bar = FALSE;
|
|
|
|
splashURL_s = NET_CreateURLStruct(netcasterSplashURL, NET_DONT_RELOAD);
|
|
|
|
newContext = FE_MakeNewWindow(NULL,
|
|
splashURL_s,
|
|
"Netcaster_Splash",
|
|
&netcasterChrome);
|
|
|
|
}
|
|
#endif
|
|
|
|
memset(&netcasterChrome, 0, sizeof(Chrome));
|
|
|
|
netcasterChrome.w_hint = 22;
|
|
netcasterChrome.h_hint = 55;
|
|
netcasterChrome.l_hint = -300;
|
|
netcasterChrome.t_hint = 0;
|
|
netcasterChrome.topmost = TRUE;
|
|
netcasterChrome.z_lock = TRUE;
|
|
netcasterChrome.location_is_chrome = TRUE;
|
|
netcasterChrome.disable_commands = TRUE;
|
|
netcasterChrome.hide_title_bar = TRUE;
|
|
netcasterChrome.restricted_target = TRUE;
|
|
netcasterChrome.allow_close = TRUE;
|
|
|
|
URL_s = NET_CreateURLStruct(netcasterURL, NET_DONT_RELOAD);
|
|
|
|
netcasterContext = FE_MakeNewWindow(NULL,
|
|
URL_s,
|
|
"Netcaster_SelectorTab",
|
|
&netcasterChrome);
|
|
|
|
theApp.m_pNetcasterWindow = netcasterContext ;
|
|
|
|
|
|
} else {
|
|
MessageBox(NULL, XP_GetString(XP_ALERT_CANT_RUN_NETCASTER), szLoadString(AFX_IDS_APP_TITLE), MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
} else {
|
|
|
|
if(! ABSTRACTCX(theApp.m_pNetcasterWindow) || ! ABSTRACTCX(theApp.m_pNetcasterWindow)->IsFrameContext() ) {
|
|
MessageBox(NULL, XP_GetString(XP_ALERT_CANT_RUN_NETCASTER), szLoadString(AFX_IDS_APP_TITLE), MB_OK | MB_ICONEXCLAMATION);
|
|
return;
|
|
} else {
|
|
// We are running, so give us focus...
|
|
//theApp.m_pNetcasterWindow->fe.cx->SetFocus() ;
|
|
|
|
if((theApp.m_pNetcasterWindow->fe.cx->IsFrameContext() == TRUE)) {
|
|
CWinCX *pWinCX = VOID2CX(theApp.m_pNetcasterWindow->fe.cx, CWinCX);
|
|
|
|
if (!pWinCX)
|
|
return ;
|
|
|
|
HWND hwnd = pWinCX->GetPane() ;
|
|
|
|
if (IsWindow(hwnd))
|
|
SetFocus(hwnd) ;
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
#endif /* JAVA */
|
|
}
|
|
|
|
BOOL FEU_IsNetcasterAvailable(void)
|
|
{
|
|
#ifdef JAVA
|
|
|
|
#ifdef XP_WIN32
|
|
|
|
/* Due to a bug using the Windows Registry to detect Netcaster
|
|
installation with both Ratbert and Dogbert installed, we
|
|
need check the XP registry first. If success, use that. If
|
|
failure (due to a bug), use Windows. If both are installed
|
|
to unique locations and then one of them was deleted, Windows
|
|
will return false, but the XP code should save our butts in
|
|
95% of the cases by returning true.
|
|
*/
|
|
|
|
CString netcaster = "Software\\Netscape\\Netcaster\\";
|
|
|
|
if (VR_InRegistry("Netcaster") == REGERR_OK) {
|
|
|
|
// The registry may be invalid since the user can delete
|
|
// the files. Check to see if one of the files exists.
|
|
// I believe this checks file existence too....
|
|
int rc = VR_ValidateComponent("Netcaster/tab.htm") ;
|
|
|
|
if (rc == REGERR_OK) {
|
|
VR_Close();
|
|
return (TRUE) ;
|
|
}
|
|
}
|
|
|
|
VR_Close();
|
|
|
|
/*
|
|
begin Windows code check
|
|
*/
|
|
|
|
netcaster = FEU_GetCurrentRegistry(netcaster);
|
|
|
|
if(netcaster.IsEmpty())
|
|
return FALSE;
|
|
CString install = FEU_GetInstallationDirectory(netcaster, szLoadString(IDS_INSTALL_DIRECTORY));
|
|
|
|
if (!install.IsEmpty()) {
|
|
|
|
// stat the directory first
|
|
struct _stat buf;
|
|
int result;
|
|
|
|
/* Get data associated with "stat.c": */
|
|
result = _stat( install.GetBuffer(256), &buf );
|
|
|
|
/* Check if statistics are valid: */
|
|
if( result != 0 )
|
|
return FALSE;
|
|
|
|
return (TRUE);
|
|
}
|
|
#endif
|
|
#endif /* JAVA */
|
|
return (FALSE);
|
|
|
|
}
|
|
|
|
|
|
void FE_ConvertSpace(char *newName)
|
|
{
|
|
char *p;
|
|
|
|
p = newName;
|
|
if (strchr(p, '%')) {
|
|
for(p = newName; *p; p++) {
|
|
if ((*p == '%') && (*(p+1) == 0x32) && (*(p+2) == 0x30)) {
|
|
*p = ' ';
|
|
strcpy(p+1, p+3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef XP_WIN32
|
|
CString FEU_GetCurrentRegistry(const CString &componentString)
|
|
{
|
|
|
|
HKEY hKey;
|
|
LONG lResult;
|
|
char szPath[_MAX_PATH + 1];
|
|
|
|
CString currentVersion, main, currentRegString("");
|
|
currentVersion.LoadString(IDS_CURRENTVERSION);
|
|
main.LoadString(IDS_MAIN);
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, componentString, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
|
|
unsigned long cbData = sizeof(szPath);
|
|
lResult = RegQueryValueEx(hKey, currentVersion, NULL, NULL, (LPBYTE) szPath, &cbData);
|
|
|
|
RegCloseKey(hKey);
|
|
if(lResult == ERROR_SUCCESS)
|
|
{
|
|
currentRegString = componentString + szPath;
|
|
currentRegString = currentRegString + main;
|
|
}
|
|
}
|
|
return currentRegString;
|
|
}
|
|
#endif
|
|
|
|
CString FEU_GetInstallationDirectory(const CString &productString, const CString &installationString)
|
|
{
|
|
#ifdef _WIN32
|
|
|
|
|
|
HKEY hKey;
|
|
LONG lResult;
|
|
char szPath[_MAX_PATH + 1];
|
|
CString install("");
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, productString, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
|
|
|
|
unsigned long cbData = sizeof(szPath);
|
|
lResult = RegQueryValueEx(hKey, installationString, NULL, NULL, (LPBYTE) szPath, &cbData);
|
|
|
|
RegCloseKey(hKey);
|
|
if(lResult == ERROR_SUCCESS)
|
|
install = szPath;
|
|
|
|
}
|
|
|
|
return install;
|
|
#else ifdef XP_WIN16
|
|
char szPath[_MAX_PATH + 1];
|
|
|
|
const char *pOldProfile = theApp.m_pszProfileName;
|
|
|
|
UINT nSize = GetWindowsDirectory(szPath, _MAX_PATH + 1);
|
|
XP_STRCPY(szPath + nSize, szLoadString(IDS_NSCPINI));
|
|
theApp.m_pszProfileName = szPath;
|
|
|
|
CString version = theApp.GetProfileString(productString, szLoadString(IDS_CURRENTVERSION), NULL);
|
|
if(version.IsEmpty())
|
|
{
|
|
theApp.m_pszProfileName = pOldProfile;
|
|
return version;
|
|
}
|
|
|
|
CString currentVersion = "-" + version;
|
|
currentVersion = productString + currentVersion;
|
|
|
|
CString install = theApp.GetProfileString(currentVersion, installationString, NULL);
|
|
|
|
theApp.m_pszProfileName = pOldProfile;
|
|
|
|
return install;
|
|
#endif
|
|
}
|
|
|
|
|
|
// Send/Post a message to all top level frames in our app.
|
|
void FEU_FrameBroadcast(BOOL bSend, UINT Msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Go through list of frames.
|
|
for(CGenericFrame *pFrame = theApp.m_pFrameList;
|
|
pFrame != NULL;
|
|
pFrame = pFrame->m_pNext) {
|
|
if(pFrame->GetSafeHwnd()) {
|
|
if(bSend) {
|
|
pFrame->SendMessage(Msg, wParam, lParam);
|
|
}
|
|
else {
|
|
pFrame->PostMessage(Msg, wParam, lParam);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the hidden one too.
|
|
if(theApp.m_pMainWnd && theApp.m_pMainWnd->GetSafeHwnd()) {
|
|
if(bSend) {
|
|
theApp.m_pMainWnd->SendMessage(Msg, wParam, lParam);
|
|
}
|
|
else {
|
|
theApp.m_pMainWnd->PostMessage(Msg, wParam, lParam);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FEU_AltMail_ShowMailBox(void)
|
|
{
|
|
if(theApp.m_bInitMapi)
|
|
{
|
|
if(theApp.m_fnOpenMailSession)
|
|
{
|
|
POSTCODE status = (*theApp.m_fnOpenMailSession) (NULL, NULL);
|
|
if(status == POST_OK)
|
|
theApp.m_bInitMapi = FALSE;
|
|
else
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(theApp.m_fnShowMailBox)
|
|
(*theApp.m_fnShowMailBox) ();
|
|
}
|
|
|
|
void FEU_AltMail_ShowMessageCenter(void)
|
|
{
|
|
if(theApp.m_bInitMapi)
|
|
{
|
|
if(theApp.m_fnOpenMailSession)
|
|
{
|
|
POSTCODE status = (*theApp.m_fnOpenMailSession) (NULL, NULL);
|
|
if(status == POST_OK)
|
|
theApp.m_bInitMapi = FALSE;
|
|
else
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(theApp.m_fnShowMessageCenter)
|
|
(*theApp.m_fnShowMessageCenter) ();
|
|
}
|
|
|
|
//Modify communicators menu with alt mail specified menu
|
|
//Remove menu item if pszAltMailMenuStr is empty
|
|
void FEU_AltMail_ModifyMenu(CMenu* pMenuCommunicator, UINT uiCommunicatorMenuID, LPCSTR pszAltMailMenuStr)
|
|
{
|
|
if(*pszAltMailMenuStr)
|
|
{
|
|
CString csNewMenuStr;
|
|
#ifdef XP_WIN32
|
|
if(pMenuCommunicator->GetMenuString(uiCommunicatorMenuID, csNewMenuStr, MF_BYCOMMAND))
|
|
#else
|
|
if(pMenuCommunicator->GetMenuString(uiCommunicatorMenuID, csNewMenuStr.GetBuffer(256), 256, MF_BYCOMMAND))
|
|
#endif
|
|
{
|
|
#ifdef XP_WIN16
|
|
csNewMenuStr.ReleaseBuffer();
|
|
#endif
|
|
|
|
int iPos;
|
|
if((iPos = csNewMenuStr.Find('\t')) != -1)
|
|
{
|
|
//Accelerator present. Add it to the end of AltMail menu string
|
|
CString csAccel = csNewMenuStr.Right(csNewMenuStr.GetLength() - iPos);
|
|
csNewMenuStr = pszAltMailMenuStr + csAccel;
|
|
}
|
|
else //No accelerator. use alt mail str as is
|
|
csNewMenuStr = pszAltMailMenuStr;
|
|
|
|
pMenuCommunicator->ModifyMenu(uiCommunicatorMenuID, MF_BYCOMMAND, uiCommunicatorMenuID, csNewMenuStr);
|
|
}
|
|
}
|
|
else
|
|
pMenuCommunicator->RemoveMenu(uiCommunicatorMenuID, MF_BYCOMMAND);
|
|
}
|
|
|
|
//Modify "Messenger MailBox" and "Message Center" menu items
|
|
//to strings supplied by the AltMail DLL
|
|
void FEU_AltMail_SetAltMailMenus(CMenu* pMenuCommunicator)
|
|
{
|
|
char szAltMailMenuStr[_MAX_PATH];
|
|
|
|
szAltMailMenuStr[0] = '\0';
|
|
if(POST_OK == (*theApp.m_fnGetMenuItemString)(ALTMAIL_MenuMailBox, szAltMailMenuStr, _MAX_PATH))
|
|
FEU_AltMail_ModifyMenu(pMenuCommunicator, ID_TOOLS_INBOX, szAltMailMenuStr);
|
|
|
|
szAltMailMenuStr[0] = '\0';
|
|
if(POST_OK == (*theApp.m_fnGetMenuItemString)(ALTMAIL_MenuMessageCenter, szAltMailMenuStr, _MAX_PATH))
|
|
FEU_AltMail_ModifyMenu(pMenuCommunicator, ID_TOOLS_MAIL, szAltMailMenuStr);
|
|
}
|
|
|
|
BOOL FEU_Execute(MWContext *pContext, const char *pCommand, const char *pParams)
|
|
{
|
|
BOOL bRetval = TRUE;
|
|
BOOL bHandled = FALSE;
|
|
HINSTANCE hSpawn = (HINSTANCE)2; // 2 is application not found.
|
|
|
|
if(bHandled == FALSE) {
|
|
hSpawn = ShellExecute(NULL, NULL, pCommand, pParams, NULL, SW_SHOW);
|
|
if((int)hSpawn == 2 && pCommand && pParams) {
|
|
// Failure, Application not found.
|
|
// Some legacy helpers (netscape viewers section of preferences)
|
|
// specify switches in the pCommand such that ShellExecute
|
|
// fails. Re-attempt with WinExec to see if it works
|
|
// correctly (CyberCash, Norton Anti-Virus).
|
|
// Both command and params are specified in this scenario.
|
|
CString csCommand = CString(pCommand) + " " + CString(pParams);
|
|
hSpawn = (HINSTANCE)WinExec(csCommand, SW_SHOW);
|
|
}
|
|
bHandled = TRUE;
|
|
}
|
|
|
|
if((int)hSpawn < 32) {
|
|
bRetval = FALSE;
|
|
|
|
char szMsg[80];
|
|
switch((int)hSpawn) {
|
|
case 0:
|
|
case 8:
|
|
sprintf(szMsg, szLoadString(IDS_WINEXEC_0_8));
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
sprintf(szMsg, szLoadString(IDS_WINEXEC_2_3));
|
|
break;
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
sprintf(szMsg, szLoadString(IDS_WINEXEC_10_THRU_15));
|
|
break;
|
|
case 16:
|
|
sprintf(szMsg, szLoadString(IDS_WINEXEC_16));
|
|
break;
|
|
case 21:
|
|
sprintf(szMsg, szLoadString(IDS_WINEXEC_21));
|
|
break;
|
|
default:
|
|
sprintf(szMsg, szLoadString(IDS_WINEXEC_XX), (UINT)hSpawn);
|
|
break;
|
|
}
|
|
|
|
FE_Alert(pContext, szMsg);
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
|
|
/*///////////////////////////////////////////////////////////////////////
|
|
// Find the executable which will handle the filename. //
|
|
// Retval BOOL: Wether or not an executable was found. //
|
|
// pFileName: The content to be executed. //
|
|
// pExecutable: Buffer to hold the name of executable if found. //
|
|
// bIdentity: Wether or not the pFileName can be the pExecutable. //
|
|
// bExtension: Whether or not pFileName is actually an extension. //
|
|
///////////////////////////////////////////////////////////////////////*/
|
|
BOOL FEU_FindExecutable(const char *pFileName, char *pExecutable, BOOL bIdentity, BOOL bExtension) {
|
|
BOOL bRetval = FALSE;
|
|
BOOL bFound = FALSE;
|
|
BOOL bFreeFileName = FALSE;
|
|
|
|
char aViewer[_MAX_PATH];
|
|
memset(aViewer, 0, sizeof(aViewer));
|
|
|
|
// pFileName may not be a file name, but an extension.
|
|
// We want to support just extensions for ease, so check on it.
|
|
if(bExtension && pFileName) {
|
|
// We have an extension.
|
|
// Fill out the rest of the name.
|
|
bFreeFileName = TRUE;
|
|
pFileName = (const char *)WH_TempFileName(xpTemporary, "G", pFileName);
|
|
}
|
|
|
|
if(!bFound && pFileName && *pFileName) {
|
|
// Does pFileName actually exists, if not we will need to
|
|
// create it temporarily so that ::FindExecutable will work.
|
|
BOOL bCreatedFile = FALSE;
|
|
if(_access(pFileName, 00) != 0) {
|
|
HFILE hCreate = _lcreat(pFileName, 0);
|
|
if(hCreate != HFILE_ERROR) {
|
|
bCreatedFile = TRUE;
|
|
_lclose(hCreate);
|
|
}
|
|
}
|
|
|
|
HINSTANCE hRet = FindExecutable(pFileName, NULL, aViewer);
|
|
if((int)hRet > 32) {
|
|
// Found a viewer.
|
|
bFound = TRUE;
|
|
}
|
|
|
|
/* Cleanup */
|
|
if(bCreatedFile) {
|
|
_unlink(pFileName);
|
|
}
|
|
}
|
|
|
|
// Do we fill in the return value?
|
|
// Note that we fill it in regardless of the bIdentity flag.
|
|
if(pExecutable) {
|
|
strcpy(pExecutable, aViewer);
|
|
}
|
|
|
|
// Decide return value based on bIdentity if an EXE found.
|
|
if(bFound) {
|
|
if(bIdentity) {
|
|
bRetval = TRUE;
|
|
}
|
|
else {
|
|
// Must make sure executable and filename are not the
|
|
// same.
|
|
// Do a case insensitive comparison.
|
|
char *pCompareFile = (char *)pFileName;
|
|
char *pCompareExe = (char *)aViewer;
|
|
|
|
#ifdef XP_WIN32
|
|
// On win32, we compare short names to avoid any confusion.
|
|
char aShortFile[_MAX_PATH];
|
|
char aShortExe[_MAX_PATH];
|
|
|
|
memset(aShortFile, 0, sizeof(aShortFile));
|
|
memset(aShortExe, 0, sizeof(aShortExe));
|
|
|
|
GetShortPathName(pCompareFile, aShortFile, sizeof(aShortFile));
|
|
GetShortPathName(pCompareExe, aShortExe, sizeof(aShortFile));
|
|
|
|
pCompareFile = aShortFile;
|
|
pCompareExe = aShortExe;
|
|
#endif
|
|
|
|
// Case insensitive comparison.
|
|
if(stricmp(pCompareFile, pCompareExe)) {
|
|
// Not the same.
|
|
bRetval = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(bFreeFileName && pFileName) {
|
|
XP_FREE((void *)pFileName);
|
|
pFileName = NULL;
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
// Return TRUE if the given path points to an existing
|
|
// directory. Attempt to create the directory if we can
|
|
BOOL FEU_SanityCheckDir(const char * dir)
|
|
{
|
|
int ret;
|
|
XP_StatStruct statinfo;
|
|
|
|
ret = _stat((char *) dir, &statinfo);
|
|
if(ret == -1) {
|
|
|
|
// see if we can just create it
|
|
#ifdef __WATCOMC__
|
|
ret = mkdir(dir);
|
|
#else
|
|
ret = _mkdir(dir);
|
|
#endif
|
|
|
|
// still couldn't create it
|
|
if(ret == -1)
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
// Return TRUE if the given file has a valid path
|
|
BOOL FEU_SanityCheckFile(const char * file)
|
|
{
|
|
int ret;
|
|
XP_StatStruct statinfo;
|
|
|
|
ret = _stat((char *) file, &statinfo);
|
|
if(ret == -1)
|
|
return(FALSE);
|
|
else
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
void FEU_DeleteUrlData(URL_Struct *pUrl, MWContext *pCX) {
|
|
// A Url is about to be removed.
|
|
// Clean up any extra stuff that we know about but Netlib doesn't.
|
|
if(pUrl->ncapi_data != NULL) {
|
|
CNcapiUrlData *pUrlData = (CNcapiUrlData *)pUrl->ncapi_data;
|
|
delete pUrlData;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL FEU_IsNetscapeFrame(CWnd* pFocusWnd)
|
|
{
|
|
if (pFocusWnd->IsKindOf(RUNTIME_CLASS(CGenericView)))
|
|
return TRUE;
|
|
else if (pFocusWnd->IsKindOf(RUNTIME_CLASS(CGenericFrame)))
|
|
return TRUE;
|
|
#ifdef MOZ_MAIL_NEWS
|
|
else if (pFocusWnd->IsKindOf(RUNTIME_CLASS(CMsgListFrame)))
|
|
return TRUE;
|
|
#endif /* MOZ_MAIL_NEWS */
|
|
// else if (pFocusWnd->IsKindOf(RUNTIME_CLASS(CNSToolbar2)))
|
|
// return TRUE;
|
|
else return FALSE;
|
|
|
|
}
|
|
|
|
BOOL CALLBACK WinEnumProc(HWND hwnd, LPARAM lParam)
|
|
{
|
|
// check to see if the Windows title is "Netscape's Hidden Frame"
|
|
char winText[256];
|
|
if (GetWindowText(hwnd, winText, sizeof(winText)) != 0)
|
|
{
|
|
if (lstrcmpi(winText, "Netscape's Hidden Frame") == 0)
|
|
{
|
|
*((HWND*)lParam) = hwnd;
|
|
return(FALSE);
|
|
}
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
extern "C"
|
|
HWND FindNavigatorHiddenWindow(void)
|
|
{
|
|
// find Navigator's hidden frame
|
|
HWND hWnd = NULL;
|
|
EnumWindows(WinEnumProc, (LPARAM)&hWnd);
|
|
return(hWnd);
|
|
}
|
|
|
|
|
|
//Used to determine initialization action. If we detect a previous instance
|
|
//and it is in the middle of initializing, find out how far along it is by
|
|
//looking for it's hidden frame. If the previous instance has a hidden frame
|
|
//then we return TRUE and alow the second instance to DDE to the first. If it
|
|
//doesn't have a hidden frame, we wait for 10 seconds in the case that the first
|
|
//and the second instance started at nearly the same time. Thus, giving the first
|
|
//instance a chance to create it's hidden frame and allowing the second instance
|
|
//to open a successful DDE conversation to the first instance.
|
|
//This function should be called from InitInstance prior to the Initialization of
|
|
//the NetscapeSlaveClass. This call is only need for win32. This same call
|
|
//will be made for win16 but from the NAVSTART.EXE application.
|
|
#ifdef XP_WIN32
|
|
BOOL BailOrStay(void)
|
|
{
|
|
if (FindWindow("NetscapeSlaveClass",NULL))
|
|
{
|
|
if (!FindNavigatorHiddenWindow())
|
|
{
|
|
Sleep(10000);//give the first instance a chance to start
|
|
if(!FindNavigatorHiddenWindow()) //If it's not present yet we just exit.
|
|
{ //First instance is probably running the profile manager.
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
// Do not change the current drive to a floppy.
|
|
BOOL FEU_GetSaveFileName(OPENFILENAME *pOFN)
|
|
{
|
|
// Check to see if the dialog will ignore directory changes.
|
|
BOOL bCheckFloppy = (pOFN && !(pOFN->Flags & OFN_NOCHANGEDIR));
|
|
char aOriginalPath[MAX_PATH];
|
|
if(bCheckFloppy) {
|
|
// Make sure we're not already on a floppy.
|
|
if(FEU_GetCurrentDriveType() == DRIVE_REMOVABLE) {
|
|
// We don't care what they do.
|
|
bCheckFloppy = FALSE;
|
|
}
|
|
else {
|
|
// Save current directory.
|
|
DWORD dwCopy = ::GetCurrentDirectory(sizeof(aOriginalPath), aOriginalPath);
|
|
if(0 == dwCopy || sizeof(aOriginalPath) < dwCopy) {
|
|
// On failure, switch to not care.
|
|
bCheckFloppy = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL bRetval = ::GetSaveFileName(pOFN);
|
|
|
|
// Are we to check if we are on a floppy drive?
|
|
if(bCheckFloppy) {
|
|
BOOL bFloppy = (FEU_GetCurrentDriveType() == DRIVE_REMOVABLE);
|
|
if(bFloppy) {
|
|
// Go back to a non-floppy location.
|
|
// Don't care on failure.
|
|
::SetCurrentDirectory(aOriginalPath);
|
|
}
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
// Do not change the current drive to a floppy.
|
|
BOOL FEU_GetOpenFileName(OPENFILENAME *pOFN)
|
|
{
|
|
// Check to see if the dialog will ignore directory changes.
|
|
BOOL bCheckFloppy = (pOFN && !(pOFN->Flags & OFN_NOCHANGEDIR));
|
|
char aOriginalPath[MAX_PATH];
|
|
if(bCheckFloppy) {
|
|
// Make sure we're not already on a floppy.
|
|
if(FEU_GetCurrentDriveType() == DRIVE_REMOVABLE) {
|
|
// We don't care what they do.
|
|
bCheckFloppy = FALSE;
|
|
}
|
|
else {
|
|
// Save current directory.
|
|
DWORD dwCopy = ::GetCurrentDirectory(sizeof(aOriginalPath), aOriginalPath);
|
|
if(0 == dwCopy || sizeof(aOriginalPath) < dwCopy) {
|
|
// On failure, switch to not care.
|
|
bCheckFloppy = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL bRetval = ::GetOpenFileName(pOFN);
|
|
|
|
// Are we to check if we are on a floppy drive?
|
|
if(bCheckFloppy) {
|
|
BOOL bFloppy = (FEU_GetCurrentDriveType() == DRIVE_REMOVABLE);
|
|
if(bFloppy) {
|
|
// Go back to a non-floppy location.
|
|
// Don't care on failure.
|
|
::SetCurrentDirectory(aOriginalPath);
|
|
}
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
// Return the current Drive's type
|
|
UINT FEU_GetCurrentDriveType(void)
|
|
{
|
|
#ifdef XP_WIN16
|
|
return(::GetDriveType(::_getdrive() - 1));
|
|
#else
|
|
return(::GetDriveType(NULL));
|
|
#endif
|
|
}
|
|
|
|
#ifdef XP_WIN16
|
|
DWORD GetCurrentDirectory(DWORD nBufferLength, LPSTR lpBuffer)
|
|
{
|
|
DWORD dwRetval = nBufferLength + MAX_PATH;
|
|
char *pRetval = NULL;
|
|
if(lpBuffer) {
|
|
pRetval = _getcwd(lpBuffer, nBufferLength);
|
|
}
|
|
if(pRetval) {
|
|
dwRetval = XP_STRLEN(lpBuffer);
|
|
}
|
|
return(dwRetval);
|
|
}
|
|
|
|
BOOL SetCurrentDirectory(LPCSTR lpPathName)
|
|
{
|
|
BOOL bRetval = FALSE;
|
|
if(lpPathName) {
|
|
if(_chdir(lpPathName) == 0) {
|
|
// Must also change drive in 16 bits.
|
|
char aDrive[_MAX_DRIVE];
|
|
aDrive[0] = '\0';
|
|
_splitpath(lpPathName, aDrive, NULL, NULL, NULL);
|
|
if(aDrive[0]) {
|
|
// A drive, convert to numeral.
|
|
aDrive[0] = toupper(aDrive[0]);
|
|
if(_chdrive(aDrive[0] - 'A' + 1) == 0) {
|
|
bRetval = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
// No drive, then a success.
|
|
bRetval = TRUE;
|
|
}
|
|
}
|
|
}
|
|
return(bRetval);
|
|
}
|
|
#endif
|
|
|
|
// Determine the top most window below the given point.
|
|
// No guarantees that the window belongs to our process, or what
|
|
// type of window it is.
|
|
// Invisible windows are not returned.
|
|
// Disabled windows are not returned.
|
|
//
|
|
// hWndTop same as GetTopWindow SDK function.
|
|
// Point is in Screen coordinates.
|
|
HWND FEU_GetWindowFromPoint(HWND hWndTop, POINT *pPoint)
|
|
{
|
|
HWND hRetval = NULL;
|
|
if(pPoint) {
|
|
HWND hTraverse = GetTopWindow(hWndTop);
|
|
if(hTraverse) {
|
|
RECT rWindow;
|
|
do {
|
|
memset(&rWindow, 0, sizeof(rWindow));
|
|
GetWindowRect(hTraverse, &rWindow);
|
|
if(PtInRect(&rWindow, *pPoint)) {
|
|
if(!IsWindowVisible(hTraverse)) {
|
|
// Skip this one.
|
|
continue;
|
|
}
|
|
if(!IsWindowEnabled(hTraverse)) {
|
|
// Window is visible, but disabled.
|
|
// Have to return NULL.
|
|
break;
|
|
}
|
|
hRetval = hTraverse;
|
|
break;
|
|
}
|
|
} while(hTraverse = GetNextWindow(hTraverse, GW_HWNDNEXT));
|
|
}
|
|
}
|
|
return(hRetval);
|
|
}
|
|
|
|
CNSGenFrame *FEU_GetDockingFrameFromPoint(POINT *pPoint)
|
|
{
|
|
CNSGenFrame *pRetval = NULL;
|
|
HWND hAttempt = FEU_GetWindowFromPoint(NULL, pPoint);
|
|
if(hAttempt) {
|
|
CWnd *pPerm = CWnd::FromHandlePermanent(hAttempt);
|
|
if(pPerm && pPerm->IsKindOf(RUNTIME_CLASS(CNSGenFrame))) {
|
|
CNSGenFrame *pDockable = (CNSGenFrame *)pPerm;
|
|
if(pDockable->AllowDocking()) {
|
|
pRetval = pDockable;
|
|
}
|
|
}
|
|
}
|
|
return(pRetval);
|
|
}
|
|
|
|
extern "C" PRBool FE_IsNetscapeDefault(void) {
|
|
return PR_TRUE;
|
|
}
|
|
|
|
extern "C" PRBool FE_MakeNetscapeDefault(void) {
|
|
return PR_TRUE;
|
|
}
|
|
|
|
// Use this to create some COM objects, as we need to switch to the
|
|
// directory where the .EXE sits if the current directory isn't
|
|
// the same, as the pref COM DLLs have relative paths in the
|
|
// registry.
|
|
HRESULT FEU_CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv)
|
|
{
|
|
HRESULT hRetval = NULL;
|
|
|
|
char aOrigDir[MAX_PATH + 1];
|
|
DWORD dwCheck = GetCurrentDirectory(sizeof(aOrigDir), aOrigDir);
|
|
ASSERT(dwCheck);
|
|
|
|
char aProgramDir[MAX_PATH + 1];
|
|
FE_GetProgramDirectory(aProgramDir, sizeof(aProgramDir));
|
|
|
|
BOOL bCheck = SetCurrentDirectory(aProgramDir);
|
|
ASSERT(bCheck);
|
|
|
|
hRetval = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv);
|
|
|
|
BOOL bRestoreCheck = SetCurrentDirectory(aOrigDir);
|
|
ASSERT(bRestoreCheck);
|
|
|
|
return(hRetval);
|
|
}
|
|
|