/* -*- 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; CPrintCX::AutomatedPrint((char*)(const char*)url, pr, dr, pt); 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); }