gecko-dev/cmd/winfe/dde.cpp
1998-06-05 01:03:18 +00:00

4399 lines
127 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.
*/
// File to handle DDE remote control commands.
#include "stdafx.h"
#include "genframe.h"
#include "wfedde.h"
#include "ddectc.h"
#include "regproto.h"
#include "winclose.h"
#include "presentm.h"
#include "urlecho.h"
#include "mainfrm.h"
#include "prefapi.h" // Added so that prefs can be referenced (Dave Hyatt - 8/13/97)
#include "net.h" // Added so cache can be referenced (8/18/97)
#include "netcache.h" // Ditto
#include "cxprint.h" // The printing context... used for PrintWindow and PrintURL (8/27/97)
#include "animecho.h"
// Our DDE instance identifier.
DWORD CDDEWrapper::m_dwidInst;
// Wether or not DDE was successfully initialized.
BOOL CDDEWrapper::m_bDDEActive;
// Our array of hsz strings.
HSZ CDDEWrapper::m_hsz[CDDEWrapper::m_MaxHSZ];
// A list of all current conversations. The PtrToPtr map was used since
// the pointers are known to be 32 bits long, and the HCONV is a
// DWORD or possibly a pointer, and WordToPtr just wouldn't cut it
// with 16 bits and all.
CMapPtrToPtr CDDEWrapper::m_ConvList;
// Command filter for DDEML
DWORD CDDEWrapper::m_dwafCmd;
// Call back function for use with DDEML
FARPROC CDDEWrapper::m_pfnCallBack;
// Array of acceptable clipboard formats in our CallBack
// Null terminate, please.
UINT CDDEWrapper::m_cfFmts[] = { CF_TEXT, 0 };
// Purpose: Initialize our DDE layer
// Arguments: void
// Returns: void
// Comments: Sets all CDDEWrapper static members and makes our DDE
// service available to the DDEML.
// We won't warn the user on an invalid initialization,
// as they probably won't be using this DDE layer if
// they have a screwed up setup....
// Revision History:
// 12-28-94 created GAB
void DDEStartup()
{
// Initialize all CDDEWrapper static members here.
// No CDDEWrapper instances exist at this point.
// Note that m_cfFmts is already intialized, m_ConvList should
// be initially already empty.
CDDEWrapper::m_dwidInst = 0L;
CDDEWrapper::m_bDDEActive = FALSE;
for(int i_counter = 0; i_counter < CDDEWrapper::m_MaxHSZ;
i_counter++) {
CDDEWrapper::m_hsz[i_counter] = NULL;
}
CDDEWrapper::m_dwafCmd = APPCLASS_STANDARD
| CBF_FAIL_SELFCONNECTIONS;
CDDEWrapper::m_pfnCallBack = NULL;
#ifdef XP_WIN16
// Find out if we can even use DDEML (must be in protected mode).
// Undoubtedly, this is the case since we must be in protected
// mode to use WINSOCK services, but just to be anal....
// GetWinFlags() has been removed in MSVC 2.0 and the analog doesn't
// look like it does the same thing. chouck 29-Dec-94
if(!(GetWinFlags() & WF_PMODE)) {
// Not in protected mode, can not continue with DDEML
return;
}
#endif
// Set up our callback function to be registered with DDEML.
CDDEWrapper::m_pfnCallBack = (FARPROC)NetscapeDDECallBack;
// DDEML initialization, don't do anything on failure.
if(DdeInitialize(&CDDEWrapper::m_dwidInst,
(PFNCALLBACK)CDDEWrapper::m_pfnCallBack,
CDDEWrapper::m_dwafCmd, 0L)) {
// Unable to initialize, don't continue.
return;
}
// We're DDEed.
CDDEWrapper::m_bDDEActive = TRUE;
// Load in all frequently used HSZs.
// Unfortunately, there is really no good way to detect any errors
// on these string intializations, so let the blame land
// where it will if something fails; we could actually just
// call shutdown and return if need be....
// Ugh. I hate CStrings reason #59: passing it as a (char *) requires
// a nasty cast like the one below. Chouck 29-Dec-94
CString CS;
CS.LoadString(IDS_DDE_SERVICE_NAME);
CDDEWrapper::m_hsz[CDDEWrapper::m_ServiceName] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_OPENURL);
CDDEWrapper::m_hsz[CDDEWrapper::m_OpenURL] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_SHOWFILE);
CDDEWrapper::m_hsz[CDDEWrapper::m_ShowFile] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_ACTIVATE);
CDDEWrapper::m_hsz[CDDEWrapper::m_Activate] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_LISTWINDOWS);
CDDEWrapper::m_hsz[CDDEWrapper::m_ListWindows] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_GETWINDOWINFO);
CDDEWrapper::m_hsz[CDDEWrapper::m_GetWindowInfo] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_PARSEANCHOR);
CDDEWrapper::m_hsz[CDDEWrapper::m_ParseAnchor] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_EXIT);
CDDEWrapper::m_hsz[CDDEWrapper::m_Exit] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_REGISTERPROTOCOL);
CDDEWrapper::m_hsz[CDDEWrapper::m_RegisterProtocol] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_UNREGISTERPROTOCOL);
CDDEWrapper::m_hsz[CDDEWrapper::m_UnRegisterProtocol] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_REGISTERVIEWER);
CDDEWrapper::m_hsz[CDDEWrapper::m_RegisterViewer] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_QUERYVIEWER);
CDDEWrapper::m_hsz[CDDEWrapper::m_QueryViewer] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_VIEWDOCFILE);
CDDEWrapper::m_hsz[CDDEWrapper::m_ViewDocFile] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_UNREGISTERVIEWER);
CDDEWrapper::m_hsz[CDDEWrapper::m_UnRegisterViewer] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_REGISTERURLECHO);
CDDEWrapper::m_hsz[CDDEWrapper::m_RegisterURLEcho] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_URLECHO);
CDDEWrapper::m_hsz[CDDEWrapper::m_URLEcho] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_UNREGISTERURLECHO);
CDDEWrapper::m_hsz[CDDEWrapper::m_UnRegisterURLEcho] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_REGISTERWINDOWCHANGE);
CDDEWrapper::m_hsz[CDDEWrapper::m_RegisterWindowChange] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_WINDOWCHANGE);
CDDEWrapper::m_hsz[CDDEWrapper::m_WindowChange] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_UNREGISTERWINDOWCHANGE);
CDDEWrapper::m_hsz[CDDEWrapper::m_UnRegisterWindowChange] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_BEGINPROGRESS);
CDDEWrapper::m_hsz[CDDEWrapper::m_BeginProgress] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_SETPROGRESSRANGE);
CDDEWrapper::m_hsz[CDDEWrapper::m_SetProgressRange] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_MAKINGPROGRESS);
CDDEWrapper::m_hsz[CDDEWrapper::m_MakingProgress] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_ENDPROGRESS);
CDDEWrapper::m_hsz[CDDEWrapper::m_EndProgress] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_ALERT);
CDDEWrapper::m_hsz[CDDEWrapper::m_Alert] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_VERSION);
CDDEWrapper::m_hsz[CDDEWrapper::m_Version] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_CANCELPROGRESS);
CDDEWrapper::m_hsz[CDDEWrapper::m_CancelProgress] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_QUERYURLFILE);
CDDEWrapper::m_hsz[CDDEWrapper::m_QueryURLFile] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_LISTFRAMECHILDREN);
CDDEWrapper::m_hsz[CDDEWrapper::m_ListFrameChildren] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_GETFRAMEPARENT);
CDDEWrapper::m_hsz[CDDEWrapper::m_GetFrameParent] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_REGISTERSTATUSBARCHANGE);
CDDEWrapper::m_hsz[CDDEWrapper::m_RegisterStatusBarChange] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_STATUSBARCHANGE);
CDDEWrapper::m_hsz[CDDEWrapper::m_StatusBarChange] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_UNREGISTERSTATUSBARCHANGE);
CDDEWrapper::m_hsz[CDDEWrapper::m_UnRegisterStatusBarChange] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_NAVIGATEBACK);
CDDEWrapper::m_hsz[CDDEWrapper::m_NavigateBack] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_NAVIGATEFORWARD);
CDDEWrapper::m_hsz[CDDEWrapper::m_NavigateForward] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_RELOAD);
CDDEWrapper::m_hsz[CDDEWrapper::m_Reload] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_STOP);
CDDEWrapper::m_hsz[CDDEWrapper::m_Stop] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_GETDOCWIDTH);
CDDEWrapper::m_hsz[CDDEWrapper::m_GetDocumentWidth] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_GETDOCHEIGHT);
CDDEWrapper::m_hsz[CDDEWrapper::m_GetDocumentHeight] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_USERAGENT);
CDDEWrapper::m_hsz[CDDEWrapper::m_UserAgent] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_CACHE_CLEARCACHE);
CDDEWrapper::m_hsz[CDDEWrapper::m_Cache_ClearCache] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_CACHE_FILENAME);
CDDEWrapper::m_hsz[CDDEWrapper::m_Cache_Filename] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_CACHE_INCACHE);
CDDEWrapper::m_hsz[CDDEWrapper::m_Cache_InCache] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_CACHE_REMOVEURL);
CDDEWrapper::m_hsz[CDDEWrapper::m_Cache_RemoveURL] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_CACHE_ADDURL);
CDDEWrapper::m_hsz[CDDEWrapper::m_Cache_AddURL] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_HISTORY_REMOVEURL);
CDDEWrapper::m_hsz[CDDEWrapper::m_History_RemoveURL] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_HISTORY_ADDURL);
CDDEWrapper::m_hsz[CDDEWrapper::m_History_AddURL] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_HISTORY_INHISTORY);
CDDEWrapper::m_hsz[CDDEWrapper::m_History_InHistory] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_HISTORY_CLEARHISTORY);
CDDEWrapper::m_hsz[CDDEWrapper::m_History_ClearHistory] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_HISTORY_NUMENTRIES);
CDDEWrapper::m_hsz[CDDEWrapper::m_History_NumEntries] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_HISTORY_GETENTRY);
CDDEWrapper::m_hsz[CDDEWrapper::m_History_GetEntry] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_GETWINDOWID);
CDDEWrapper::m_hsz[CDDEWrapper::m_GetWindowID] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_SUPPORTSMIMETYPE);
CDDEWrapper::m_hsz[CDDEWrapper::m_SupportsMimeType] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_EXECUTEJAVASCRIPT);
CDDEWrapper::m_hsz[CDDEWrapper::m_ExecuteJavaScript] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_PRINTWINDOW);
CDDEWrapper::m_hsz[CDDEWrapper::m_PrintWindow] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_PRINTURL);
CDDEWrapper::m_hsz[CDDEWrapper::m_PrintURL] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
// Added by DWH 4/98
CS.LoadString(IDS_DDE_REGISTERANIMATIONECHO);
CDDEWrapper::m_hsz[CDDEWrapper::m_RegisterAnimationEcho] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_UNREGISTERANIMATIONECHO);
CDDEWrapper::m_hsz[CDDEWrapper::m_UnRegisterAnimationEcho] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
CS.LoadString(IDS_DDE_ANIMATIONECHO);
CDDEWrapper::m_hsz[CDDEWrapper::m_AnimationEcho] =
DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
(char *)(const char *)CS, CP_WINANSI);
// Register our Name Service with DDEML; we are prepared to rock.
// Ignore any error, we could call shutdown if need really be....
DdeNameService(CDDEWrapper::m_dwidInst,
CDDEWrapper::m_hsz[CDDEWrapper::m_ServiceName], NULL,
DNS_REGISTER);
TRACE("DDE started, forgive me, father....\n");
}
// Purpose: Shut down any intitialization that occurred previously
// Arguments: void
// Returns: void
// Comments: Won't call any DDE functions if there is no need.
// Revision History:
// 12-28-94 created GAB
void DDEShutdown()
{
// First see if we're DDEed.
if(CDDEWrapper::m_bDDEActive == TRUE) {
// Turn off all our name services.
DdeNameService(CDDEWrapper::m_dwidInst,
CDDEWrapper::m_hsz[CDDEWrapper::m_ServiceName], NULL,
DNS_UNREGISTER);
// Get rid of all our HSZ strings.
// We have to finish up all DDE calls before we call DdeUnInitialize
// (that's the current theory), so just do this and don't
// worry about the side effects if we can't unitialize.
for(int i_counter = 0; i_counter < CDDEWrapper::m_MaxHSZ;
i_counter++) {
if(CDDEWrapper::m_hsz[i_counter] != NULL) {
// Ignore errors. No proper way to handle them on wind
// down. Will not hurt initialization at a later
// time as Windows recycles these strings.
DdeFreeStringHandle(CDDEWrapper::m_dwidInst,
CDDEWrapper::m_hsz[i_counter]);
CDDEWrapper::m_hsz[i_counter] = NULL;
}
}
// We have no real way of recognizing why we can't deinitialize
// our DDE layer, so just return if unable....
if(DdeUninitialize(CDDEWrapper::m_dwidInst) == 0) {
// System won't let us unitialize.
// Just return without disabling the callback and current
// conversations; it will be up to the system to clean
// this up and handle the abscense of any missing HSZs...
TRACE("Couldn't shut down DDE.\n");
return;
}
// Reset value for consistancy.... Someone, one day, might
// for some reason shut us down, and then restart. Best
// not to keep state between periods.
CDDEWrapper::m_dwidInst = 0L;
CDDEWrapper::m_bDDEActive = FALSE;
CDDEWrapper::m_dwafCmd = 0L;
}
// Erase the pointer to the callback.
CDDEWrapper::m_pfnCallBack = NULL;
// DDEML and the CallBack are dead.
// Kill off any dead conversation objects that we have, unbiased.
// Chances are, that if we receive appropriate disconnects when
// deinitializing, that we won't have any conversations anyhow,
// though I can't guarantee windows is so well thought out in
// this regard.
// It should be noted here that the list management is actually
// maintained by the CDDEWrapper constructor, and destructor,
// respectively.
CDDEWrapper *pWrap;
void *vp_dump, *vp_wrap;
POSITION pos;
while(CDDEWrapper::m_ConvList.IsEmpty() != 0) {
pos = CDDEWrapper::m_ConvList.GetStartPosition();
if(pos == NULL) {
// don't know how this would happen.
// don't let it happen though.
break;
}
// Get the valid pointer to the DDEWrapper
CDDEWrapper::m_ConvList.GetNextAssoc(pos, vp_dump, vp_wrap);
pWrap = (CDDEWrapper *)vp_wrap;
// Is this a valid entry anyhow?
if(pWrap != NULL) {
// Actually remove the object from memory
delete pWrap;
}
}
// Shutdown complete.
// If someone needed to, they could call our startup function
// again and start this whole thing over again now.
TRACE("DDE shutdown is complete.\n");
}
// Purpose: A callback function for the DDEML DLL, and to possibly
// multiplex custom calls in from our own application.
// Arguments: type Specifies the type of the current transation.
// fmt Specifies the format in which data is to be sent
// or received
// hconv Identifies the conversation associated with the
// current transaction
// hsz1 Identifies a string, the context of which is
// decided by the current transaction type
// hsz2 ditto
// hData Identifies some DDE data, the context of which is
// decided by the current transaction type
// dwData1 Specifies tranaction specific data
// dwData2 ditto
// Returns: HDDEDATA The actual return type is relative to the
// type of the transaction.
// Comments: Multiplexes all conversations to their appropriate
// CDDEWrapper instance, or ignores them.
// Due to the nature of Callbacks, and exported functions,
// DO NOT USE TRACES HERE, or GPF.
// The code will have to be air tight first time through,
// be careful.
// Revision History:
// 12-28-94 created GAB
// 12-30-94 Began fleshing out else ifs and switch statement
// to multiplex DDE transactions.
// This is likely to be one of the most monstrous
// functions I'll ever write.
HDDEDATA
CALLBACK
#ifndef XP_WIN32
_export
#endif
NetscapeDDECallBack(UINT type, UINT fmt,
HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hData, DWORD dwData1,
DWORD dwData2)
{
// First, are we correctly initialized?
if(CDDEWrapper::m_bDDEActive == FALSE) {
return(NULL);
}
// Do we support the format they are requesting?
// Fall through on not specified.
if(fmt) {
// Look through our list of supported formats, until we hit
// NULL at the end.
for(int i_counter = 0; 1; i_counter++) {
if(CDDEWrapper::m_cfFmts[i_counter] == 0) {
// End of list, and no match, fail.
return(NULL);
}
if(CDDEWrapper::m_cfFmts[i_counter] == fmt) {
// Matched, so break.
break;
}
}
}
// Depending on the class of transaction, we return different data.
if(type & XCLASS_BOOL) {
// Must return (HDDEDATA)TRUE or (HDDEDATA)FALSE
switch(type) {
case XTYP_ADVSTART: {
// We are the server.
// A client specified the XTYP_ADVSTART in a call to
// DdeClientTransaction
break;
}
case XTYP_CONNECT: {
// We are the server.
// A client call the DdeConnect specifying a service and
// topic name which we support.
HSZ& hszTopic = hsz1;
HSZ& hszService = hsz2;
// Deny the connection if the service name is not the
// one we are taking connections for.
if(hszService !=
CDDEWrapper::m_hsz[CDDEWrapper::m_ServiceName]) {
return((HDDEDATA)FALSE);
}
// Now, the topic can be NULL, or it can be any one of our
// topic names to be accepted.
if(hszTopic == NULL) {
return((HDDEDATA)TRUE);
}
// Go through all our topics, see if we match.
if(0 != CDDEWrapper::EnumTopic(hszTopic)) {
return((HDDEDATA)TRUE);
}
// Topic not supported
return((HDDEDATA)FALSE);
}
default:
// unknown
return((HDDEDATA)FALSE);
}
// Break handled here
return((HDDEDATA)FALSE);
}
else if(type & XCLASS_DATA) {
// Must return DDE data handle, CBR_BLOCK, or NULL
switch(type) {
case XTYP_ADVREQ: {
// We are the server.
// We called DdePostAdvise indicating that the data of
// an item in the advise loop had changed.
break;
}
case XTYP_REQUEST: {
// We are the server.
// A client said XTYP_REQUEST in DdeClientTransaction
HSZ& hszTopic = hsz1;
HSZ& hszItem = hsz2;
// Get the object associated with this conversation,
// and let it handle the request.
CDDEWrapper *pWrap = CDDEWrapper::GetConvObj(hconv);
if(pWrap != NULL) {
return(pWrap->RequestHandler(hszTopic, hszItem));
}
break;
}
case XTYP_WILDCONNECT: {
// We are the server
// A client called DdeConnect or DdeConnectList specifying
// NULL for the service name, the topic name, or both
HSZ& hszTopic = hsz1;
HSZ& hszService = hsz2;
// One way we can deny this type of connection is
// if the service name is not null, and is not our
// service name.
if(hszService != NULL) {
if(hszService !=
CDDEWrapper::m_hsz[CDDEWrapper::m_ServiceName]) {
return(NULL);
}
}
// The only other way we can deny this type of connection
// is if the topic name is not one that we support.
// Skip the service name.
if(hszTopic != NULL) {
if(0 == CDDEWrapper::EnumTopic(hszTopic)) {
// Topic wasn't matched.
return(NULL);
}
}
// Obviously, we're going to be accepting this connection.
// We have to return all matching service/topic pairs
// that were given to us.
// Get an array of HSZPAIRs that is big enough to take
// all our topics.
HSZPAIR ahszpair[CDDEWrapper::m_MaxHSZ + 1 -
CDDEWrapper::m_TopicStart];
// Match up all service/topic matches.
int i_depth = 0;
for(int i_counter = CDDEWrapper::m_TopicStart; i_counter <
CDDEWrapper::m_MaxHSZ; i_counter++) {
// See if we are over an appropriate topic.
if(hszTopic == NULL || hszTopic ==
CDDEWrapper::m_hsz[i_counter]) {
// Assign stuff over, don't care about service name,
// we only have one.
ahszpair[i_depth].hszSvc =
CDDEWrapper::m_hsz[CDDEWrapper::m_ServiceName];
ahszpair[i_depth].hszTopic =
CDDEWrapper::m_hsz[i_counter];
// We are one further in the array.
i_depth++;
}
}
// Cap off the list with some NULLs, i_depth is correctly
// set.
ahszpair[i_depth].hszSvc = NULL;
ahszpair[i_depth].hszTopic = NULL;
i_depth++;
// Create the array in the DDE way.
HDDEDATA pData = DdeCreateDataHandle(CDDEWrapper::m_dwidInst,
(unsigned char *) &ahszpair,
sizeof(HSZPAIR) * i_depth,
0L,
NULL,
fmt,
0);
// Return it. Don't care on failure, as it will be NULL
// anyhow.
return(pData);
}
default:
// unknown
return(NULL);
}
// Break handled here
return(NULL);
}
else if(type & XCLASS_FLAGS) {
// Must return DDE_FACK, DDE_BUSY, or DDE_FNOTPROCESSED
switch(type) {
case XTYP_ADVDATA: {
// We are the client.
// The server gave us a data handle.
break;
}
case XTYP_EXECUTE: {
// We are the server.
// A client said XTYP_EXECUTE in DdeClientTransaction
break;
}
case XTYP_POKE: {
// We are the Server
// A client said XTYP_POKE in DdeClientTransaction
HSZ& hszTopic = hsz1;
HSZ& hszItem = hsz2;
HDDEDATA& hDataPoke = hData;
// Get the object associated with this conversation,
// and let it handle the request.
CDDEWrapper *pWrap = CDDEWrapper::GetConvObj(hconv);
if(pWrap != NULL) {
return(pWrap->PokeHandler(hszTopic, hszItem, hDataPoke));
}
break;
}
default:
// unknown
return(DDE_FNOTPROCESSED);
}
// Break handled here
return(DDE_FNOTPROCESSED);
}
else if(type & XCLASS_NOTIFICATION) {
// Must return NULL, as the return value is ignored
switch(type) {
case XTYP_ADVSTOP: {
// We are the server
// A client said XTYP_ADVSTOP in DdeClientTransaction
break;
}
case XTYP_CONNECT_CONFIRM: {
// We are the server.
// We returned 1 to a XTYP_CONNECT transaction.
// This callback is mainly to inform us of the conversation
// handle that now exists, but we will actually be
// creating an instance of an object to handle this
// conversation from now on.
HSZ& hszTopic = hsz1;
HSZ& hszService = hsz2;
// Create the object, correctly initialized so that
// it understands the service, topic, and conversation
// it is handling.
// It will add itself to the conversation list.
CDDEWrapper *pObject = new CDDEWrapper(hszService, hszTopic,
hconv);
break;
}
case XTYP_DISCONNECT: {
// We are either client/server
// The partner in the conversation called DdeDisconnect
// causing both client/server to receive this.
// Find out which conversation object we are dealing with.
CDDEWrapper *pWrapper = CDDEWrapper::GetConvObj(hconv);
// Simply delete it.
// The object takes care of removing itself from the list.
if(pWrapper != NULL) {
delete pWrapper;
}
break;
}
case XTYP_ERROR: {
// We are either client/server
// A serious error has occurred.
// DDEML doesn't have any resources left to guarantee
// good communication.
break;
}
case XTYP_REGISTER: {
// We are either client/server
// A server application used DdeNameService to register
// a new service name.
break;
}
case XTYP_UNREGISTER: {
// We are either client/server
// A server applciation used DdeNameService to unregister
// an old service name.
break;
}
case XTYP_XACT_COMPLETE: {
// We are the client
// An asynchronous tranaction, sent when the client specified
// the TIMEOUT_ASYNC flag in DdeClientTransaction has
// concluded.
break;
}
default:
// unknown
return(NULL);
}
return(NULL);
}
// Unknown class type
return(NULL);
}
// Purpose: Construct a DDEWrapper object
// Arguments: hszService The name of the service we are handling.
// hszTopic The name of the topic we are handling.
// hConv The handle of the conversation we are
// handling.
// Returns: nothing
// Comments: Handles all created objects internally through a map.
// Revision History:
// 12-30-94 created GAB
CDDEWrapper::CDDEWrapper(HSZ hszService, HSZ hszTopic, HCONV hConv)
{
// Set our members passed in.
m_hszService = hszService;
m_hszTopic = hszTopic;
m_hConv = hConv;
// Figure out our enumerated service number.
// We know this anyhow, we only have one service name at this
// point.
m_iService = m_ServiceName;
// Figure out our enumerated topic number.
m_iTopic = EnumTopic(hszTopic);
// Add ourselves to the current map of conversations.
m_ConvList.SetAt((void *)hConv, this);
}
// Purpose: Destory a CDDEWrapper object
// Arguments: void
// Returns: nothing
// Comments: Removes us from the internally handled list
// Revision History:
// 12-30-94 created GAB
CDDEWrapper::~CDDEWrapper()
{
// Remove ourselves from the list of current conversations.
m_ConvList.RemoveKey((void *)m_hConv);
}
// Purpose: Figure out which wrapper is associated with a conversation.
// Arguments: hConv The conversation to find out about.
// Returns: CDDEWrapper * A pointer to the CDDEWrapper that is
// handling the conversation, or NULL
// if none is present.
// Comments: Shouldn't ever return NULL really.
// Revision History:
// 12-30-94 created GAB
CDDEWrapper *CDDEWrapper::GetConvObj(HCONV hConv)
{
// Query our static map of conversations for the object.
void *pWrap;
if(m_ConvList.Lookup((void *)hConv, pWrap) == 0) {
return(NULL);
}
return((CDDEWrapper *)pWrap);
}
// Purpose: Return the offset of the hsz topic string in our static
// m_hsz array
// Arguments: hsz The HSZ string to find in our array
// Returns: int The offset into the array, also correlating to
// it's enumerated value. If not found, the
// returned failure value is 0.
// Comments: Mainly coded to remove redundant lookups. Modularity...
// Revision History:
// 12-30-94 created GAB
int CDDEWrapper::EnumTopic(HSZ& hsz)
{
int i_retval = 0;
int i_counter;
// Just start looking for the HSZ string in our static array.
for(i_counter = m_TopicStart; i_counter < m_MaxHSZ; i_counter++)
{
if(m_hsz[i_counter] == hsz) {
i_retval = i_counter;
break;
}
}
return(i_retval);
}
// Purpose: Scan in the arguments with a specified format.
// Arguments: hszArgs The string containing the arguments, in string
// format.
// pFormat The format (order) that the strings will be
// scanned in.
// ... Variable number of parameters, decided by
// pFormat, that the values will be stored in.
// Returns: void
// Comments: Data should always be an exact match, no need for
// errors, do it right the first time.
// See below, as there will be some funky heuristics
// going on regarding some parameters and how they
// are represented.
// Of course, only pointers should be passed in as the
// variable number of arguments.
// ->Appropriate type casting here is a must, as we could
// possibly overwrite, or underwrite, data. This
// also means that all the parameters passed in must
// be correct!
// Never call this function with an empty format!
// Revision History:
// 12-31-94 created GAB
void CDDEWrapper::ScanArgs(HSZ& hszArgs, const char *pFormat, ...)
{
// Initialize variable number of argumetns.
va_list VarList;
va_start(VarList, pFormat);
// Set up some variables we are going to use.
int i_ArgNum = 0;
char *pScan = (char *)pFormat;
char *pExtract;
// Loop through the arguments we are going to parse.
while(pScan && *pScan) {
// What argument are we currently looking for?
// Extract it's value from our HSZ
i_ArgNum++;
pExtract = ExtractArg(hszArgs, i_ArgNum);
// Check it for currently supported types
if(0 == strncmp(pScan, "DW", 2)) {
// Why, it's a DWORD.
// Take the pointer to it off our argument list.
DWORD *pWord;
pWord = va_arg(VarList, DWORD *);
// If there is nothing to scan, use a default value.
if(pExtract == NULL) {
*pWord = 0x0;
}
else {
// Take the value.
*pWord = strtoul(pExtract, NULL, 0);
//sscanf(pExtract, "%lu", pWord);
}
}
else if(0 == strncmp(pScan, "QCS", 3)) {
// A quoted CString
CString *pCS = va_arg(VarList, CString *);
if(pExtract == NULL) {
pCS->Empty();
}
else {
// Fun thing about a qouted string, is that we need
// to compress and '\"' into '"'.
// Extractions took off the leading and ending quotes.
char *pCopy = pExtract;
while(*pCopy) {
if(*pCopy == '\\' && *(pCopy + 1) == '\"') {
pCopy++;
}
*pCS += *pCopy;
pCopy++;
}
}
}
else if(0 == strncmp(pScan, "CS", 2)) {
// A CString
CString *pCS = va_arg(VarList, CString *);
if(pExtract == NULL) {
pCS->Empty();
}
else {
// Just copy.
*pCS = pExtract;
}
}
else if(0 == strncmp(pScan, "BL", 2)) {
// A boolean
TwoByteBool *pBool = va_arg(VarList, TwoByteBool *);
if(pExtract == NULL) {
*pBool = FALSE;
}
else {
// Compare for a TRUE or a FALSE
if(0 == stricmp(pExtract, "TRUE")) {
*pBool = TRUE;
}
else {
*pBool = FALSE;
}
}
}
else {
// Doh!, not supported, just break out of the while loop.
ASSERT(0);
break;
}
// Go on to the next argument in our format string.
pScan = SkipToNextFormat(pScan);
// Free the memory that was used during extraction.
if(pExtract != NULL) {
delete pExtract;
}
}
// Done with variable number of arguments
va_end(VarList);
}
// Purpose: Scan in the arguments with a specified format.
// Arguments: hArgs The string containing the arguments, in string
// format (must convert to HSZ first).
// pFormat The format (order) that the strings will be
// scanned in.
// ... Variable number of parameters, decided by
// pFormat, that the values will be stored in.
// Returns: void
// Comments: Data should always be an exact match, no need for
// errors, do it right the first time.
// See below, as there will be some funky heuristics
// going on regarding some parameters and how they
// are represented.
// Of course, only pointers should be passed in as the
// variable number of arguments.
// ->Appropriate type casting here is a must, as we could
// possibly overwrite, or underwrite, data. This
// also means that all the parameters passed in must
// be correct!
// Never call this function with an empty format!
// Revision History:
// 01-05-95 created GAB
void CDDEWrapper::ScanDataArgs(HDDEDATA& hArgs, const char *pFormat, ...)
{
char *pDataArgs = (char *)DdeAccessData(hArgs, NULL);
// Initialize variable number of argumetns.
va_list VarList;
va_start(VarList, pFormat);
// With DATA args, it will be possible that with only one argument,
// that we are receiving raw data.
// Use this method.
if(strchr(pFormat, ',') == NULL) {
// Only one argument.
if(strcmp(pFormat, "DW") == 0) {
DWORD *pWord;
pWord = va_arg(VarList, DWORD *);
*pWord = *(DWORD *)pDataArgs;
DdeUnaccessData(hArgs);
va_end(VarList);
return;
}
else if(strcmp(pFormat, "BL") == 0) {
TwoByteBool *pBool;
pBool = va_arg(VarList, TwoByteBool *);
*pBool = *(TwoByteBool *)pDataArgs;
DdeUnaccessData(hArgs);
va_end(VarList);
return;
}
}
// Convert our hArgs to HSZ format.
HSZ hszArgs = DdeCreateStringHandle(m_dwidInst, pDataArgs,
CP_WINANSI);
DdeUnaccessData(hArgs);
// Set up some variables we are going to use.
int i_ArgNum = 0;
char *pScan = (char *)pFormat;
char *pExtract;
// Loop through the arguments we are going to parse.
while(pScan && *pScan) {
// What argument are we currently looking for?
// Extract it's value from our HSZ
i_ArgNum++;
pExtract = ExtractArg(hszArgs, i_ArgNum);
// Check it for currently supported types
if(0 == strncmp(pScan, "DW", 2)) {
// Why, it's a DWORD.
// Take the pointer to it off our argument list.
DWORD *pWord;
pWord = va_arg(VarList, DWORD *);
// If there is nothing to scan, use a default value.
if(pExtract == NULL) {
*pWord = 0x0;
}
else {
// Take the value.
*pWord = strtoul(pExtract, NULL, 0);
//sscanf(pExtract, "%lu", pWord);
}
}
else if(0 == strncmp(pScan, "QCS", 3)) {
// A quoted CString
CString *pCS = va_arg(VarList, CString *);
if(pExtract == NULL) {
pCS->Empty();
}
else {
// Fun thing about a qouted string, is that we need
// to compress and '\"' into '"'.
// Extractions took off the leading and ending quotes.
char *pCopy = pExtract;
while(*pCopy) {
if(*pCopy == '\\' && *(pCopy + 1) == '\"') {
pCopy++;
}
*pCS += *pCopy;
pCopy++;
}
}
}
else if(0 == strncmp(pScan, "CS", 2)) {
// A CString
CString *pCS = va_arg(VarList, CString *);
if(pExtract == NULL) {
pCS->Empty();
}
else {
// Just copy.
*pCS = pExtract;
}
}
else if(0 == strncmp(pScan, "BL", 2)) {
// A boolean
TwoByteBool *pBool = va_arg(VarList, TwoByteBool *);
if(pExtract == NULL) {
*pBool = FALSE;
}
else {
// Compare for a TRUE or a FALSE
if(0 == stricmp(pExtract, "TRUE")) {
*pBool = TRUE;
}
else {
*pBool = FALSE;
}
}
}
else {
// Doh!, not supported, just break out of the while loop.
ASSERT(0);
break;
}
// Go on to the next argument in our format string.
pScan = SkipToNextFormat(pScan);
// Free the memory that was used during extraction.
if(pExtract != NULL) {
delete pExtract;
}
}
// Done with variable number of arguments
va_end(VarList);
// Free off our created HSZ string.
DdeFreeStringHandle(m_dwidInst, hszArgs);
}
// Purpose: Create an argument list, as HDDEDATA
// Arguments: pFormat The format of the argument list
// ... The viarables correlating to the format
// Returns: HSZ The argument list (a string, really)
// Comments: HSZ is the return type because this will mainly
// be used to create return values back to the
// server.
// Do not screw up and pass in the wrong arguments, or
// a wrong format.
// Only pointers are accepted as arguments, because if
// a NULL is passed in, then it will be considered
// an optional non-existant argument. If this is
// not the case, then pass in a valid pointer,
// pointing to a valid argument.
// Revision History:
// 01-05-95 created GAB
HSZ CDDEWrapper::MakeItemArgs(const char *pFormat, ...)
{
// Safety dance
char *pTraverse = (char *)pFormat;
if(pTraverse == NULL || *pTraverse == '\0') {
return(NULL);
}
// Set up for variable number of arguments.
va_list VarList;
va_start(VarList, pFormat);
// Real simple.
// Go through our format, and append the string representation
// to our developing return value.
char caNumpad[64];
CString csBuffer;
CString csRetval;
while(*pTraverse) {
// Erase temp data from our last pass.
caNumpad[0] = '\0';
csBuffer.Empty();
// Compare our current format to the known formats
if(0 == strncmp(pTraverse, "DW", 2)) {
// A DWORD.
DWORD *pWord = va_arg(VarList, DWORD *);
if(pWord != NULL) {
sprintf(caNumpad, "%lu", *pWord);
csRetval += caNumpad;
}
}
else if(0 == strncmp(pTraverse, "CS", 2)) {
// A CString, not quoted
CString *pCS = va_arg(VarList, CString *);
if(pCS != NULL) {
csRetval += *pCS;
}
}
else if(0 == strncmp(pTraverse, "QCS", 3)) {
// A quoted CString
CString *pQCS = va_arg(VarList, CString *);
if(pQCS != NULL) {
csRetval += '\"';
// Need to escape any '"' to '\"', literally.
char *pConvert = (char *)(const char *)*pQCS;
while(*pConvert != '\0') {
if(*pConvert == '\"') {
csRetval += '\\';
}
csRetval += *pConvert;
pConvert++;
}
csRetval += '\"';
}
}
else if(0 == strncmp(pTraverse, "BL", 2)) {
// A boolean
TwoByteBool *pBool = va_arg(VarList, TwoByteBool *);
if(pBool != NULL) {
if(*pBool != FALSE) {
csRetval += "TRUE";
}
else {
csRetval += "FALSE";
}
}
}
else {
// Unhandled format, just get out of loop.
ASSERT(0);
break;
}
// Go on to next type
pTraverse = SkipToNextFormat(pTraverse);
// See if we need a comma
if(*pTraverse != '\0') {
csRetval += ',';
}
}
// Done with varargs.
va_end(VarList);
// Make sure we're atleast returning something.
if(csRetval.IsEmpty()) {
return(NULL);
}
// Return our resultant HSZ, created from our string, and
// the DDEML will own this once we return it.
HSZ Final = DdeCreateStringHandle(m_dwidInst, (char *)
(const char *)csRetval, CP_WINANSI);
return(Final);
}
// Purpose: Create an argument list, as HDDEDATA
// Arguments: pFormat The format of the argument list
// ... The viarables correlating to the format
// Returns: HDDEDATA The argument list (a string, really)
// Comments: HDDEDATA is the return type because this will mainly
// be used to create return values back to the
// client.
// Do not screw up and pass in the wrong arguments, or
// a wrong format.
// Only pointers are accepted as arguments, because if
// a NULL is passed in, then it will be considered
// an optional non-existant argument. If this is
// not the case, then pass in a valid pointer,
// pointing to a valid argument.
// Revision History:
// 01-02-95 created GAB
HDDEDATA CDDEWrapper::MakeArgs(const char *pFormat, ...)
{
// Safety dance
char *pTraverse = (char *)pFormat;
if(pTraverse == NULL || *pTraverse == '\0') {
return(NULL);
}
// Set up for variable number of arguments.
va_list VarList;
va_start(VarList, pFormat);
// Real simple.
// Go through our format, and append the string representation
// to our developing return value.
char caNumpad[64];
CString csBuffer;
CString csRetval;
while(*pTraverse) {
// Erase temp data from our last pass.
caNumpad[0] = '\0';
csBuffer.Empty();
// Compare our current format to the known formats
if(0 == strncmp(pTraverse, "DW", 2)) {
// A DWORD.
DWORD *pWord = va_arg(VarList, DWORD *);
if(pWord != NULL) {
sprintf(caNumpad, "%lu", *pWord);
csRetval += caNumpad;
}
}
else if(0 == strncmp(pTraverse, "CS", 2)) {
// A CString, not quoted
CString *pCS = va_arg(VarList, CString *);
if(pCS != NULL) {
csRetval += *pCS;
}
}
else if(0 == strncmp(pTraverse, "QCS", 3)) {
// A quoted CString
CString *pQCS = va_arg(VarList, CString *);
if(pQCS != NULL) {
csRetval += '\"';
// Need to escape any '"' to '\"', literally.
char *pConvert = (char *)(const char *)*pQCS;
while(*pConvert != '\0') {
if(*pConvert == '\"') {
csRetval += '\\';
}
csRetval += *pConvert;
pConvert++;
}
csRetval += '\"';
}
}
else if(0 == strncmp(pTraverse, "BL", 2)) {
// A boolean
TwoByteBool *pBool = va_arg(VarList, TwoByteBool *);
if(pBool != NULL) {
if(*pBool != FALSE) {
csRetval += "TRUE";
}
else {
csRetval += "FALSE";
}
}
}
else {
// Unhandled format, just get out of loop.
ASSERT(0);
break;
}
// Go on to next type
pTraverse = SkipToNextFormat(pTraverse);
// See if we need a comma
if(*pTraverse != '\0') {
csRetval += ',';
}
}
// Done with varargs.
va_end(VarList);
// Make sure we're atleast returning something.
if(csRetval.IsEmpty()) {
return(NULL);
}
// Return our resultant HDDEDATA, created from our string, be
// sure to copy over the terminating NULL, no offset, no
// item association, this is text, and the DDEML will own
// this once we return it.
HDDEDATA Final;
TRACE("Returning HDDEDATA: %s\n", (const char *)csRetval);
Final = DdeCreateDataHandle(m_dwidInst,
#ifdef XP_WIN16
(void *)(const char *)csRetval,
#else
(LPBYTE)(const char *)csRetval,
#endif
csRetval.GetLength() + 1, 0, m_hsz[m_ServiceName],
CF_TEXT, 0);
// Okay, we're not supposed to know this, but the minimum data size of this
// object is in increments of 32. So we're going to do a little proactive
// writing to it if need be.
// THIS IS A HACK.
// I just recently figured out that we need to return actual raw data to the
// calling application, so handle it here for now.
// This only happens if we have only one argument, check for commas.
// Forget the speed considerations, anyone using DDE is insane anyhow.
if(strchr(pFormat, ',') == NULL) {
if(strcmp(pFormat, "BL") == 0) {
// Scan in the value.
TwoByteBool bData = FALSE;
if(csRetval == "TRUE") {
bData = TRUE;
}
DdeFreeDataHandle(Final);
Final = DdeCreateDataHandle(m_dwidInst, (unsigned char *) &bData, sizeof(TwoByteBool), 0, m_hsz[m_ServiceName], CF_TEXT, 0);
}
else if(strcmp(pFormat, "DW") == 0) {
// Scan in the value.
DWORD dwData;
dwData = strtoul(csRetval, NULL, 0);
//sscanf(csRetval, "%lu", &dwData);
DdeFreeDataHandle(Final);
// Reset the value in a binary way.
Final = DdeCreateDataHandle(m_dwidInst, (unsigned char *) &dwData, sizeof(DWORD), 0, m_hsz[m_ServiceName], CF_TEXT, 0);
}
}
return(Final);
}
// Purpose: Move the pointer passed in to the next argument
// Arguments: pFormat the format string wanting to be incremented
// Returns: char * The next format.
// Comments:
// Revision History:
// 01-01-95 created GAB
char *CDDEWrapper::SkipToNextFormat(char *pFormat)
{
// Safety dance
if(pFormat == NULL || *pFormat == '\0') {
return(pFormat);
}
// The next format is directly after a ','
while(*pFormat != ',' && *pFormat != '\0') {
pFormat++;
}
if(*pFormat == ',') {
pFormat++;
}
return(pFormat);
}
// Purpose: Return an allocated char array conatining the contents
// of a specified argument.
// Arguments: hszArgs The HSZ of all arguments
// iArg Integer specifying which argument to extract.
// Returns: char * The allocated array containing the contents of
// argument iArg, or NULL if there is no such
// argument or if the argument was empty.
// Comments: Quoted strings are counted as only one argument, though
// the quotes are not copied into the return string.
// Revision History:
// 01-01-95 created GAB
char *CDDEWrapper::ExtractArg(HSZ& hszArgs, int iArg)
{
// Allocate some memory to retrieve infomation from out HSZ.
DWORD dwLength = DdeQueryString(m_dwidInst, hszArgs, NULL, 0L,
CP_WINANSI) + 1;
char *pTraverse = new char[dwLength];
char *pRemove = pTraverse;
if(pTraverse == NULL) {
return(NULL);
}
DdeQueryString(m_dwidInst, hszArgs, pTraverse, dwLength, CP_WINANSI);
// safety dance
if(*pTraverse == '\0' || iArg < 1) {
delete(pRemove);
return(NULL);
}
// Need to decrement the argument we're looking for, as the very
// first argument has no ',' at the beginning.
iArg--;
// Search through the arguments, seperated by ','.
while(iArg) {
// Special handling of quoted strings.
if(*pTraverse == '\"') {
// Find the ending quote.
while(*pTraverse != '\0') {
pTraverse++;
if(*pTraverse == '\"') {
pTraverse++; // One beyond, please
break;
}
else if(*pTraverse == '\\') {
// Attempting to embed a quoted, perhaps....
if(*(pTraverse + 1) == '\"') {
pTraverse++;
}
}
}
}
// Find the next comma
while(*pTraverse != '\0' && *pTraverse != ',') {
pTraverse++;
}
// Go beyond a comma
if(*pTraverse == ',') {
pTraverse++;
}
// Okay, we're at the next argument, decrement our argument
// count.
iArg--;
// By chance, if we're at the end of the string, break out of
// the loop.
if(*pTraverse == '\0') {
break;
}
}
// Handle empty arguments here.
if(*pTraverse == ',' || *pTraverse == '\0') {
delete(pRemove);
return(NULL);
}
// Count chars up to next comma, plus 1 (end of string stuff)
int iLength = 1;
char *pCounter = pTraverse;
TwoByteBool bQuoted = FALSE;
// specially handle quoted strings
if(*pCounter == '\"') {
// Go past initial quote.
pCounter++;
bQuoted = TRUE;
// Find the ending quote.
while(*pCounter != '\0') {
if(*pCounter == '\"') {
break;
}
else if(*pCounter == '\\') {
// Attempting to embed a quoted, perhaps....
if(*(pCounter + 1) == '\"') {
pCounter++;
iLength++;
}
}
pCounter++;
iLength++;
}
}
// Go to next comma
while(*pCounter != '\0' && *pCounter != ',') {
iLength++;
pCounter++;
}
// Subtrace one to ignore ending quote if we were quoted....
if(bQuoted == TRUE) {
iLength--;
}
// Argument's of length 1 are of no interest.
if(iLength == 1) {
delete(pRemove);
return(NULL);
}
// Okay, allocate some memory for the string, we'll copy it over.
char *pRetVal = new char[iLength];
if(*pTraverse == '\"') {
pTraverse++;
}
strncpy(pRetVal, pTraverse, iLength - 1);
pRetVal[iLength - 1] = '\0';
delete(pRemove);
// If pRetval begins with a caret, then detect if this is a file.
// We will substitue in file data if this is the case.
if(pRetVal && *pRetVal == '^') {
char *pFilename = pRetVal + 1;
if(*pFilename) {
CFileStatus cfs;
BOOL bValid = CFile::GetStatus(pFilename, cfs);
if(bValid) {
// We have a file.
// Allocate the number of bytes + 1 (for null termination).
char *pFileData = NULL;
TRY {
pFileData = new char[cfs.m_size + 1];
}
CATCH(CException, e) {
pFileData = NULL;
}
END_CATCH
if(pFileData != NULL) {
TRY {
// Leave as shared readable for DDE apps looking into the file early.
CFile cf(pFilename, CFile::modeRead | CFile::shareDenyWrite);
// Read in the data.
cf.Read(pFileData, CASTSIZE_T(cfs.m_size));
// Null terminate.
pFileData[cfs.m_size] = '\0';
}
CATCH(CException, e) {
// Opening or reading of the file failed.
delete pFileData;
pFileData = NULL;
}
END_CATCH
}
// If we have file data, swap with the return value.
if(pFileData) {
delete(pRetVal);
pRetVal = pFileData;
}
}
}
}
return(pRetVal);
}
// Purpose: Handle XTYP_REQUEST calls for this conversation.
// Arguments: hszTopic The topic-name of the conversation
// hszItem The item-name under this topic
// Returns: HDDEDATA Mainly, we will just pass back the return
// values of functions that we call
// depending upon our topic name. Look
// there.
// Comments: Second level muliplexor, for topics under an already
// multiplexed conversation.
// Server only code, here.
// I would have used function tables to index into the
// appropriate function on topic type, but the
// topics are not neccessarily grouped together in
// the same range as thier topic number.
// Revision History:
// 12-30-94 created GAB
HDDEDATA CDDEWrapper::RequestHandler(HSZ& hszTopic, HSZ& hszItem)
{
// Ensure this conversation is about the topic we think it is.
if(m_hsz[m_iTopic] != hszTopic) {
return(NULL);
}
TRACE("REQUEST topic %d\n", m_iTopic);
// Switch on all possible request topics, and pass params on down.
switch(m_iTopic) {
case m_OpenURL:
return(OpenURL(hszItem));
case m_ShowFile:
return(ShowFile(hszItem));
case m_Activate:
return(Activate(hszItem));
case m_ListWindows:
return(ListWindows(hszItem));
case m_GetWindowInfo:
return(GetWindowInfo(hszItem));
case m_ParseAnchor:
return(ParseAnchor(hszItem));
case m_RegisterProtocol:
return(RegisterProtocol(hszItem));
case m_UnRegisterProtocol:
return(UnRegisterProtocol(hszItem));
case m_RegisterViewer:
return(RegisterViewer(hszItem));
case m_UnRegisterViewer:
return(UnRegisterViewer(hszItem));
case m_RegisterWindowChange:
return(RegisterWindowChange(hszItem));
case m_UnRegisterWindowChange:
return(UnRegisterWindowChange(hszItem));
case m_BeginProgress:
return(BeginProgress(hszItem));
case m_MakingProgress:
return(MakingProgress(hszItem));
case m_EndProgress:
return(EndProgress(hszItem));
case m_Version:
return(Version(hszItem));
case m_QueryURLFile:
return(QueryURLFile(hszItem));
case m_ListFrameChildren:
return(ListFrameChildren(hszItem));
case m_GetFrameParent:
return(GetFrameParent(hszItem));
// Start of the Netscape 5.0 topics (Dave Hyatt - 8/13/97)
case m_RegisterStatusBarChange:
return(RegisterStatusBarChange(hszItem));
case m_UnRegisterStatusBarChange:
return(UnRegisterStatusBarChange(hszItem));
case m_NavigateBack:
return(NavigateBack(hszItem));
case m_NavigateForward:
return (NavigateForward(hszItem));
case m_Stop:
return (Stop(hszItem));
case m_Reload:
return (Reload(hszItem));
case m_UserAgent:
return (UserAgent(hszItem));
case m_Cache_ClearCache:
return (ClearCache(hszItem));
case m_Cache_Filename:
return (CacheFilename(hszItem));
case m_Cache_InCache:
return (InCache(hszItem));
case m_Cache_RemoveURL:
return (CacheRemoveURL(hszItem));
case m_Cache_AddURL:
return (CacheAddURL(hszItem));
case m_History_ClearHistory:
return (ClearHistory(hszItem));
case m_History_AddURL:
return (HistoryAddURL(hszItem));
case m_History_RemoveURL:
return (HistoryRemoveURL(hszItem));
case m_History_InHistory:
return (InHistory(hszItem));
case m_History_NumEntries:
return (HistoryNumEntries(hszItem));
case m_History_GetEntry:
return (HistoryGetEntry(hszItem));
case m_GetWindowID:
return (GetWindowID(hszItem));
case m_SupportsMimeType:
return (SupportsMimeType(hszItem));
case m_ExecuteJavaScript:
return (ExecuteJavaScript(hszItem));
case m_PrintWindow:
return (PrintWindow(hszItem));
case m_PrintURL:
return (PrintURL(hszItem));
}
// Default, should never reach.
return(NULL);
}
// Purpose: Handle XTYP_POKE calls for this conversation.
// Arguments: hszTopic The topic-name of the conversation
// hszItem The item-name under this topic
// hData Identifies data the client is sending to
// this server conversation.
// Returns: HDDEDATA Mainly, we will just pass back the return
// values of functions that we call
// depending upon our topic name. Look
// there.
// Comments: Second level muliplexor, for topics under an already
// multiplexed conversation.
// Server only code, here.
// I would have used function tables to index into the
// appropriate function on topic type, but the
// topics are not neccessarily grouped together in
// the same range as thier topic number.
// Revision History:
// 12-30-94 created GAB
HDDEDATA CDDEWrapper::PokeHandler(HSZ& hszTopic, HSZ& hszItem,
HDDEDATA& hData)
{
// Ensure this conversation is about the topic we think it is.
if(m_hsz[m_iTopic] != hszTopic) {
return(NULL);
}
TRACE("POKE topic %d\n", m_iTopic);
// Switch on all possible poke topics, and pass params on down.
switch(m_iTopic) {
case m_Exit:
return(Exit(hszItem, hData));
case m_SetProgressRange:
return(SetProgressRange(hszItem, hData));
case m_RegisterURLEcho:
return(RegisterURLEcho(hszItem, hData));
case m_UnRegisterURLEcho:
return(UnRegisterURLEcho(hszItem, hData));
case m_RegisterAnimationEcho:
return(RegisterAnimationEcho(hszItem, hData));
case m_UnRegisterAnimationEcho:
return(UnRegisterAnimationEcho(hszItem, hData));
case m_WindowChange:
return(WindowChange(hszItem, hData));
case m_CancelProgress:
return(CancelProgress(hszItem, hData));
}
// Default, should never reach.
return((HDDEDATA)DDE_FNOTPROCESSED);
}
// Purpose: Bring Netscape to the top of all other applications,
// and show the windows specified. This will restore
// minimized Netscape icons.
// Arguments: hszItem A string representing our real parameters.
// Returns: HDDEDATA Returns the ID of the window that was
// activated and has focus.
// NULL on failure.
// Comments: Parameters within hszItem are
// WindowID,Flags
// WindowID is the handle of the window to restore, or bring
// to the top. -1 means don't care, I suppose.
// Flags is currently reserved for later use, so just
// ignore it.
// Revision History:
// 12-31-94 created GAB
HDDEDATA CDDEWrapper::Activate(HSZ& hszItem)
{
DWORD ReturnID = 0L;
// Obtain our arguments.
DWORD WindowID;
DWORD Flags;
ScanArgs(hszItem, "DW,DW", &WindowID, &Flags);
// If we have a specified WindowID, attempt to activate it.
if(WindowID != 0xFFFFFFFF && WindowID != 0x0) {
// See if it's a valid Window ID
CFrameWnd *pWnd = FEU_FindFrameByID(WindowID, MWContextBrowser);
if(pWnd != NULL) {
if(pWnd->IsIconic()) {
pWnd->ShowWindow(SW_RESTORE);
}
::SetWindowPos(pWnd->GetSafeHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
#ifdef XP_WIN32
pWnd->SetForegroundWindow();
#endif
// Success, set the return value.
ReturnID = WindowID;
}
}
else if(WindowID != 0x0) {
// If we have no windows, then it's time to create a new one.
// This is a valid possibility, since we could be doing some
// type of background work through OLE.
if(XP_ContextCount(MWContextBrowser, TRUE) == 0) {
CFE_CreateNewDocWindow(NULL, NULL);
}
// We're just supposed to bring ourselves to the front.
// Return the WindowID of the window up front.
// Since if there wasn't an active window, then we created one,
// the value returned by the below should never be NULL.
CFrameWnd *pWnd = FEU_GetLastActiveFrame(MWContextBrowser);
if(pWnd != NULL) {
if(pWnd->IsIconic()) {
pWnd->ShowWindow(SW_RESTORE);
}
::SetWindowPos(pWnd->GetSafeHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
#ifdef XP_WIN32
pWnd->SetForegroundWindow();
#endif
// Success, set the return value.
CFrameGlue *pGlue = CFrameGlue::GetFrameGlue(pWnd);
if(pGlue != NULL) {
if(pGlue->GetActiveContext() != NULL) {
ReturnID = pGlue->GetActiveContext()->GetContextID();
}
else if(pGlue->GetMainContext() != NULL) {
ReturnID = pGlue->GetMainContext()->GetContextID();
}
}
}
}
if(ReturnID) {
// Activate it for real.
CAbstractCX *pCX = CAbstractCX::FindContextByID(ReturnID);
if(pCX && pCX->IsFrameContext() && pCX->GetContext()->type == MWContextBrowser) {
CWinCX *pWinCX = (CWinCX *)pCX;
if(pWinCX->GetFrame() && pWinCX->GetFrame()->GetFrameWnd()) {
pWinCX->
GetFrame()->
GetFrameWnd()->
SetActiveView(pWinCX->GetView(), TRUE);
}
}
}
// HDDEDATA hData = DdeCreateDataHandle(m_dwidInst, &ReturnID, sizeof(DWORD), 0, NULL, 0, 0);
HDDEDATA hData = MakeArgs("DW", &ReturnID);
return(hData);
}
// Purpose: Retrieves a URL from the net, and either dumps it into
// a file, or displays it in a given frame.
// Arguments: hszArgs A string representing our real parameters.
// Returns: HDDEDATA Returns the actual WindowID of the window
// the performed the open, where 0 means
// the operation failed, and 0xFFFFFFFF
// means the data was not of an appropriate
// MIME type to display in a Web browser....
// Comments: Parameters within hszItem are
// URL,[FileSpec],WindowID,Flags,[FormData],[MIMEType],
// [ProgressApp]
// URL is the location to load
// FileSpec is the file to dump the load to
// WindowID is the window to load into, 0 meaning
// a new window, 0xFFFFFFFF means the default
// window.
// Flags are:
// 0x1 Ignore document cache
// 0x2 Ignore image cache
// 0x4 Operate in the background (?)
// FormData allows the POSTing of a form.
// MIMEType specifies the form data mime type.
// ProgressApp can be named, which is a DDE server
// that will handle progress messages....
//
// Revision History:
// 01-02-95 created GAB
HDDEDATA CDDEWrapper::OpenURL(HSZ& hszArgs)
{
DWORD dwReturn = 0L;
// Obtain our arguments.
CString csURL;
CString csFileSpec;
DWORD dwWindowID;
DWORD dwFlags;
CString csFormData;
CString csMimeType;
CString csProgressApp;
ScanArgs(hszArgs, "QCS,QCS,DW,DW,QCS,QCS,CS", &csURL, &csFileSpec,
&dwWindowID, &dwFlags, &csFormData, &csMimeType,
&csProgressApp);
// This is very important.
// If the client specified a server callback service, then we need
// to save this right now.
// It will be used in WWW_Alert, WWW_BeginProgress,
// WWW_SetProgressRange, WWW_MakingProgress, and WWW_EndProgress.
m_csProgressApp = csProgressApp;
// Get the appropriate window.
if(dwWindowID == 0) {
// They want a new window.
if(NULL != CFE_CreateNewDocWindow(NULL, NULL)) {
// Window ID is no longer 0.
dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
}
}
else if(dwWindowID == 0xFFFFFFFF) {
// They want the current frame....
// See if we even have one.
if(XP_ContextCount(MWContextBrowser, TRUE) == 0) {
if(NULL != CFE_CreateNewDocWindow(NULL, NULL)) {
// Window ID is no longer 0.
dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
}
else {
dwWindowID = 0;
}
}
else {
if(FEU_GetLastActiveFrame(MWContextBrowser) != NULL) {
// Should be safe.
dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
}
else {
// No last active frame, but more than one window....
// Just create a new one. Can't pick one up arbitrarily.
if(NULL != CFE_CreateNewDocWindow(NULL, NULL)) {
dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
}
else {
dwWindowID = 0;
}
}
}
}
else {
// They are requesting a specific frame.
// See if we've got it.
if(FEU_FindFrameByID(dwWindowID, MWContextBrowser) == NULL) {
dwWindowID = 0;
}
}
// Get the frame
CAbstractCX *pCX = CAbstractCX::FindContextByID(dwWindowID);
if(!pCX || !pCX->IsFrameContext() || !pCX->GetContext() || pCX->GetContext()->type != MWContextBrowser)
{
dwWindowID = 0;
}
// See if the window exists, a value of 0 means failure at this
// point.
if(dwWindowID == 0) {
// Well, either the window didn't exist, or we couldn't create
// a new window.
return(MakeArgs("DW", &dwWindowID));
}
// So far so good. Our current return value will be the window ID,
// until another failure further along.
dwReturn = dwWindowID;
// Decide whether or not to force a reload.
NET_ReloadMethod Reload = NET_DONT_RELOAD;
if(dwFlags & 0x1 || dwFlags & 0x2) {
Reload = NET_NORMAL_RELOAD;
}
// Create the URL structure to load up the URL.
URL_Struct *pURL = NET_CreateURLStruct(csURL, Reload);
// See if we've got some form to POST.
if(csFormData.IsEmpty() != TRUE) {
// We don't allow anything but a post....
pURL->method = URL_POST_METHOD;
// We need to fill in the post data, memory is freed by netlib.
char *cp_FormData = (char *)XP_ALLOC(csFormData.GetLength() + 1);
strcpy(cp_FormData, csFormData);
pURL->post_data = cp_FormData;
// Set the length of the data, don't include our final NULL
// I suppose.
pURL->post_data_size = csFormData.GetLength();
// We need to manually fill in the Content-type:
// If there's not one specified, we default to
// applications/x-www-form-urlencoded
if(csMimeType.IsEmpty() != TRUE) {
StrAllocCopy(pURL->post_headers, "Content-type: ");
StrAllocCat(pURL->post_headers, csMimeType);
}
else {
StrAllocCopy(pURL->post_headers,
"Content-type: application/x-www-form-urlencoded");
}
StrAllocCat(pURL->post_headers, CRLF);
// Also now need to fill in content-length....
char aBuffer[1024];
sprintf(aBuffer, "Content-length: %d", csFormData.GetLength());
StrAllocCat(pURL->post_headers, aBuffer);
StrAllocCat(pURL->post_headers, CRLF);
}
// Have the URL load. We simply can't block our return value until
// all connections are completed for the window because we
// hose all the messaging.
MWContext *pContext = pCX->GetContext();
// Here we should set up all progress callbacks.
// So whenever we get an Alert, or any progress messages, we'll
// be sending it on down to this callback.
// This must be cleared in GetURL_exit_routine
if(csProgressApp.IsEmpty() == FALSE && pContext != NULL) {
// Set up a progress app for this one.
CNcapiUrlData *pNcapi = new CNcapiUrlData(ABSTRACTCX(pContext), pURL);
pNcapi->SetProgressServer(csProgressApp);
}
if(pContext != NULL) {
if(csFileSpec.IsEmpty()) {
// Load up.
ABSTRACTCX(pContext)->GetUrl(pURL, FO_CACHE_AND_PRESENT);
}
else {
// Load to file.
// Protect against re-entrancy
if(pContext->save_as_name) {
XP_FREE(pContext->save_as_name);
pContext->save_as_name = NULL;
}
pContext->save_as_name = strdup(csFileSpec);
// Load up.
ABSTRACTCX(pContext)->GetUrl(pURL, FO_CACHE_AND_SAVE_AS);
}
}
return(MakeArgs("DW", &dwReturn));
}
// Purpose: Register a DDE viewer
// Arguments: hszItem The arguement string.
// Returns: HDDEDATA A boolean indicating success or failure of
// the registration.
// Comments: Parameters withing hszItem are
// qcsApplication The DDE server which will handle
// the requests.
// qcsMIMEType The mime type that the viewer wants
// to handle.
// dwFlags Flags on how to handle:
// 0x00000001 Platform specific open document command.
// 0x00000002 Use of a QueryViewer DDE command, to ask for a file spec.
// 0x00000004 Use ViewDocFile DDE command.
// 0x00000008 Use ViewDocData, not supported.
// The only registration we allow will be FO_PRESENT
// There is a default if the flags is 0, which is
// ViewDocFile method.
// Revision History:
// 01-06-94 created GAB
HDDEDATA CDDEWrapper::RegisterViewer(HSZ& hszItem)
{
// Scan in our arguments.
CString csApplication;
CString csMimeType;
DWORD dwFlags;
ScanArgs(hszItem, "QCS,QCS,DW", &csApplication, &csMimeType, &dwFlags);
TwoByteBool bRetval = TRUE;
// Extract out if we are going to be using the QueryViewer command.
TwoByteBool bQueryViewer = (dwFlags & 0x2UL) != 0UL ? TRUE : FALSE;
if(bQueryViewer == TRUE) {
dwFlags ^= 0x2;
}
// Screen any flags we don't support
if(dwFlags != 0x1 && dwFlags != 0x4) {
bRetval = FALSE;
return(MakeArgs("BL", &bRetval));
}
// Make sure the application and mime type aren't empty.
if(csApplication.IsEmpty() || csMimeType.IsEmpty()) {
bRetval = FALSE;
return(MakeArgs("BL", &bRetval));
}
// Build a special data object to be handed to each stream.
// Basically this will contain the DDE server to contact once we
// are receiving data, and will contain the flag representing
// how the data should be handled.
// We will also be marking this MimeType as un overrideable, until
// it is unregistered.
CDDEStreamData *pCData = new CDDEStreamData(csApplication, csMimeType,
dwFlags, bQueryViewer);
// Register a special converter for the mime type.
if(FALSE == WPM_RegisterContentTypeConverter(
(char *)(const char *)csMimeType, FO_PRESENT,
(void *)pCData, dde_stream, TRUE)) {
// Couldn't do it, another remote control client is already
// using this mime type.
delete pCData;
bRetval = FALSE;
}
return(MakeArgs("BL", &bRetval));
}
// Purpose: Determine the URL a temp file came from.
// Arguments: hszItem The arguement string.
// Returns: HDDEDATA The URL, or NULL on failure.
// Comments: Parameters withing hszItem are
// qcsFileName The file name to look up.
// Revision History:
// 03-21-95 created GAB
HDDEDATA CDDEWrapper::QueryURLFile(HSZ& hszItem)
{
// Scan in our arguments.
CString csFileName;
ScanArgs(hszItem, "QCS", &csFileName);
csFileName.MakeLower();
CString csRetval;
// Find out if the file name is one we know about.
csRetval = theApp.GetProfileString("Temporary File URL Resolution", csFileName, "");
if(csRetval.IsEmpty()) {
return(NULL);
}
return(MakeArgs("QCS", &csRetval));
}
// Purpose: Unregisters on the fly a DDE content type converter.
// Arguments: hszItem Our arguments, in a string
// Returns: HDDEDATA A boolean indicating the success of the
// operation, which should always be TRUE.
// Comments: Our real arguments inside hszItem are
// qcsApplication The DDE server to unregister
// qcsMimeType The Mime type to unregister
// The only registration we allow will be FO_PRESENT
// Revision History:
// 01-06-95 created GAB
HDDEDATA CDDEWrapper::UnRegisterViewer(HSZ& hszItem)
{
// Retrieve our arguments.
CString csApplication;
CString csMimeType;
ScanArgs(hszItem, "QCS,QCS", &csApplication, &csMimeType);
TwoByteBool bRetval = TRUE;
if(csApplication.IsEmpty() || csMimeType.IsEmpty()) {
bRetval = FALSE;
return(MakeArgs("BL", &bRetval));
}
CDDEStreamData *pCData =
(CDDEStreamData *)WPM_UnRegisterContentTypeConverter(csApplication,
csMimeType, FO_PRESENT);
if(pCData == NULL) {
bRetval = FALSE;
}
else {
delete pCData;
}
return(MakeArgs("BL", &bRetval));
}
// Purpose: Connect to a service using a specific topic
// Arguments: cpService The service name of the DDE server
// hszTopic The topic of the conversation to the server
// Returns: CDDEWrapper * The conversation object if established,
// otherwise NULL.
// Comments: Generic connection establishment.
// Revision History:
// 01-05-95 created GAB
CDDEWrapper *CDDEWrapper::ClientConnect(const char *cpService,
HSZ& hszTopic)
{
CDDEWrapper *pConv = NULL;
// Make the service name into an HSZ.
HSZ hszService = DdeCreateStringHandle(m_dwidInst,
(char *) cpService,
CP_WINANSI);
if(hszService == NULL) {
return(NULL);
}
// Establish the connection.
HCONV hConv = DdeConnect(m_dwidInst, hszService, hszTopic, NULL);
if(hConv != NULL) {
// We have a connection, all that's left to do is to create
// a CDDEWrapper, we'll be creating it with the wrong
// service name of course, but client connections no
// longer really care about the service connection number,
// all they need is the conversation handle.
pConv = new CDDEWrapper(m_hsz[m_ServiceName], hszTopic, hConv);
}
// Free off our created hsz.
DdeFreeStringHandle(m_dwidInst, hszService);
// Our return value, sir.
return(pConv);
}
// Purpose: Send the service app a begin progress verb.
// Arguments: pNcapi The url data causing this to occur.
// pService The service name to connect to.
// dwWindowID The windowID which has progressed.
// pMessage The message to show in the server.
// Returns: DWORD The transaction ID that the server sends us
// to use in all other progress verbs.
// Comments: Netscape is a DDE client in this function.
// Revision History:
// 01-05-95 created GAB
// 10-17-95 modified to use CNcapiUrlData
DWORD CDDEWrapper::BeginProgress(CNcapiUrlData *pNcapi, const char *pService,
DWORD dwWindowID, const char *pMessage)
{
DWORD dwTransactionID;
// Get the conversation going.
CDDEWrapper *pConv = ClientConnect(pService, m_hsz[m_BeginProgress]);
// If we didn't connect, don't let the document try this again
// for this progress.
if(pConv == NULL) {
pNcapi->ClearProgressServer();
return(0L);
}
// Save our conversation, in case the server decides to disconnect
// behind our backs.
HCONV hSaveConv = pConv->m_hConv;
// Create our Item arguemnts.
CString csTemp = pMessage;
HSZ hszItem = MakeItemArgs("DW,QCS", &dwWindowID, &csTemp);
// Do the transaction, expect a transaction ID back.
HDDEDATA ddeTransaction = DdeClientTransaction(NULL, 0L,
hSaveConv, hszItem, CF_TEXT, XTYP_REQUEST, m_Timeout, NULL);
// Cut the cord.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
// Make sure we still have a conversation, if so, delete the object.
pConv = GetConvObj(hSaveConv);
if(pConv != NULL) {
delete pConv;
}
if(ddeTransaction == NULL) {
// Server didn't want to process this.
// Don't try them again.
pNcapi->ClearProgressServer();
dwTransactionID = 0L;
}
else {
// Scan in the progress ID, and get rid of the handle.
// Well, it would seem that they're not following their own
// spec. They send us raw data, get it that way.
//ScanArgs(ddeTransaction, "DW", &dwTransactionID);
if(ddeTransaction != NULL) {
ScanDataArgs(ddeTransaction, "DW", &dwTransactionID);
DdeFreeDataHandle(ddeTransaction);
}
else {
dwTransactionID = 0L;
}
}
// If the transaction ID is 0, then they don't want progress.
if(dwTransactionID == 0) {
pNcapi->ClearProgressServer();
}
return(dwTransactionID);
}
// Purpose: Tell the DDE server our progress range.
// Arguments: pNcapi The url data initiating this request.
// pService The server's service name.
// dwTransactionID The transaction ID of this progress.
// dwMaxRange The max range that we can achieve.
// Returns: void
// Comments: Netscape is the DDE client.
// Revision History:
// 01-05-94 created GAB
// 10-17-95 modified to use CNcapiUrlData
void CDDEWrapper::SetProgressRange(CNcapiUrlData *pNcapi, const char *pService,
DWORD dwTransactionID, DWORD dwMaxRange)
{
// Get the conversation going.
CDDEWrapper *pConv = ClientConnect(pService,
m_hsz[m_SetProgressRange]);
// If we didn't connect, don't let the document try this again
// for this progress.
if(pConv == NULL) {
pNcapi->ClearProgressServer();
return;
}
// Save the conversation, in case the DDE server disconnects behind
// our backs.
HCONV hSaveConv = pConv->m_hConv;
// Create our item arguments.
HSZ hszItem = MakeItemArgs("DW,DW", &dwTransactionID, &dwMaxRange);
// Do the transaction, expect nothing back XTYP_POKE
if(FALSE == DdeClientTransaction(NULL, 0L, hSaveConv, hszItem,
CF_TEXT, XTYP_POKE, m_Timeout, NULL)) {
// For some reason, this didn't fly.
// Don't let the document try this again.
pNcapi->ClearProgressServer();
}
// Cut the cord.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
pConv = GetConvObj(hSaveConv);
if(pConv != NULL) {
delete pConv;
}
}
// Purpose: Tell the DDE server that we have made progress.
// Arguments: pNcapi The document initiating this request.
// pServic The server's service name
// dwTransactionID The transaction ID to send with the
// message, aquired by a begin progress call.
// pMessage A message to send to the server, explaining
// the progress message.
// dwCurrent A number, representing a range, which
// was set by a set progress range call.
// Returns: TwoByteBool TRUE The server would like to discontinue
// the download.
// FALSE Continue downloading.
// Comments: Netscape is a DDE client.
// Revision History:
// 01-05-95 created GAB
// 10-17-95 modified to use CNcapiUrlData
TwoByteBool CDDEWrapper::MakingProgress(CNcapiUrlData *pNcapi, const char *pService,
DWORD dwTransactionID, const char *pMessage, DWORD dwCurrent)
{
// Get the conversation going.
CDDEWrapper *pConv = ClientConnect(pService,
m_hsz[m_MakingProgress]);
// If we didn't connect, don't let the document try this again
// for this progress.
if(pConv == NULL) {
pNcapi->ClearProgressServer();
return(FALSE);
}
// Save the conversation, in case the DDE server disconnects behind
// our backs.
HCONV hSaveConv = pConv->m_hConv;
// Create our item arguments.
CString csMessage = pMessage;
HSZ hszItem = MakeItemArgs("DW,QCS,DW", &dwTransactionID, &csMessage,
&dwCurrent);
// Do the transaction, expect a TwoByteBool back.
HDDEDATA ddeTransaction = DdeClientTransaction(NULL, 0L,
hSaveConv, hszItem, CF_TEXT, XTYP_REQUEST, m_Timeout, NULL);
// Cut the cord.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
// Make sure we still have a conversation, if so, delete the object.
pConv = GetConvObj(hSaveConv);
if(pConv) {
delete pConv;
}
TwoByteBool bResult = FALSE;
if(ddeTransaction == NULL) {
// Server didn't want to process this.
// Don't try them again.
pNcapi->ClearProgressServer();
}
else {
// Scan in the progress ID, and get rid of the handle.
if(ddeTransaction != NULL) {
ScanDataArgs(ddeTransaction, "BL", &bResult);
DdeFreeDataHandle(ddeTransaction);
}
else {
bResult = FALSE;
}
}
return(bResult);
}
// Purpose: Tell the DDE server that the progress is ending.
// Arguments: pNcapi The document initiating the request
// pService The server's service name
// dwTransactionID The transaction ID of these progress
// messages.
// Returns: TwoByteBool A success or failure boolean, we really don't
// care, and will always end.
// BUT WAIT, the spec says this, but in reality, it isn't
// done.
// Comments: Netscape is the DDE client.
// Revision History:
// 01-05-95 created GAB
// 10-17-95 modified to use CNcapiUrlData
void CDDEWrapper::EndProgress(CNcapiUrlData *pNcapi, const char *pService,
DWORD dwTransactionID)
{
// Get the conversation going.
CDDEWrapper *pConv = ClientConnect(pService,
m_hsz[m_EndProgress]);
// If we didn't connect, don't let the document try this again
// for this progress.
if(pConv == NULL) {
pNcapi->ClearProgressServer();
return;
}
// Save the conversation, in case the DDE server disconnects behind
// our backs.
HCONV hSaveConv = pConv->m_hConv;
// Create our item arguments.
HSZ hszItem = MakeItemArgs("DW", &dwTransactionID);
// Do the transaction, expect nothing.
DdeClientTransaction(NULL, 0L,
hSaveConv, hszItem, CF_TEXT, XTYP_POKE, m_Timeout, NULL);
// Cut the cord.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
// Make sure we still have a conversation, if so, delete the object.
pConv = GetConvObj(hSaveConv);
if(pConv) {
delete pConv;
}
}
// Purpose: Send our progress app an error message.
// Arguments: pDoc The document requesting this action
// pService The server's service name
// pMessage The message to send
// Returns: DWORD The button pushed by the remote app, or error (0)
// on failuer.
// Comments: All servers should consider this message as a failure to
// load.
// Revision History:
// 01-05-95 created GAB
// 10-17-95 modified to use CNcapiUrlData
DWORD CDDEWrapper::AlertProgress(CNcapiUrlData *pNcapi, const char *pService,
const char *pMessage)
{
// Get the conversation going.
CDDEWrapper *pConv = ClientConnect(pService,
m_hsz[m_Alert]);
// If we didn't connect, simply return, not everyone will have
// this verb.
if(pConv == NULL) {
return(m_PushedError);
}
// Save the conversation, in case the DDE server disconnects behind
// our backs.
HCONV hSaveConv = pConv->m_hConv;
// Create our item arguments.
CString csMessage = pMessage;
DWORD dwType = m_AlertError; // error box
DWORD dwButtons = m_ButtonOk; // What buttons to show
HSZ hszItem = MakeItemArgs("QCS,DW,DW", &csMessage, &dwType,
&dwButtons);
// Do the transaction
HDDEDATA ddeTransaction = DdeClientTransaction(NULL, 0L,
hSaveConv, hszItem, CF_TEXT, XTYP_REQUEST, m_Timeout, NULL);
// Cut the cord.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
// Make sure we still have a conversation, if so, delete the object.
pConv = GetConvObj(hSaveConv);
if(pConv) {
delete pConv;
}
DWORD dwResult = 0L;
if(ddeTransaction != NULL) {
// Scan in the return value, and get rid of the handle.
ScanDataArgs(ddeTransaction, "DW", &dwResult);
DdeFreeDataHandle(ddeTransaction);
}
return(dwResult);
}
// Purpose: Send our progress app a confirmation message.
// Arguments: pNcapi The document requesting this action
// pService The server's service name
// pMessage The message to send
// Returns: DWORD The button pushed by the remote app, or error (0)
// on failuer.
// Comments:
// Revision History:
// 10-17-95 created
DWORD CDDEWrapper::ConfirmProgress(CNcapiUrlData *pNcapi, const char *pService,
const char *pMessage)
{
// Get the conversation going.
CDDEWrapper *pConv = ClientConnect(pService,
m_hsz[m_Alert]);
// If we didn't connect, simply return, not everyone will have
// this verb.
if(pConv == NULL) {
return(m_PushedError);
}
// Save the conversation, in case the DDE server disconnects behind
// our backs.
HCONV hSaveConv = pConv->m_hConv;
// Create our item arguments.
CString csMessage = pMessage;
DWORD dwType = m_AlertQuestion; // error box
DWORD dwButtons = m_ButtonYesNo; // What buttons to show
HSZ hszItem = MakeItemArgs("QCS,DW,DW", &csMessage, &dwType,
&dwButtons);
// Do the transaction
HDDEDATA ddeTransaction = DdeClientTransaction(NULL, 0L,
hSaveConv, hszItem, CF_TEXT, XTYP_REQUEST, m_Timeout, NULL);
// Cut the cord.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
// Make sure we still have a conversation, if so, delete the object.
pConv = GetConvObj(hSaveConv);
if(pConv) {
delete pConv;
}
DWORD dwResult = 0L;
if(ddeTransaction != NULL) {
// Scan in the return value, and get rid of the handle.
ScanDataArgs(ddeTransaction, "DW", &dwResult);
DdeFreeDataHandle(ddeTransaction);
}
return(dwResult);
}
// Purpose: Ask a DDE server what file we should save a file under,
// one that we just downloaded.
// Arguments: pDData Our download data, will hold everything needed
// to establish the conversation.
// Returns: void
// Comments: Another topic should be called after this one in order
// to tell the registered viewer that it's document is now ready.
// Revision History:
// 01-06-95 created GAB
void CDDEWrapper::QueryViewer(CDDEDownloadData *pDData)
{
// Get our parameters to establish the conversation.
CString csService = pDData->m_pCData->m_csServerName;
// Get the conversation going.
CDDEWrapper *pConv = ClientConnect(csService, m_hsz[m_QueryViewer]);
if(pConv == NULL) {
// There's not much else we can do here, simply return.
return;
}
// Save the conversation, in case the DDE server disconnects behind
// our backs.
HCONV hSaveConv = pConv->m_hConv;
// Create our argument list.
CString csURL;
CString csMimeType;
csMimeType = pDData->m_pCData->m_csMimeType;
csURL = pDData->m_csURL;
HSZ hszItem = MakeItemArgs("QCS,QCS", &csURL, &csMimeType);
// Do the transaction, expect a FileSpec back.
HDDEDATA ddeTransaction = DdeClientTransaction(NULL, 0L,
hSaveConv, hszItem, CF_TEXT, XTYP_REQUEST, m_Timeout, NULL);
// Get rid of our string handle, don't need it anymore; same with the
// connection.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
// Make sure we still have a conversation, if so, delete the object.
pConv = GetConvObj(hSaveConv);
if(pConv) {
delete pConv;
}
if(ddeTransaction == NULL) {
// There's not much else we can do here, simply return.
return;
}
// Get the file name out of the data returned by the DDE server.
CString csFileName;
ScanDataArgs(ddeTransaction, "QCS", &csFileName);
DdeFreeDataHandle(ddeTransaction);
// Move it over to where the server wants it.
TRY {
CFile::Rename(pDData->m_csFileName, csFileName);
}
CATCH(CFileException, e) {
// Couldn't rename for some reason.
return;
}
END_CATCH
// Tell the download data, that it won't be necessary to delete this file.
// The viewer will take care of it.
pDData->m_bDelete = FALSE;
// Change the name.
pDData->m_csFileName = csFileName;
// Done.
return;
}
// Purpose: Tell a registered viewer that a document of it's type is loaded
// and in a certain file.
// Arguments: pDData The download instance specific data, contains
// the file name.
// Returns: void
// Comments: Function will unregister any viewers that don't respond in
// a fashion that we deem fit.
// Revision History:
// 01-08-95 created GAB
void CDDEWrapper::ViewDocFile(CDDEDownloadData *pDData)
{
// Get our parameters to establish the conversation.
CString csService = pDData->m_pCData->m_csServerName;
// Get the conversation going.
CDDEWrapper *pConv = ClientConnect(csService, m_hsz[m_ViewDocFile]);
if(pConv == NULL) {
// Well, Doh!, the server isn't responding.
// Disable it from further being our registered app.
CString csMimeType = pDData->m_pCData->m_csMimeType;
WPM_UnRegisterContentTypeConverter(csService, csMimeType,
FO_PRESENT);
delete pDData->m_pCData;
// There's not much else we can do here, simply return.
return;
}
// Save the conversation, in case the DDE server disconnects behind
// our backs.
HCONV hSaveConv = pConv->m_hConv;
// Create our argument list.
CString csFileSpec = pDData->m_csFileName;
CString csURL = pDData->m_csURL;
CString csMimeType = pDData->m_pCData->m_csMimeType;
DWORD dwWindowID = pDData->m_dwFrameID;
HSZ hszItem = MakeItemArgs("QCS,QCS,QCS,DW", &csFileSpec, &csURL,
&csMimeType, &dwWindowID);
// Do the transaction, expect nothing.
DdeClientTransaction(NULL, 0L, hSaveConv, hszItem, CF_TEXT,
XTYP_POKE, m_Timeout, NULL);
// Cut the cord.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
// Make sure we still have a conversation, if so, delete the object.
pConv = GetConvObj(hSaveConv);
if(pConv) {
delete pConv;
}
// Done here.
return;
}
// Purpose: Use a shell open to open the file name in our download data.
// Arguments: pDData Data specific to this download.
// Returns: void
// Comments: Support of another RegisterViewer command.
// Revision History:
// 01-14-95 created GAB
void CDDEWrapper::OpenDocument(CDDEDownloadData *pDData)
{
// Well, we don't really do any DDE per se here, but this is where the
// funciton logically belongs.
// Attempt to have windows open the file specified.
// This is a fire and forget mechanism, though we will unregister the
// DDE content type converter on an error.
HINSTANCE hReturns = ::ShellExecute(::GetDesktopWindow(), NULL, pDData->m_csFileName, NULL, NULL, SW_SHOW);
if(hReturns <= (HINSTANCE)32) {
// There seemed to have been an error.
// Unregister the content type converter now.
CString csService = pDData->m_pCData->m_csServerName;
CString csMimeType = pDData->m_pCData->m_csMimeType;
WPM_UnRegisterContentTypeConverter(csService, csMimeType,
FO_PRESENT);
delete pDData->m_pCData;
}
}
// Purpose: Exit the Netscape application.
// Arguments: hszItem Our arguments.
// hData Any data in particular that the server is sending us.
// Returns: HDDEDATA Wether or not we completed this operation.
// Comments: Netscape will not always exit on this command, since we may be automated.
// Revision History:
// 01-13-95 created GAB
// 10-17-95 modified to send the last active frame, if around, the
// ID_APP_EXIT WM_COMMAND message.
HDDEDATA CDDEWrapper::Exit(HSZ& hszItem, HDDEDATA& hData)
{
// See if any frame windows are around.
CFrameWnd *pWnd = FEU_GetLastActiveFrame();
if(pWnd != NULL) {
// Send it the app exit message.
pWnd->PostMessage(WM_COMMAND, ID_APP_SUPER_EXIT);
return((HDDEDATA)DDE_FACK);
}
return((HDDEDATA)DDE_FNOTPROCESSED);
}
// Purpose: Get some misc information about a Netscape window.
// Arguments: hstItem Our arugments, see below.
// Returns: HDDEDATA Contains
// qcsUrl The current URL loaded in the window.
// qcsTitle The current title of the window.
// Comments: This is useless, but implementable.
// Revision History:
// 01-13-95 created GAB
HDDEDATA CDDEWrapper::GetWindowInfo(HSZ& hszItem)
{
// Retrieve our arguments.
DWORD dwFrameID;
ScanArgs(hszItem, "DW", &dwFrameID);
// We'll let dwFrameID be 0xffffffff for the default window.
if(dwFrameID == 0xFFFFFFFF) {
dwFrameID = FEU_GetLastActiveFrameID(MWContextBrowser);
if(dwFrameID == 0) {
// This is going to fail, no active window.
return(NULL);
}
}
// Okay, all we have left to do is obtain the current title of the window,
// and the current loaded URL.
CAbstractCX *pCX = CAbstractCX::FindContextByID(dwFrameID);
if(pCX && pCX->GetContext() && pCX->GetContext()->type != MWContextBrowser) {
pCX = NULL;
}
if(pCX == NULL) {
return(NULL);
}
// Get the stuff.
CString csTitle;
CString csUrl;
CString csName;
if(pCX->GetContext()) {
if(pCX->GetContext()->title) {
csTitle = pCX->GetContext()->title;
}
if(pCX->GetContext()->hist.cur_doc_ptr) {
if(pCX->GetContext()->hist.cur_doc_ptr->address) {
csUrl = pCX->GetContext()->hist.cur_doc_ptr->address;
}
}
if(pCX->GetContext()->name) {
csName = pCX->GetContext()->name;
}
}
// Create our return arguments.
return(MakeArgs("QCS,QCS,QCS", &csUrl, &csTitle, &csName));
}
// Purpose: List all the open Netscape windows.
// Arguments: hszItem ignored.
// Returns: HDDEDATA An array of DWORDs corresponding to the windows.
// Comments: We will manually create the return data in this function,
// as it follows no previously coded standard.
// We will not return the ID of the minimized window.
// Revision History:
// 01-13-94 created GAB
HDDEDATA CDDEWrapper::ListWindows(HSZ& hszItem)
{
// Count our windows.
DWORD dwFrames = XP_ContextCount(MWContextBrowser, FALSE);
// No frames, don't do this.
if(dwFrames == 0) {
return(NULL);
}
DWORD *pData = new DWORD[dwFrames + 1];
DWORD dwCounter = 0;
// Loop through each context, taking only browser style contexts.
MWContext *pTraverseContext = NULL;
CAbstractCX *pTraverseCX = NULL;
XP_List *pTraverse = XP_GetGlobalContextList();
while (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) {
// Looks like this is the type of context we'll list.
*(pData + dwCounter) = pWinCX->GetContextID();
dwCounter++;
}
}
}
}
// Null terminate the list.
*(pData + dwCounter) = (DWORD)0;
// allocate some data to return to the caller.
HDDEDATA hData = DdeCreateDataHandle(m_dwidInst, (unsigned char *)pData, (dwCounter + 1) * sizeof(DWORD), 0, m_hsz[m_ServiceName],
CF_TEXT, 0);
delete [] pData;
return(hData);
}
// Purpose: Parse a main, and relative URL, returning the fully qualified URL.
// Arguments: hszItem The arguments. See below.
// Returns: HDDEDATA A null terminated string representing the fully qualified URL.
// Comments: Nothing special here, folks.
// Revision History:
// 01-13-95 created GAB
HDDEDATA CDDEWrapper::ParseAnchor(HSZ& hszItem)
{
// Get our arguments.
CString csMainURL;
CString csRelativeURL;
ScanArgs(hszItem, "QCS,QCS", &csMainURL, &csRelativeURL);
// create the URL.
char *cpURL = NET_MakeAbsoluteURL((char *)(const char *)csMainURL, (char *)(const char *)csRelativeURL);
CString csURL;
if(cpURL != NULL) {
csURL = cpURL;
XP_FREE(cpURL);
}
// Create our return value.
return(MakeArgs("QCS", &csURL));
}
// Purpose: Report the current DDE API version back to the caller.
// Arguments: hszItem none and ignored.
// Returns: HDDEDATA which actually contains the version.
// Comments: Version control information for the API.
// Revision History:
// 01-17-95 created GAB
HDDEDATA CDDEWrapper::Version(HSZ& hszItem)
{
return(MakeArgs("DW", &dwDDEVersion));
}
// Purpose: Register a particular DDE server to handle URLs of a particular type.
// Arguments: hszItem Arguments, see below.
// Returns: HDDEDATA TRUE registered
// FALSE unable to register, another applciation is handling it.
// Comments:
// Revision History:
// 01-18-95 created GAB
HDDEDATA CDDEWrapper::RegisterProtocol(HSZ& hszItem)
{
// Get our arguments.
CString csServer;
CString csProtocol;
ScanArgs(hszItem, "QCS,QCS", &csServer, &csProtocol);
// If either is empty, we'll just fail.
if(csServer.IsEmpty() || csProtocol.IsEmpty()) {
return(NULL);
}
// Need to see if something is already registered to handle this protocol.
TwoByteBool bRetval = CDDEProtocolItem::DDERegister(csProtocol, csServer);
return(MakeArgs("BL", &bRetval));
}
// Purpose: Register a particular DDE server to handle URLs of a particular type.
// Arguments: hszItem Arguments, see below.
// Returns: HDDEDATA TRUE registered
// FALSE unable to register, another applciation is handling it.
// Comments:
// Revision History:
// 01-18-95 created GAB
HDDEDATA CDDEWrapper::UnRegisterProtocol(HSZ& hszItem)
{
// Get our arguments.
CString csServer;
CString csProtocol;
ScanArgs(hszItem, "QCS,QCS", &csServer, &csProtocol);
// If either is empty, we'll just fail.
if(csServer.IsEmpty() || csProtocol.IsEmpty()) {
return(NULL);
}
TwoByteBool bRetval = CDDEProtocolItem::DDEUnRegister(csProtocol, csServer);
return(MakeArgs("BL", &bRetval));
}
// Purpose: Have an external protocol handler open a URL.
// Arguments: csServiceName The name of the external service application.
// pURL The URL to perform the load on; contains possible form data also.
// pContext The context to load from (windowID).
// iFormatOut Wether or not to save the URL.
// Returns: TwoByteBool TRUE External application handling the request.
// FALSE External application failed to handle.
// Comments: Will automatically deregister the external applciation if failure to connect.
// Revision History:
// 01-18-94 created GAB
TwoByteBool CDDEWrapper::OpenURL(CString csProtocol, CString csServiceName, URL_Struct *pURL, MWContext *pContext, FO_Present_Types iFormatOut)
{
// Get the conversation going.
CDDEWrapper *pConv = ClientConnect(csServiceName, m_hsz[m_OpenURL]);
if(pConv == NULL) {
// Well, Doh!, the server isn't responding.
// Disable it from further being our registered app.
CDDEProtocolItem::DDEUnRegister(csProtocol, csServiceName);
// There's not much else we can do here, simply return.
return(FALSE);
}
// Save the conversation, in case the DDE server disconnects behind
// our backs.
HCONV hSaveConv = pConv->m_hConv;
// See if we need to save the file.
// The filename was saved in the context some time ago.
CString csSaveAs;
if((iFormatOut & FO_SAVE_AS) == FO_SAVE_AS) {
if(pContext->save_as_name != NULL) {
csSaveAs = pContext->save_as_name;
// Steal it from the old context.
free(pContext->save_as_name);
pContext->save_as_name = NULL;
}
else {
// There's no name to save it under, so that must mean that the user either
// cancelled a save, or we're simply broken.
// Be sure to get rid of the conversation too.
// Make sure we still have a conversation, if so, delete the object.
DdeDisconnect(hSaveConv);
pConv = GetConvObj(hSaveConv);
if(pConv) {
delete pConv;
}
return(FALSE);
}
}
// Screen types we don't want to handle.
else if((iFormatOut & FO_PRESENT) != FO_PRESENT) {
// Be sure to get rid of the conversation too.
// Make sure we still have a conversation, if so, delete the object.
DdeDisconnect(hSaveConv);
pConv = GetConvObj(hSaveConv);
if(pConv) {
delete pConv;
}
return(FALSE);
}
// Create our argument list.
CString csURL = pURL->address;
DWORD dwWindowID = FE_GetContextID(pContext);
DWORD dwFlags = 0UL;
CString csFormData;
if(pURL->post_data != NULL) {
csFormData = pURL->post_data;
}
CString csPostMimeType;
if(pURL->post_headers != NULL) {
// Need to extract the content type.
char *pFind = strcasestr(pURL->post_headers, "Content-type:");
if(pFind != NULL) {
while(*pFind != ':') {
pFind++;
}
pFind++;
while(*pFind != '\0' && isspace(*pFind)) {
pFind++;
}
csPostMimeType = pFind;
csPostMimeType = csPostMimeType.SpanExcluding("\r\n");
}
}
CString csProgressApp; // leave empty for now.
HSZ hszItem = MakeItemArgs("QCS,QCS,DW,DW,QCS,QCS,CS", &csURL, &csSaveAs, &dwWindowID, &dwFlags, &csFormData,
&csPostMimeType, &csProgressApp);
// Do the transaction, expect return value.
HDDEDATA hData = DdeClientTransaction(NULL, 0L, hSaveConv, hszItem, CF_TEXT,
XTYP_REQUEST, m_Timeout, NULL);
// Cut the cord.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
// Make sure we still have a conversation, if so, delete the object.
pConv = GetConvObj(hSaveConv);
if(pConv) {
delete pConv;
}
// See if we've gotten a return value. Failure to give us a value will cause use to unregister the app.
if(hData == NULL) {
CDDEProtocolItem::DDEUnRegister(csProtocol, csServiceName);
return(FALSE);
}
// We've got a return value. Determine what it is.
DWORD dwRetval;
ScanDataArgs(hData, "DW", &dwRetval);
DdeFreeDataHandle(hData);
// Check for failure.
if(dwRetval == 0 || dwRetval == 0xFFFFFFFFUL) {
return(FALSE);
}
// Done.
// Be sure to let the frame know it's not saving any file, regardless, since we
// may have handled it.
return(TRUE);
}
// Purpose: Register a DDE server for URL echo.
// Arguments: hszItem our arguments.
// hData Disregard, not used.
// Returns: HDDEDATA Always DDE_FACK, acknowleding that we processed this.
// Comments:
// Revision History:
// 01-18-95 created GAB.
HDDEDATA CDDEWrapper::RegisterURLEcho(HSZ& hszItem, HDDEDATA& hData)
{
// Scan in our arguments.
CString csServiceName;
ScanArgs(hszItem, "QCS", &csServiceName);
// Have the URL echo class handle it.
CDDEEchoItem::DDERegister(csServiceName);
return((HDDEDATA)DDE_FACK);
}
// Purpose: Unregister a DDE server from URL echo.
// Arguments: hszItem our arugumetns.
// hData Disregard.
// Returns: HDDEDATA always DDE_FACK, unless invalid
// Comments:
// Revision History:
// 01-18-95 created GAB
HDDEDATA CDDEWrapper::UnRegisterURLEcho(HSZ& hszItem, HDDEDATA& hData)
{
// Scan in our arguments.
CString csServiceName;
ScanArgs(hszItem, "QCS", &csServiceName);
// Have the URL echo class handle it.
if(CDDEEchoItem::DDEUnRegister(csServiceName) == TRUE) {
return((HDDEDATA)DDE_FACK);
}
return((HDDEDATA)DDE_FNOTPROCESSED);
}
// Purpose: Echo a URL event to a server.
// Arguments: pItem The Echo object causing this (so we can get our service name out of it, and anything else.
// csURL The url loaded.
// csMimeType The mime type of the url.
// dwWindowID The window performing the load.
// csReferrer The referrer URL.
// Returns: void
// Comments:
// Revision History:
// 01-18-95 created GAB
void CDDEWrapper::URLEcho(CDDEEchoItem *pItem, CString& csURL, CString& csMimeType, DWORD dwWindowID, CString& csReferrer)
{
// Get the server name.
CString csServiceName = pItem->GetServiceName();
// Establish the connection to homeworld.
CDDEWrapper *pConv = ClientConnect(csServiceName, m_hsz[m_URLEcho]);
if(pConv == NULL) {
// Well, Doh!, the server isn't responding.
// Disable it from further being our registered app.
CDDEEchoItem::DDEUnRegister(csServiceName);
// There's not much else we can do here, simply return.
return;
}
// Save the conversation, in case the DDE server disconnects behind
// our backs.
HCONV hSaveConv = pConv->m_hConv;
// Create our argument list.
HSZ hszItem = MakeItemArgs("QCS,QCS,DW,QCS", &csURL, &csMimeType, &dwWindowID, &csReferrer);
// Do the transaction, expect nothing.
DdeClientTransaction(NULL, 0L, hSaveConv, hszItem, CF_TEXT,
XTYP_POKE, m_Timeout, NULL);
// Cut the cord.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
// Make sure we still have a conversation, if so, delete the object.
pConv = GetConvObj(hSaveConv);
if(pConv) {
delete pConv;
}
}
// Functions for handling animation echoing (Added by Dave Hyatt 4/98)
HDDEDATA CDDEWrapper::RegisterAnimationEcho(HSZ& hszItem, HDDEDATA& hData)
{
// Scan in our arguments.
CString csServiceName;
ScanArgs(hszItem, "QCS", &csServiceName);
// Have the URL echo class handle it.
CDDEAnimationEcho::DDERegister(csServiceName);
return((HDDEDATA)DDE_FACK);
}
HDDEDATA CDDEWrapper::UnRegisterAnimationEcho(HSZ& hszItem, HDDEDATA& hData)
{
// Scan in our arguments.
CString csServiceName;
ScanArgs(hszItem, "QCS", &csServiceName);
// Have the URL echo class handle it.
if(CDDEAnimationEcho::DDEUnRegister(csServiceName) == TRUE) {
return((HDDEDATA)DDE_FACK);
}
return((HDDEDATA)DDE_FNOTPROCESSED);
}
void CDDEWrapper::AnimationEcho(CDDEAnimationEcho *pItem, DWORD dwWindowID, DWORD dwState)
{
// Get the server name.
CString csServiceName = pItem->GetServiceName();
// Establish the connection to homeworld.
CDDEWrapper *pConv = ClientConnect(csServiceName, m_hsz[m_AnimationEcho]);
if(pConv == NULL)
{
CDDEAnimationEcho::DDEUnRegister(csServiceName);
return;
}
// Save the conversation, in case the DDE server disconnects behind
// our backs.
HCONV hSaveConv = pConv->m_hConv;
// Create our argument list.
HSZ hszItem = MakeItemArgs("DW,DW", &dwWindowID, &dwState);
// Do the transaction, expect nothing.
DdeClientTransaction(NULL, 0L, hSaveConv, hszItem, CF_TEXT,
XTYP_POKE, m_Timeout, NULL);
// Cut the cord.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
// Make sure we still have a conversation, if so, delete the object.
pConv = GetConvObj(hSaveConv);
if(pConv)
{
delete pConv;
}
}
// Purpose: Register a DDE server to monitor a certain window's close.
// Arguments: hszItem the argumetns, the server and the window
// Returns: HDDEDATA TRUE or FALSE, FALSE there was no window.
// Comments:
// Revision History:
// 01-19-95 created GAB
//
// Purpose: Register a particular DDE server to handle URLs of a particular type.
// Arguments: hszItem Arguments, see below.
// Returns: HDDEDATA dwWindowID
// Comments:
// Revision History:
// 01-18-95 created GAB
HDDEDATA CDDEWrapper::RegisterWindowChange(HSZ& hszItem)
{
// Get our arguments.
CString csServer;
DWORD dwWindowID;
ScanArgs(hszItem, "QCS,DW", &csServer, &dwWindowID);
// If server is empty, we'll just fail.
if(csServer.IsEmpty()) {
return(NULL);
}
// Sign up to watch the window, this possibly fails.
if(FALSE == CDDEWindowChangeItem::DDERegister(csServer, dwWindowID)) {
dwWindowID = 0;
}
return(MakeArgs("DW", &dwWindowID));
}
// Purpose: Unregister a window to be monitored.
// Arguments: hszItem The arguments, the server ,and the windowID.
// Returns: HDDEDATA TRUE or FALSE, FALSE there was no prior registration.
// Comments:
// Revision History:
// 01-19-95 created GAB
HDDEDATA CDDEWrapper::UnRegisterWindowChange(HSZ& hszItem)
{
// Get our arguments.
CString csServer;
DWORD dwWindowID;
ScanArgs(hszItem, "QCS,DW", &csServer, &dwWindowID);
// If server is empty, we'll just fail.
if(csServer.IsEmpty()) {
return(NULL);
}
// Sign up to watch the window, this possibly fails.
TwoByteBool bRetval = CDDEWindowChangeItem::DDEUnRegister(csServer, dwWindowID);
return(MakeArgs("BL", &bRetval));
}
// Purpose: Send a message to the registere monitoring server that the window is chaning.
// Arguments: pItem The registry of window close monitors.
// iChange The type of change ocurring.
// bExiting Wether or not we believe Netscape is actually exiting.
// dwX The X position of the window.
// dwY The Y position of the window.
// dwCX The width of the window.
// dwCY The height of the window.
// Returns: void
// Comments:
// Revision History:
// 01-19-95 created GAB
// 02-01-95 modified extensively to handle multiple different types of window actions.
void CDDEWrapper::WindowChange(CDDEWindowChangeItem *pItem, int iChange, TwoByteBool bExiting, DWORD dwX, DWORD dwY, DWORD dwCX, DWORD dwCY)
{
// Get the server name.
CString csServiceName = pItem->GetServiceName();
// Establish the connection to homeworld.
CDDEWrapper *pConv = ClientConnect(csServiceName, m_hsz[m_WindowChange]);
if(pConv == NULL) {
// Well, Doh!, the server isn't responding.
// There's not much else we can do here, simply return.
// Unregistration happens elsewhere.
return;
}
// Save the conversation, in case the DDE server disconnects behind
// our backs.
HCONV hSaveConv = pConv->m_hConv;
// Construct the flags for the call, and our calling format.
DWORD dwFlags = 0;
const char *pFormat;
switch(iChange) {
case CDDEWindowChangeItem::m_Close: {
dwFlags |= 0x00000010UL;
if(bExiting == TRUE) {
dwFlags |= 0x00010000UL;
}
pFormat = "DW,DW";
break;
}
case CDDEWindowChangeItem::m_Size: {
dwFlags |= 0x00000001UL;
pFormat = "DW,DW,DW,DW,DW,DW";
break;
}
case CDDEWindowChangeItem::m_Maximize: {
dwFlags |= 0x00000002UL;
pFormat = "DW,DW";
break;
}
case CDDEWindowChangeItem::m_Minimize: {
dwFlags |= 0x00000008UL;
pFormat = "DW,DW";
break;
}
case CDDEWindowChangeItem::m_Normalize: {
dwFlags |= 0x00000004UL;
pFormat = "DW,DW";
break;
}
default: {
// Not handled, this is bad.
pFormat = "DW,DW";
ASSERT(0);
break;
}
}
// Create our argument list.
DWORD dwWindowID = pItem->GetWindowID();
HSZ hszItem = MakeItemArgs(pFormat, &dwWindowID, &dwFlags, &dwX, &dwY, &dwCX, &dwCY);
// Do the transaction, expect nothing.
DdeClientTransaction(NULL, 0L, hSaveConv, hszItem, CF_TEXT,
XTYP_POKE, m_Timeout, NULL);
// Cut the cord.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
// Make sure we still have a conversation, if so, delete the object.
pConv = GetConvObj(hSaveConv);
if(pConv) {
delete pConv;
}
}
// Purpose: Retrieves a file from the local file system and displays it in a given frame.
// Arguments: hszArgs A string representing our real parameters.
// Returns: HDDEDATA Returns the actual WindowID of the window
// the performed the open, where 0 means
// the operation failed, and 0xFFFFFFFF
// means the data was not of an appropriate
// MIME type to display in a Web browser....
// Comments: Parameters within hszItem are
// qcsFileName the file on the local file system that Netscape should attempt to load.
// qcsMimeType is the mime type of the file.
// dwWindowID is the Netscape window in which to perform the load.
// A value of 0x0 requests Netscape to load into a new window.
// A value of 0xFFFFFFFF requests Netscape to load into the last active window.
// qcsURL is the original URL of the document to reload if necessary. Will only attempt if can't
// open the file for reading.
// Revision History:
// 01-19-95 created GAB
HDDEDATA CDDEWrapper::ShowFile(HSZ& hszArgs)
{
DWORD dwReturn = 0L;
// Obtain our arguments.
CString csFileName;
CString csMimeType;
DWORD dwWindowID;
CString csURL;
ScanArgs(hszArgs, "QCS,QCS,DW,QCS", &csFileName, &csMimeType, &dwWindowID, &csURL);
// Get the appropriate window.
if(dwWindowID == 0) {
// They want a new window.
if(NULL != CFE_CreateNewDocWindow(NULL, NULL)) {
// Window ID is no longer 0.
dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
}
}
else if(dwWindowID == 0xFFFFFFFF) {
// They want the current frame....
// See if we even have one.
if(XP_ContextCount(MWContextBrowser, TRUE) == 0) {
if(NULL != CFE_CreateNewDocWindow(NULL, NULL)) {
dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
}
else {
dwWindowID = 0;
}
}
else {
if(FEU_GetLastActiveFrame(MWContextBrowser) != NULL) {
// Should be safe.
dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
}
else {
dwWindowID = 0;
if(NULL != CFE_CreateNewDocWindow(NULL, NULL)) {
dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
}
}
}
}
else {
// They are requesting a specific frame.
// See if we've got it.
if(FEU_FindFrameByID(dwWindowID, MWContextBrowser) == NULL) {
dwWindowID = 0;
}
}
CAbstractCX *pCX = NULL;
if(dwWindowID) {
pCX = CAbstractCX::FindContextByID(dwWindowID);
if(NULL == pCX ||
pCX->IsDestroyed() ||
pCX->IsFrameContext() == FALSE ||
pCX->GetContext()->type != MWContextBrowser) {
dwWindowID = 0;
pCX = NULL;
}
}
// See if the window exists, a value of 0 means failure at this
// point.
if(dwWindowID == 0) {
// Well, either the window didn't exist, or we couldn't create
// a new window.
return(MakeArgs("DW", &dwWindowID));
}
// So far so good. Our current return value will be the window ID,
// until another failure further along.
dwReturn = dwWindowID;
// Create the URL structure to load up the URL.
// We do this first by seeing if we can access the file, if so go on, and if
// not use the URL that they presented us with.
URL_Struct *pURL = NULL;
if(_access(csFileName, 0x4) == -1) {
// Use the URL
pURL = NET_CreateURLStruct(csURL, NET_DONT_RELOAD);
}
else {
// Use the file name.
CString csURL;
WFE_ConvertFile2Url(csURL, csFileName);
pURL = NET_CreateURLStruct(csURL, NET_DONT_RELOAD);
}
// Manually assign in the mime type of the URL struct.
if(csMimeType.IsEmpty() == FALSE) {
pURL->content_type = strdup(csMimeType);
}
// Have the URL load. We simply can't block our return value until
// all connections are completed for the window because we
// hose all the messaging.
pCX->GetUrl(pURL, FO_CACHE_AND_PRESENT);
return(MakeArgs("DW", &dwReturn));
}
// Purpose: Change our window position/attributes.
// Arguments: hszItem Our arguments.
// hData Data, ignored.
// Returns: HDDEDATA TRUE or FALSE, depending on successful completion.
// Comments: This should probably by XTYP_REQUEST, as they may specify an invalid window ID, but they get the candy they want.
// They could always check for valid IDs themselves.
// Revision History:
// 02-01-95 created GAB
HDDEDATA CDDEWrapper::WindowChange(HSZ& hszItem, HDDEDATA& hData)
{
// Scan in our argumetnts.
DWORD dwWindowID;
DWORD dwFlags;
DWORD dwX;
DWORD dwY;
DWORD dwCX;
DWORD dwCY;
ScanArgs(hszItem, "DW,DW,DW,DW,DW,DW", &dwWindowID, &dwFlags, &dwX, &dwY, &dwCX, &dwCY);
// Figure out if the frame exists.
CAbstractCX *pCX = CAbstractCX::FindContextByID(dwWindowID);
CFrameWnd *pFrame = FEU_FindFrameByID(dwWindowID);
if(pFrame == NULL || dwWindowID == 0 || NULL == pCX || pCX->IsGridCell()) {
return((HDDEDATA)DDE_FNOTPROCESSED);
}
TwoByteBool bDidSomething = FALSE;
// Figure out, via the flags, what in the hell we are doing.
if(dwFlags & 0x00000001UL) {
// We're changing size.
// X and Y are always significant, though the others may not be....
if(dwCX == 0) {
// Determine what this should really be.
RECT rDim;
pFrame->GetWindowRect(&rDim);
dwCX = rDim.right - rDim.left;
}
if(dwCY == 0) {
// Determine what this should really be.
RECT rDim;
pFrame->GetWindowRect(&rDim);
dwCX = rDim.bottom - rDim.top;
}
pFrame->MoveWindow(CASTINT(dwX), CASTINT(dwY), CASTINT(dwCX), CASTINT(dwCY));
bDidSomething = TRUE;
}
if(dwFlags & 0x00000002UL) {
// We're maximizing.
pFrame->ShowWindow(SW_SHOWMAXIMIZED);
bDidSomething = TRUE;
}
if(dwFlags & 0x00000004UL) {
// We're normalizing.
pFrame->ShowWindow(SW_SHOWNORMAL);
bDidSomething = TRUE;
}
if(dwFlags & 0x00000008UL) {
// We're minimizing.
pFrame->ShowWindow(SW_MINIMIZE);
bDidSomething = TRUE;
}
if(dwFlags & 0x00000010UL) {
// We're closing.
pFrame->PostMessage(WM_CLOSE);
bDidSomething = TRUE;
}
if(bDidSomething == TRUE) {
return((HDDEDATA)DDE_FACK);
}
else {
return((HDDEDATA)DDE_FNOTPROCESSED);
}
}
// Purpose: Pure hell.
// Arguments: hszItem The arguments, the transaction ID to stop loading.
// hData is ignored.
// Returns: HDDEDATA TRUE, always work.
// Comments: We need to traverse all windows, hence all frames, and then documents, to find out the Transaction ID.
// Revision History:
// 02-01-95 created GAB
// 10-17-95 Modified to search for the transaction ID in a different manner.
HDDEDATA CDDEWrapper::CancelProgress(HSZ& hszItem, HDDEDATA& hData)
{
// Get the argument.
DWORD dwTransactionID;
ScanArgs(hszItem, "DW", &dwTransactionID);
// Go through all contexts, searching for the one with the specific
// transaction ID.
MWContext *pTraverseContext = NULL;
CAbstractCX *pTraverseCX = NULL;
XP_List *pTraverse = XP_GetGlobalContextList();
while (pTraverseContext = (MWContext *)XP_ListNextObject(pTraverse)) {
if(pTraverseContext != NULL && ABSTRACTCX(pTraverseContext) != NULL) {
pTraverseCX = ABSTRACTCX(pTraverseContext);
if(pTraverseCX->m_pNcapiUrlData != NULL) {
if(pTraverseCX->m_pNcapiUrlData->GetTransactionID()) {
if(pTraverseCX->m_pNcapiUrlData->GetTransactionID() == dwTransactionID) {
// Found it, cancel it.
pTraverseCX->Interrupt();
return((HDDEDATA)DDE_FACK);
}
}
}
}
}
// Not found, not valid.
return((HDDEDATA)DDE_FNOTPROCESSED);
}
HDDEDATA CDDEWrapper::ListFrameChildren(HSZ& hszItem)
{
HDDEDATA hRetval = NULL;
DWORD dwCXID;
ScanArgs(hszItem, "DW", &dwCXID);
CWinCX *pCX = GetContext(dwCXID);
if(pCX && pCX->IsGridParent()) {
XP_List *pChildren = pCX->GetContext()->grid_children;
DWORD dwCount = XP_ListCount(pChildren);
if(dwCount) {
// Allocate a buffer for the children IDs.
DWORD *pBuf = new DWORD[dwCount + 1];
if(pBuf) {
memset(pBuf, 0, CASTSIZE_T(sizeof(DWORD) * (dwCount + 1)));
// Go through the list figuring out the context ID and
// assigning it in.
void *pTraverse;
DWORD dwIndex = 0;
while(pTraverse = XP_ListNextObject(pChildren)) {
CWinCX *pChildCX = WINCX(((MWContext *)pTraverse));
pBuf[dwIndex] = pChildCX->GetContextID();
dwIndex++;
}
// Convert
hRetval = DdeCreateDataHandle(
m_dwidInst,
(unsigned char *)pBuf,
(dwCount + 1) * sizeof(DWORD),
0,
m_hsz[m_ServiceName],
CF_TEXT, 0);
delete [] pBuf;
pBuf = NULL;
}
}
}
return(hRetval);
}
HDDEDATA CDDEWrapper::GetFrameParent(HSZ& hszItem)
{
DWORD dwCXID;
ScanArgs(hszItem, "DW", &dwCXID);
CWinCX *pCX = GetContext(dwCXID);
if(pCX && pCX->IsGridCell()) {
DWORD dwParentID = WINCX(pCX->GetParentContext())->GetContextID();
return(MakeArgs("DW", &dwParentID));
}
return(NULL);
}
HDDEDATA CDDEWrapper::RegisterStatusBarChange(HSZ& hszItem)
{
// Get our arguments.
CString csServer;
DWORD dwWindowID;
ScanArgs(hszItem, "QCS,DW", &csServer, &dwWindowID);
// If server is empty, we'll just fail.
if(csServer.IsEmpty()) {
return(NULL);
}
if(FALSE == CDDEStatusBarChangeItem::DDERegister(csServer, dwWindowID)) {
dwWindowID = 0;
}
return(MakeArgs("DW", &dwWindowID));
}
HDDEDATA CDDEWrapper::UnRegisterStatusBarChange(HSZ& hszItem)
{
// Get our arguments.
CString csServer;
DWORD dwWindowID;
ScanArgs(hszItem, "QCS,DW", &csServer, &dwWindowID);
// If server is empty, we'll just fail.
if(csServer.IsEmpty()) {
return(NULL);
}
TwoByteBool bRetval = CDDEStatusBarChangeItem::DDEUnRegister(csServer, dwWindowID);
return(MakeArgs("BL", &bRetval));
}
void CDDEWrapper::StatusBarChange(CDDEStatusBarChangeItem *pItem, LPCSTR lpStatusMsg)
{
CString csStatusMsg = lpStatusMsg;
// Get the server name.
CString csServiceName = pItem->GetServiceName();
// Establish the connection to homeworld.
CDDEWrapper *pConv = ClientConnect(csServiceName, m_hsz[m_StatusBarChange]);
if(pConv == NULL) {
// The server isn't responding.
// There's not much else we can do here, simply return.
// Unregistration happens elsewhere.
return;
}
// Save the conversation, in case the DDE server disconnects behind
// our backs.
HCONV hSaveConv = pConv->m_hConv;
// Construct the flags for the call, and our calling format.
DWORD dwFlags = 0;
const char *pFormat = "DW,QCS";
// Create our argument list.
DWORD dwWindowID = pItem->GetWindowID();
HSZ hszItem = MakeItemArgs(pFormat, &dwWindowID, &csStatusMsg);
// Do the transaction, expect nothing.
DdeClientTransaction(NULL, 0L, hSaveConv, hszItem, CF_TEXT,
XTYP_POKE, m_Timeout, NULL);
// Cut the cord.
DdeFreeStringHandle(m_dwidInst, hszItem);
DdeDisconnect(hSaveConv);
// Make sure we still have a conversation, if so, delete the object.
pConv = GetConvObj(hSaveConv);
if(pConv) {
delete pConv;
}
}
//Returns :
// 0 - If incorrect WindowID
// -1 - If Can't go back
// ID - Id of window on which the operation was performed
HDDEDATA CDDEWrapper::NavigateBack(HSZ& hszItem)
{
DWORD ReturnID = 0x0;
// Retrieve our arguments.
DWORD WindowID;
ScanArgs(hszItem, "DW", &WindowID);
if (WindowID == 0xFFFFFFFF)
WindowID = fetchLastActiveWindow();
if(WindowID != 0x0)
{
// See if it's a valid Window ID
CFrameGlue *pFrame = CFrameGlue::FindFrameByID(WindowID, MWContextBrowser);
if(pFrame != NULL)
{
MWContext *pContext = (pFrame->GetMainContext() != NULL) ? pFrame->GetMainContext()->GetContext() : NULL;
if(pContext != NULL)
{
if(ABSTRACTCX(pContext)->CanAllBack())
{
ABSTRACTCX(pContext)->AllBack();
ReturnID = WindowID;
}
}
}
}
HDDEDATA hData = MakeArgs("DW", &ReturnID);
return(hData);
}
//Returns :
// 0 - If incorrect WindowID
// -1 - If Can't go forward
// ID - Id of window on which the operation was performed
HDDEDATA CDDEWrapper::NavigateForward(HSZ& hszItem)
{
DWORD ReturnID = 0x0;
// Retrieve our arguments.
DWORD WindowID;
ScanArgs(hszItem, "DW", &WindowID);
if (WindowID == 0xFFFFFFFF)
WindowID = fetchLastActiveWindow();
if(WindowID != 0x0)
{
// See if it's a valid Window ID
CFrameGlue *pFrame = CFrameGlue::FindFrameByID(WindowID, MWContextBrowser);
if(pFrame != NULL)
{
MWContext *pContext = (pFrame->GetMainContext() != NULL) ? pFrame->GetMainContext()->GetContext() : NULL;
if(pContext != NULL)
{
if(ABSTRACTCX(pContext)->CanAllForward())
{
ABSTRACTCX(pContext)->AllForward();
//Success, set the return value.
ReturnID = WindowID;
}
//else
// ReturnID = 0xFFFFFFFF;
}
}
}
HDDEDATA hData = MakeArgs("DW", &ReturnID);
return(hData);
}
//Returns :
// 0 - If incorrect WindowID
// -1 - If Can't Stop
// ID - Id of window on which the operation was performed
HDDEDATA CDDEWrapper::Stop(HSZ& hszItem)
{
DWORD ReturnID = 0L;
// Retrieve our arguments.
DWORD WindowID;
ScanArgs(hszItem, "DW", &WindowID);
if (WindowID == 0xFFFFFFFF)
WindowID = fetchLastActiveWindow();
if(WindowID != 0x0)
{
// See if it's a valid Window ID
CFrameGlue *pFrame = CFrameGlue::FindFrameByID(WindowID, MWContextBrowser);
if(pFrame != NULL)
{
MWContext *pContext = (pFrame->GetMainContext() != NULL) ? pFrame->GetMainContext()->GetContext() : NULL;
if(pContext != NULL)
{
if(ABSTRACTCX(pContext)->CanAllInterrupt())
{
ABSTRACTCX(pContext)->AllInterrupt();
//Success, set the return value.
ReturnID = WindowID;
}
else
ReturnID = 0xFFFFFFFF;
}
}
}
HDDEDATA hData = MakeArgs("DW", &ReturnID);
return(hData);
}
//Returns :
// 0 - If incorrect WindowID
// -1 - If Can't Reload
// ID - Id of window on which the operation was performed
HDDEDATA CDDEWrapper::Reload(HSZ& hszItem)
{
DWORD ReturnID = 0L;
// Retrieve our arguments.
DWORD WindowID;
ScanArgs(hszItem, "DW", &WindowID);
if (WindowID == 0xFFFFFFFF)
WindowID = fetchLastActiveWindow();
if(WindowID != 0x0)
{
// See if it's a valid Window ID
CFrameGlue *pFrame = CFrameGlue::FindFrameByID(WindowID, MWContextBrowser);
if(pFrame != NULL)
{
MWContext *pContext = (pFrame->GetMainContext() != NULL) ? pFrame->GetMainContext()->GetContext() : NULL;
if(pContext != NULL)
{
if(ABSTRACTCX(pContext)->CanAllReload())
{
ABSTRACTCX(pContext)->AllReload();
//Success, set the return value.
ReturnID = WindowID;
}
else
ReturnID = 0xFFFFFFFF;
}
}
}
HDDEDATA hData = MakeArgs("DW", &ReturnID);
return(hData);
}
//Returns :
// 0 - If incorrect WindowID
// -1 - If Can't Reload
// ID - Id of window on which the operation was performed
HDDEDATA CDDEWrapper::UserAgent(HSZ& hszItem)
{
CString csVersion = theApp.ResolveAppVersion();
return MakeArgs("QCS", &csVersion);
}
HDDEDATA CDDEWrapper::ClearCache(HSZ& hszItem)
{
TwoByteBool returnVal = FALSE;
int32 nSize;
// This would fail if the pref were locked, but it's what is done
// in the prefs dialog
if (!PREF_PrefIsLocked("browser.cache.disk_cache_size"))
{
PREF_GetIntPref("browser.cache.disk_cache_size", &nSize);
PREF_SetIntPref("browser.cache.disk_cache_size", 0);
PREF_SetIntPref("browser.cache.disk_cache_size", nSize);
returnVal = TRUE;
}
return MakeArgs("BL", &returnVal);
}
HDDEDATA CDDEWrapper::InCache(HSZ& hszItem)
{
TwoByteBool retVal = FALSE;
CString url;
ScanArgs(hszItem, "QCS", &url);
URL_Struct* url_s = NET_CreateURLStruct(url, NET_NORMAL_RELOAD);
int i;
if (url_s)
{
i = NET_FindURLInCache(url_s, NULL);
}
retVal = (i != 0);
NET_FreeURLStruct(url_s);
return MakeArgs("BL", &retVal);
}
HDDEDATA CDDEWrapper::CacheFilename(HSZ& hszItem)
{
CString retVal = "";
CString url;
ScanArgs(hszItem, "QCS", &url);
URL_Struct* url_s = NET_CreateURLStruct(url, NET_NORMAL_RELOAD);
if (url_s)
{
NET_FindURLInCache(url_s, NULL);
}
if (url_s && url_s->cache_file && *url_s->cache_file)
{
retVal = WH_FileName(url_s->cache_file, xpCache);
}
NET_FreeURLStruct(url_s);
return MakeArgs("QCS", &retVal);
}
HDDEDATA CDDEWrapper::CacheRemoveURL(HSZ& hszItem)
{
TwoByteBool retVal = FALSE;
CString url;
ScanArgs(hszItem, "QCS", &url);
URL_Struct* url_s = NET_CreateURLStruct(url, NET_NORMAL_RELOAD);
if (url_s)
{
NET_RemoveURLFromCache(url_s);
retVal = TRUE;
}
NET_FreeURLStruct(url_s);
return MakeArgs("BL", &retVal);
}
HDDEDATA CDDEWrapper::CacheAddURL(HSZ& hszItem)
{
TwoByteBool retVal = FALSE;
CString url;
ScanArgs(hszItem, "QCS", &url);
CAbstractCX* theContext = CAbstractCX::FindContextByID(fetchLastActiveWindow());
MWContext* mwContext = theContext->GetContext();
URL_Struct* url_s = NET_CreateURLStruct(url, NET_NORMAL_RELOAD);
if (url_s)
{
// Fetch and cache only
ABSTRACTCX(mwContext)->GetUrl(url_s, FO_CACHE_ONLY);
retVal = TRUE;
}
return MakeArgs("BL", &retVal);
}
HDDEDATA CDDEWrapper::ClearHistory(HSZ& hszItem)
{
TwoByteBool returnVal = FALSE;
int32 nSize;
// This would fail if the pref were locked, but it's what is done
// in the prefs dialog
if (!PREF_PrefIsLocked("browser.link_expiration"))
{
PREF_GetIntPref("browser.link_expiration", &nSize);
PREF_SetIntPref("browser.link_expiration", 0);
PREF_SetIntPref("browser.link_expiration", nSize);
returnVal = TRUE;
}
return MakeArgs("BL", &returnVal);
}
HDDEDATA CDDEWrapper::HistoryAddURL(HSZ& hszItem)
{
TwoByteBool retVal = FALSE;
CString url;
ScanArgs(hszItem, "QCS", &url);
URL_Struct* url_s = NET_CreateURLStruct(url, NET_NORMAL_RELOAD);
CAbstractCX *theContext = CAbstractCX::FindContextByID(fetchLastActiveWindow());
//MWContext *mwContext = theContext->GetContext();
if (url_s)
{
theContext->GetUrl(url_s, FO_CACHE_ONLY);
GH_UpdateGlobalHistory(url_s);
GH_UpdateURLTitle(url_s, (char*)(const char*)url, FALSE);
retVal = TRUE;
}
return MakeArgs("BL", &retVal);
}
HDDEDATA CDDEWrapper::HistoryRemoveURL(HSZ& hszItem)
{
TwoByteBool retVal = FALSE;
CString url;
ScanArgs(hszItem, "QCS", &url);
GHHANDLE theHistory = GH_GetContext(eGH_NameSort, NULL, NULL, NULL, NULL);
int recNo = GH_GetRecordNum(theHistory, (char*)((const char*)url));
if (recNo != -1)
{
GH_DeleteRecord(theHistory, recNo, FALSE);
GH_ReleaseContext(theHistory, FALSE);
retVal = TRUE;
}
return MakeArgs("BL", &retVal);
}
HDDEDATA CDDEWrapper::HistoryNumEntries(HSZ& hszItem)
{
DWORD retVal = 0;
GHHANDLE theHistory = GH_GetContext(eGH_NameSort, NULL, NULL, NULL, NULL);
retVal = GH_GetNumRecords(theHistory);
return MakeArgs("DW", &retVal);
}
HDDEDATA CDDEWrapper::HistoryGetEntry(HSZ& hszItem)
{
CString title;
CString url;
DWORD lastAccessed = 0;
DWORD firstAccessed = 0;
DWORD visitCount = 0;
DWORD recNo = 0;
DWORD retVal = 0;
ScanArgs(hszItem, "DW", &recNo);
GHHANDLE theHistory = GH_GetContext(eGH_NameSort, NULL, NULL, NULL, NULL);
gh_HistEntry* historyEntry = GH_GetRecord(theHistory, recNo);
if (historyEntry != NULL)
{
title = historyEntry->pszName;
url = historyEntry->address;
lastAccessed = historyEntry->last_accessed;
firstAccessed = historyEntry->first_accessed;
visitCount = historyEntry->iCount;
return MakeArgs("QCS,QCS,DW,DW,DW", &url, &title, &firstAccessed, &lastAccessed, &visitCount);
}
return MakeArgs("DW", &retVal);
}
HDDEDATA CDDEWrapper::InHistory(HSZ& hszItem)
{
TwoByteBool retVal = FALSE;
CString url;
ScanArgs(hszItem, "QCS", &url);
int i = GH_CheckGlobalHistory((char*)(const char*)url);
if (i != -1)
retVal = TRUE;
return MakeArgs("BL", &retVal);
}
HDDEDATA CDDEWrapper::GetWindowID(HSZ& hszItem)
{
CString name;
DWORD WindowID;
ScanArgs(hszItem, "QCS,DW", &name, &WindowID);
if (WindowID == 0xFFFFFFFF)
WindowID = fetchLastActiveWindow();
DWORD retVal = 0x0;
if(WindowID != 0x0)
{
// See if it's a valid Window ID
CFrameGlue *pFrame = CFrameGlue::FindFrameByID(WindowID, MWContextBrowser);
if(pFrame != NULL)
{
MWContext *pContext = (pFrame->GetMainContext() != NULL) ? pFrame->GetMainContext()->GetContext() : NULL;
if(pContext != NULL)
{
// We have a reference point.... find the named window
MWContext* returnContext = XP_FindNamedContextInList(pContext, (char*)(const char*)name);
if (returnContext != NULL)
retVal = WINCX(pContext)->GetContextID();
}
}
}
return MakeArgs("DW", &retVal);
}
HDDEDATA CDDEWrapper::SupportsMimeType(HSZ& hszItem)
{
return 0;
}
HDDEDATA CDDEWrapper::ExecuteJavaScript(HSZ& hszItem)
{
return 0;
}
HDDEDATA CDDEWrapper::PrintWindow(HSZ& hszItem)
{
DWORD ReturnID = 0L;
// Retrieve our arguments.
DWORD WindowID;
ScanArgs(hszItem, "DW", &WindowID);
if (WindowID == 0xFFFFFFFF)
WindowID = fetchLastActiveWindow();
if(WindowID != 0x0)
{
// See if it's a valid Window ID
CWinCX* pContext = GetContext(WindowID);
if(pContext != NULL)
{
if(pContext->CanPrint())
{
pContext->Print();
//Success, set the return value.
ReturnID = WindowID;
}
else
ReturnID = 0xFFFFFFFF;
}
}
HDDEDATA hData = MakeArgs("DW", &ReturnID);
return(hData);
}
HDDEDATA CDDEWrapper::PrintURL(HSZ& hszItem)
{
TwoByteBool retVal = TRUE;
CString url;
CString printer;
CString driver;
CString port;
ScanArgs(hszItem, "QCS,QCS,QCS,QCS", &url, &printer, &driver, &port);
char* pr = NULL;
char* dr = NULL;
char* pt = NULL;
if (!printer.IsEmpty())
pr = (char*)(const char*)printer;
if (!driver.IsEmpty())
dr = (char*)(const char*)driver;
if (!port.IsEmpty())
pt = (char*)(const char*)port;
#ifdef MOZ_NGLAYOUT
XP_ASSERT(0);
#else
CPrintCX::AutomatedPrint((char*)(const char*)url, pr, dr, pt);
#endif
return MakeArgs("BL", &retVal);
}
CGenericView *CDDEWrapper::GetView(DWORD dwContextID)
{
CGenericView *pRetval = NULL;
CWinCX *pCX = GetContext(dwContextID);
if(pCX) {
pRetval = pCX->GetView();
}
return(pRetval);
}
CFrameGlue *CDDEWrapper::GetFrame(DWORD dwContextID)
{
CFrameGlue *pRetval = NULL;
CWinCX *pCX = GetContext(dwContextID);
if(pCX) {
pRetval = pCX->GetFrame();
}
return(pRetval);
}
CWinCX *CDDEWrapper::GetContext(DWORD dwContextID)
{
CWinCX *pRetval = NULL;
CAbstractCX *pAbstract = CAbstractCX::FindContextByID(dwContextID);
if(pAbstract && pAbstract->IsDestroyed() == FALSE) {
// Must be a window, and a MWContextBrowser.
if(pAbstract->IsFrameContext() && pAbstract->GetContext()->type == MWContextBrowser) {
pRetval = VOID2CX(pAbstract, CWinCX);
}
}
return(pRetval);
}
DWORD CDDEWrapper::fetchLastActiveWindow()
{
return FEU_GetLastActiveFrameID(MWContextBrowser);
}