gecko-dev/cmd/winfe/hiddenfr.cpp
1998-09-29 21:35:57 +00:00

860 lines
24 KiB
C++

/* -*- 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 "hiddenfr.h"
#include "template.h"
#ifdef MOZ_MAIL_NEWS
#include "wfemsg.h"
#endif
#include "timer.h"
#ifdef MOZ_MAIL_NEWS
#include "addrfrm.h"
#endif
#include "feselect.h"
#include "postal.h"
#include "ssl.h"
#ifdef MOZ_MAIL_NEWS
#include "nscpmapi.h" // rhp - for MAPI
#include "mapihook.h" // rhp - for MAPI
#include "mapismem.h"
#include "abapi.h" // rhp - for Address Book API
#include "abhook.h" // rhp - for Address Book API
#endif
extern "C" {
#include "layprobe.h"
}
#include "mozprobe.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CHiddenFrame
#ifndef _AFXDLL
#undef new
#endif
IMPLEMENT_DYNCREATE(CHiddenFrame, CFrameWnd)
#ifndef _AFXDLL
#define new DEBUG_NEW
#endif
#define EXITING -10 //multi-instance code return values
#define RUNNING 10
const UINT NEAR msg_FoundDNS = RegisterWindowMessage("NetscapeDNSFound");
const UINT NEAR msg_ExitStatus = RegisterWindowMessage("ExitingNetscape");
UINT NEAR msg_ForceIOSelect = (UINT)-1;
UINT NEAR msg_NetActivity = (UINT)-1;
const UINT NEAR msg_AltMailBiffNotification = RegisterWindowMessage("Netscape Mail System");
// Net dike.
int gNetFloodStage = 0;
CHiddenFrame::CHiddenFrame()
{
// Attempt to make the registration of this as late as possible as to
// get the highest possible ID (see NSPumpMessage).
msg_ForceIOSelect = RegisterWindowMessage("NetscapeForceIOSelect");
msg_NetActivity = RegisterWindowMessage("NetscapeSocketSelect");
}
CHiddenFrame::~CHiddenFrame()
{
}
LONG CHiddenFrame::OnRequestExitStatus(WPARAM wParam/*0*/,LPARAM lParam/*0*/)
{
return (theApp.m_bExitStatus ? EXITING :RUNNING );
}
BEGIN_MESSAGE_MAP(CHiddenFrame, CFrameWnd)
//{{AFX_MSG_MAP(CHiddenFrame)
// NOTE - the ClassWizard will add and remove mapping macros here.
ON_REGISTERED_MESSAGE(msg_NetActivity, OnNetworkActivity)
ON_REGISTERED_MESSAGE(msg_FoundDNS, OnFoundDNS)
ON_REGISTERED_MESSAGE(msg_ForceIOSelect, OnForceIOSelect)
ON_REGISTERED_MESSAGE(msg_ExitStatus, OnRequestExitStatus)
ON_MESSAGE(MSG_TASK_NOTIFY, OnTaskNotify)
ON_WM_DESTROY()
ON_WM_ENDSESSION()
//}}AFX_MSG_MAP
#ifdef MOZ_MAIL_NEWS
ON_REGISTERED_MESSAGE(msg_AltMailBiffNotification, OnAltMailBiffNotification)
#endif
ON_WM_QUERYENDSESSION() //~~av
ON_MESSAGE(WM_COPYDATA, OnProcessIPCHook) // rhp - for MAPI
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CHiddenFrame message handlers
#define HIDDENTIME 333
struct HiddenMessage {
UINT m_uMsg;
WPARAM m_wParam;
LPARAM m_lParam;
};
void wfe_HiddenRepost(void *pData)
{
HiddenMessage *pMsg = (HiddenMessage *)pData;
if(pMsg) {
if(theApp.m_pMainWnd && theApp.m_pMainWnd->GetSafeHwnd()) {
theApp.m_pMainWnd->PostMessage(pMsg->m_uMsg, pMsg->m_wParam, pMsg->m_lParam);
}
memset(pMsg, 0, sizeof(*pMsg));
delete pMsg;
pMsg = NULL;
}
}
void wfe_PostDelayedMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, uint32 uMilli = HIDDENTIME)
{
HiddenMessage *pMsg = new HiddenMessage;
if(pMsg) {
memset(pMsg, 0, sizeof(*pMsg));
pMsg->m_uMsg = uMsg;
pMsg->m_wParam = wParam;
pMsg->m_lParam = lParam;
void *pSet = FE_SetTimeout(wfe_HiddenRepost, (void *)pMsg, uMilli);
if(NULL == pSet) {
delete pMsg;
pMsg = NULL;
}
}
}
#ifdef MOZ_MAIL_NEWS
LONG CHiddenFrame::OnAltMailBiffNotification(WPARAM wParam, LPARAM lParam)
{
switch(wParam) {
case INBOX_STATE_NOMAIL:
FE_UpdateBiff(MSG_BIFF_NoMail);
break;
case INBOX_STATE_UNKNOWN:
FE_UpdateBiff(MSG_BIFF_Unknown);
break;
case INBOX_STATE_NEWMAIL:
FE_UpdateBiff(MSG_BIFF_NewMail);
break;
default:
break;
}
return(1);
}
#endif // MOZ_MAIL_NEWS
LONG CHiddenFrame::OnForceIOSelect(WPARAM wParam, LPARAM lParam)
{
// Net dike. (see hiddenfr.h)
// This code protects external message loops from the flood
// of network messages we would normally handle, thus
// keeping the app responsive while in a different
// message loop. External message loops being loops
// other than CNetscapeApp::NSPumpMessage.
BOOL bDoHandle = TRUE;
if(::GetMessageTime() != (LONG)theApp.GetMessageTime()) {
// Message came from different message loop than one
// found in CNetscapeApp::NSPumpMessage.
BOOL bReposted = FALSE;
// In the CNetscapeApp::NSPumpMessage this variable is
// usually incremented on EVERY MESSAGE. Note the
// difference here that we are incrementing it only
// on receipt of a network message, causing a much
// smaller window for these messages to get through.
// A small counter-balance is that we are going to
// repost the message, which causes this function
// to be entered again at some later time (thus
// incrementing the counter, etc).
// CNetscapeApp::NSPumpMessage only peeks and
// does not generate the overhead of yet another
// message, unlike this suboptimal code.
gNetFloodStage++;
// 1 : NET_FLOWCONTROL, we force a network event to be
// handled regardless of the queue state.
if((gNetFloodStage % NET_FLOWCONTROL) != 0) {
// See if there are messages not our own in the queue.
MSG msg;
if(::PeekMessage(&msg, NULL, 0, NET_MESSAGERANGE, PM_NOREMOVE)) {
// There are, repost till next time.
// We use a 1 millisecond timeout, based on what we know
// timers actually do. Timers don't fire until the
// queue is empty; thus the message will repost once
// all other stuff is done.
bDoHandle = FALSE;
wfe_PostDelayedMessage(msg_ForceIOSelect, wParam, lParam, 1);
}
}
}
if(bDoHandle) {
SelectType stType = (SelectType)wParam;
PRFileDesc *iFD = (PRFileDesc *)lParam;
int iNetlibType = NET_SOCKET_FD;
if(stType == FileSelect) {
iNetlibType = NET_LOCAL_FILE_FD;
}
else if(stType == NetlibSelect) {
iNetlibType = NET_EVERYTIME_TYPE;
}
// Must be socket or have in select list to continue.
// We don't check sockets here, as it is too difficult to
// segregate them out into their different select NetLib
// categories (see feselect.cpp).
//
// LJM removed call to HasSelect for nspr20 port
// if(iNetlibType == NET_SOCKET_FD || selecttracker.HasSelect(stType, iFD)) {
if(iNetlibType == NET_SOCKET_FD) {
int iWantMore = 1;
BOOL bCalledNetlib = FALSE;
if(winfeInProcessNet == FALSE) {
winfeInProcessNet = TRUE;
iWantMore = NET_ProcessNet(iFD, iNetlibType);
bCalledNetlib = TRUE;
winfeInProcessNet = FALSE;
}
if(bCalledNetlib == FALSE) {
// Wait to repost message, as we are in the callstack of netlib.
// If a dialog is up, then we don't want to max the CPU by posting
// of the same message over and over and the user can't hit
// a button.
wfe_PostDelayedMessage(msg_ForceIOSelect, wParam, lParam);
}
// LJM removed call to SSL_DataPending for NSPR20 port
else if(0 != iWantMore && (NET_SOCKET_FD != iNetlibType)) {
// Sockets don't need reposting if actually called netlib,
// as they will post messages themselves when data is ready.
// This is not true if they have SSL data buffered.
// However, we do repost for files, as they are ready for more.
PostMessage(msg_ForceIOSelect, wParam, lParam);
}
}
}
// Always handled.
return(1);
}
LONG CHiddenFrame::OnNetworkActivity(UINT socket, LONG lParam)
{
XP_ASSERT(0);
return 0;
}
LONG CHiddenFrame::OnFoundDNS(WPARAM wParam, LONG lParam)
{
int iError = WSAGETASYNCERROR(lParam);
// Go through the DNS cache, find the correct task ID.
// The find should always be successful.
// Be sure to initalize values.
POSITION pos = NULL;
CString key;
CDNSObj *obj = NULL;
int i_found = 0;
LONG return_value = 1;
for(pos = DNSCacheMap.GetStartPosition(); pos != NULL;) {
DNSCacheMap.GetNextAssoc(pos, key, (CObject *&)obj);
if(!obj)
return return_value;
// Since the handle is not unique for the session only
// compare handles that are currently in use (i.e. active entries)
if(!obj->i_finished && obj->m_handle == (HANDLE)wParam) {
i_found = 1;
break;
}
// Clear out object if we didn't break.
// That way we don't retain value if we leave the loop.
obj = NULL;
}
if(!obj)
return return_value;
TRACE("%s error=%d h_name=%d task=%d\n", obj->m_host, iError,
(obj->m_hostent->h_name != NULL) ? 1 : 0, obj->m_handle);
// If by chance we couldn't find it, we have a problem.
//
ASSERT(i_found == 1);
/* temp fix */
if(!i_found)
return return_value;
// Mark this as completed.
//
obj->i_finished = 1;
// If there was an error, set it.
if (iError) {
TRACE("DNS Lookup failed! \n");
obj->m_iError = iError;
return_value = 0;
}
/* call ProcessNet for each socket in the list */
/* use a for loop so that we don't reference the "obj"
* after our last call to processNet. We need to do
* this because the "obj" can get free'd by the call
* chain after all the sockets have been removed from
* sock_list
*/
PRFileDesc *tmp_sock;
int count = XP_ListCount(obj->m_sock_list);
for(; count; count--) {
tmp_sock = (PRFileDesc *) XP_ListRemoveTopObject(obj->m_sock_list);
// Make sure we call into the Netlib on this socket in particular,
// NET_SOCKET_FD type.
OnForceIOSelect((WPARAM)SocketSelect, (LPARAM)tmp_sock);
}
return(return_value);
}
void CHiddenFrame::OnDestroy()
{
#ifdef _WIN32
if (sysInfo.m_bWin4) {
// Kill this biff taskbar icon
NOTIFYICONDATA nid;
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = GetSafeHwnd();
nid.uID = ID_TOOLS_INBOX;
nid.uFlags = 0;
Shell_NotifyIcon( NIM_DELETE, &nid );
}
#endif
CFrameWnd::OnDestroy();
}
/****************************************************************************
*
* Task notification handling functions
*
****************************************************************************/
/****************************************************************************
*
* CHiddenFrame::OnTaskNotify
*
* PARAMETERS:
* wParam - icon ID
* lParam - mouse event
*
* RETURNS:
* Non-zero if message is processed.
*
* DESCRIPTION:
* This is the handler for the notification messages we received from
* task bar icons.
*
****************************************************************************/
LONG CHiddenFrame::OnTaskNotify(WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case ID_TOOLS_WEB:
{
HandleWebNotification(lParam);
}
break;
#ifdef MOZ_MAIL_NEWS
case ID_TOOLS_MAIL:
{
HandleMailNotification(lParam);
}
break;
case ID_TOOLS_INBOX:
{
HandleInboxNotification(lParam);
}
break;
#endif /* MOZ_MAIL_NEWS */
#ifdef EDITOR
case ID_TOOLS_EDITOR:
{
HandleEditorNotification(lParam);
}
break;
#endif // EDITOR
#ifdef MOZ_MAIL_NEWS
case ID_TOOLS_NEWS:
{
HandleNewsNotification(lParam);
}
break;
case ID_FILE_NEWMESSAGE:
{
HandleComposeNotification(lParam);
}
break;
case ID_TOOLS_ADDRESSBOOK:
{
HandleAddressBookNotification(lParam);
}
break;
#endif /* MOZ_MAIL_NEWS */
}
return(1L);
} // END OF FUNCTION CHiddenFrame::OnTaskNotify()
#ifdef MOZ_MAIL_NEWS
/****************************************************************************
*
* CHiddenFrame::HandleMailNotification
*
* PARAMETERS:
* lMessage - mouse notification message
*
* RETURNS:
* void
*
* DESCRIPTION:
* This is the mouse event notification handler for the mail icon
* located in the Task Bar.
*
****************************************************************************/
void CHiddenFrame::HandleMailNotification(LONG lMessage)
{
switch (lMessage)
{
case WM_LBUTTONUP:
{
if(!theApp.m_bKioskMode) { // TODO: is this still relevant?
WFE_MSGOpenInbox();
}
}
break;
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
break;
}
} // END OF FUNCTION CHiddenFrame::HandleMailNotification()
/****************************************************************************
*
* CHiddenFrame::HandleInboxNotification
*
* PARAMETERS:
* lMessage - mouse notification message
*
* RETURNS:
* void
*
* DESCRIPTION:
* This is the mouse event notification handler for the inbox icon
* located in the Task Bar.
*
****************************************************************************/
void CHiddenFrame::HandleInboxNotification(LONG lMessage)
{
switch (lMessage)
{
case WM_LBUTTONUP:
{
// Single click on mail icon means bring forth the mail window,
// check mail too if it wasn't already open.
if(!theApp.m_bKioskMode) // TODO: is this still relevant?
{
WFE_MSGOpenInbox(TRUE);
}
}
break;
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
break;
}
} // END OF FUNCTION CHiddenFrame::HandleMailNotification()
#endif /* MOZ_MAIL_NEWS */
/****************************************************************************
*
* CHiddenFrame::HandleWebNotification
*
* PARAMETERS:
* lMessage - mouse notification message
*
* RETURNS:
* void
*
* DESCRIPTION:
* This is the mouse event notification handler for the Web icon
* located in the Task Bar.
*
****************************************************************************/
void CHiddenFrame::HandleWebNotification(LONG lMessage)
{
switch (lMessage)
{
case WM_LBUTTONUP:
{
/* CAbstractCX *pCX = FEU_GetLastActiveFrameContext(MWContextAny);
CFrameWnd * pFrame = FEU_GetLastActiveFrame(MWContextAny);
if (pFrame && IsKindOf(RUNTIME_CLASS(CGenericFrame))) {
((CGenericFrame*)pFrame)->OnToolsWeb();
} else {
theApp.m_ViewTmplate->OpenDocumentFile( NULL );
}*/
BOOL bHandledMessage = FALSE;
CFrameWnd * pFrame = FEU_GetLastActiveFrame(MWContextAny);
if(pFrame)
if(pFrame->SendMessage(WM_COMMAND, WPARAM(ID_TOOLS_WEB), 0))
bHandledMessage = TRUE;
if(!bHandledMessage)
theApp.m_ViewTmplate->OpenDocumentFile( NULL );
}
break;
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
break;
}
} // END OF FUNCTION CHiddenFrame::HandleWebNotification()
#ifdef MOZ_MAIL_NEWS
/****************************************************************************
*
* CHiddenFrame::HandleNewsNotification
*
* PARAMETERS:
* lMessage - mouse notification message
*
* RETURNS:
* void
*
* DESCRIPTION:
* This is the mouse event notification handler for the news icon
* located in the Task Bar.
*
****************************************************************************/
void CHiddenFrame::HandleNewsNotification(LONG lMessage)
{
switch (lMessage)
{
case WM_LBUTTONUP:
{
if(!theApp.m_bKioskMode) { // TODO: is this still relevant?
WFE_MSGOpenNews();
}
}
break;
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
break;
}
} // END OF FUNCTION CHiddenFrame::HandleNewsNotification()
#endif /* MOZ_MAIL_NEWS */
#ifdef EDITOR
/****************************************************************************
*
* CHiddenFrame::HandleEditorNotification
*
* PARAMETERS:
* lMessage - mouse notification message
*
* RETURNS:
* void
*
* DESCRIPTION:
* This is the mouse event notification handler for the Compose icon
* located in the Task Bar.
*
****************************************************************************/
void CHiddenFrame::HandleEditorNotification(LONG lMessage)
{
switch (lMessage)
{
case WM_LBUTTONUP:
{
// Find last active editor/browser and find or launch new editor from there
// 2/17/96 - fixed bug 45611. Was creating disabled editor window when invoked from a
// Mail window. We need to look for any active frame, not just Browser frame.
// We send a message instead of assuming that it's a generic frame because the
// the inplace frame could be the last active frame.
CFrameWnd * pFrame = FEU_GetLastActiveFrame(MWContextAny, TRUE);
if (pFrame) {
pFrame->SendMessage(WM_COMMAND, WPARAM(ID_TOOLS_EDITOR), 0);
} else {
// there should always be an active frame.
ASSERT(FALSE); // FE_CreateNewEditWindow(NULL, NULL);
}
}
break;
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
break;
}
} // END OF FUNCTION CHiddenFrame::HandleWebNotification()
#endif
#ifdef MOZ_MAIL_NEWS
/****************************************************************************
*
* CHiddenFrame::HandleComposeNotification
*
* PARAMETERS:
* lMessage - mouse notification message
*
* RETURNS:
* void
*
* DESCRIPTION:
* This is the mouse event notification handler for the compose icon
* located in the Task Bar.
*
****************************************************************************/
void CHiddenFrame::HandleComposeNotification(LONG lMessage)
{
switch (lMessage)
{
case WM_LBUTTONUP:
{
CGenericFrame * pFrame = (CGenericFrame * )FEU_GetLastActiveFrame();
ASSERT(pFrame != NULL);
if (pFrame != NULL)
{
CAbstractCX * pCX = pFrame->GetMainContext();
if (pCX)
{
MSG_Mail ( pCX->GetContext() );
}
}
}
break;
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
break;
}
} // END OF FUNCTION CHiddenFrame::HandleNewsNotification()
void CHiddenFrame::HandleAddressBookNotification(LONG lMessage)
{
switch (lMessage)
{
case WM_LBUTTONUP:
CAddrFrame::Open();
break;
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
break;
}
} // END OF FUNCTION CHiddenFrame::HandleAddressBookNotification()
#endif /* MOZ_MAIL_NEWS */
//~~av
// added this message handler not to allow it to fall through the default
// MFC processing. Needed for bug 44748 fix when it crashed on system shutdown
// if plugin was running
BOOL CHiddenFrame::OnQueryEndSession()
{
return TRUE;
}
void CHiddenFrame::OnEndSession(BOOL bEnding)
{
if(bEnding) {
#ifdef MOZ_MAIL_NEWS
WFE_MSGShutdown();
#endif /* MOZ_MAIL_NEWS */
// Close all frames, and we'll exit.
PostMessage(WM_COMMAND, ID_APP_SUPER_EXIT, 0);
}
}
static LONG ProcessNetscapeProbeHook( WPARAM, LPARAM );
// rhp - 12/5/97
// This will simply turn around and call the function
// LONG ProcessNetscapeMAPIHook(WPARAM wParam, LPARAM lParam);
// and return the result. This is all for MAPI support in
// Communicator
//
LONG CHiddenFrame::OnProcessIPCHook(WPARAM wParam, LPARAM lParam)
{
PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT) lParam;
if (!pcds)
return(-1);
#ifdef MOZ_MAIL_NEWS
// Now check for what type of IPC message this really is?
if ((pcds->dwData > NSCP_MAPIStartRequestID) && (pcds->dwData < NSCP_MAPIEndRequestID))
{
return ( ProcessNetscapeMAPIHook(wParam, lParam) );
}
else if ((pcds->dwData > NSCP_NABStartRequestID) && (pcds->dwData < NSCP_NABEndRequestID))
{
return ( ProcessNetscapeNABHook(wParam, lParam) ); // 3-17: Address book API
}
#endif
// Not MAPI/NAB, try layout probe API...
else if ((pcds->dwData > NSCP_Probe_StartRequestID) && (pcds->dwData < NSCP_Probe_EndRequestID))
{
return ( ProcessNetscapeProbeHook(wParam, lParam) );
}
return(-1);
}
#ifdef MOZ_MAIL_NEWS
// rhp - new stuff for Address call...
void CHiddenFrame::AddressDialog(LPSTR winText,
MAPIAddressCallbackProc mapiCB,
MAPIAddressGetAddrProc getProc)
{
CAddrDialog AddressDialog(this, TRUE, winText, mapiCB, getProc);
AddressDialog.DoModal();
}
#endif /* MOZ_MAIL_NEWS */
/* Ordinal2Context
*
* Takes a simple ordinal (position in list) and returns the MWContext
* associated with that browser window. This is required by the
* layout probe server proc.
*/
static MWContext *Ordinal2Context( long context ) {
MWContext *result = 0;
// Loop through context list.
MWContext *pTraverseContext = NULL;
CAbstractCX *pTraverseCX = NULL;
XP_List *pTraverse = XP_GetGlobalContextList();
while (!result && ( pTraverseContext = (MWContext *)XP_ListNextObject(pTraverse) )) {
if(pTraverseContext != NULL && ABSTRACTCX(pTraverseContext) != NULL) {
pTraverseCX = ABSTRACTCX(pTraverseContext);
if(pTraverseCX->GetContext()->type == MWContextBrowser &&
pTraverseCX->IsFrameContext() == TRUE &&
pTraverseCX->IsDestroyed() == FALSE) {
CWinCX *pWinCX = (CWinCX *)pTraverseCX;
if(pWinCX->GetFrame()->GetFrameWnd() != NULL) {
// This is a context for a frame window. Decrement count
// and quit when it hits zero.
if ( --context == 0 ) {
// Result is the associated context.
result = pWinCX->GetContext();
}
}
}
}
}
return result;
}
static LONG ProcessNetscapeProbeHook( WPARAM wParam, LPARAM lParam ) {
static BOOL triedProbe = FALSE;
static HINSTANCE hProbe = 0;
static PROBESERVERPROC serverProc = 0;
static PROBEAPITABLE fnTbl = { LO_QA_CreateProbe,
LO_QA_DestroyProbe,
LO_QA_GotoFirstElement,
LO_QA_GotoNextElement,
LO_QA_GotoChildElement,
LO_QA_GotoParentElement,
LO_QA_GetElementType,
LO_QA_GetElementXPosition,
LO_QA_GetElementYPosition,
LO_QA_GetElementWidth,
LO_QA_GetElementHeight,
LO_QA_HasURL,
LO_QA_HasText,
LO_QA_HasColor,
LO_QA_HasChild,
LO_QA_HasParent,
LO_QA_GetText,
LO_QA_GetTextLength,
(BOOL(*)(long,long*,PROBECOLORTYPE))LO_QA_GetColor,
Ordinal2Context };
// Try one time to get the layout probe hook.
if ( !triedProbe ) {
triedProbe = TRUE;
// First, load the DLL.
hProbe = LoadLibrary( mozProbeDLLName );
if ( hProbe ) {
// Get the entry point for the server proc.
serverProc = (PROBESERVERPROC)GetProcAddress( hProbe, mozProbeServerProcName );
if ( !serverProc ) {
// Something wrong, free the DLL.
FreeLibrary( hProbe );
}
}
}
// If possible, process the layout probe hook.
if ( serverProc ) {
return ( serverProc(wParam, lParam, &fnTbl) );
}
return -1;
}