home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / dde.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  129.2 KB  |  4,310 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. //    File to handle DDE remote control commands.
  19.  
  20. #include "stdafx.h"
  21.  
  22. #include "genframe.h"
  23.  
  24. #include "wfedde.h"
  25. #include "ddectc.h"
  26. #include "regproto.h"
  27. #include "winclose.h"
  28. #include "presentm.h"
  29. #include "urlecho.h"
  30. #include "mainfrm.h"
  31. #include "prefapi.h"    // Added so that prefs can be referenced (Dave Hyatt - 8/13/97)
  32. #include "net.h"        // Added so cache can be referenced (8/18/97)
  33. #include "mkcache.h"    // Ditto
  34. #include "cxprint.h"    // The printing context... used for PrintWindow and PrintURL (8/27/97)
  35.  
  36. //    Our DDE instance identifier.
  37. DWORD CDDEWrapper::m_dwidInst;
  38.  
  39. //    Wether or not DDE was successfully initialized.
  40. BOOL CDDEWrapper::m_bDDEActive;
  41.  
  42. //    Our array of hsz strings.
  43. HSZ CDDEWrapper::m_hsz[CDDEWrapper::m_MaxHSZ];
  44.  
  45. //    A list of all current conversations.  The PtrToPtr map was used since
  46. //        the pointers are known to be 32 bits long, and the HCONV is a 
  47. //        DWORD or possibly a pointer, and WordToPtr just wouldn't cut it
  48. //        with 16 bits and all.
  49. CMapPtrToPtr CDDEWrapper::m_ConvList;
  50.  
  51. //    Command filter for DDEML
  52. DWORD CDDEWrapper::m_dwafCmd;
  53.  
  54. //    Call back function for use with DDEML
  55. FARPROC CDDEWrapper::m_pfnCallBack;
  56.  
  57. //    Array of acceptable clipboard formats in our CallBack
  58. //    Null terminate, please.
  59. UINT CDDEWrapper::m_cfFmts[] = { CF_TEXT, 0 };
  60.  
  61. //    Purpose:    Initialize our DDE layer
  62. //    Arguments:    void
  63. //    Returns:    void
  64. //    Comments:    Sets all CDDEWrapper static members and makes our DDE
  65. //                    service available to the DDEML.
  66. //                We won't warn the user on an invalid initialization,
  67. //                    as they probably won't be using this DDE layer if
  68. //                    they have a screwed up setup....
  69. //    Revision History:
  70. //        12-28-94    created GAB
  71. void DDEStartup()
  72. {
  73.     //    Initialize all CDDEWrapper static members here.
  74.     //    No CDDEWrapper instances exist at this point.
  75.     //    Note that m_cfFmts is already intialized, m_ConvList should
  76.     //        be initially already empty.
  77.     CDDEWrapper::m_dwidInst = 0L;
  78.     CDDEWrapper::m_bDDEActive = FALSE;
  79.     for(int i_counter = 0; i_counter < CDDEWrapper::m_MaxHSZ;
  80.         i_counter++)    {
  81.         CDDEWrapper::m_hsz[i_counter] = NULL;
  82.     }
  83.     CDDEWrapper::m_dwafCmd = APPCLASS_STANDARD
  84.         | CBF_FAIL_SELFCONNECTIONS;
  85.     CDDEWrapper::m_pfnCallBack = NULL;
  86.  
  87. #ifdef XP_WIN16
  88.     //    Find out if we can even use DDEML (must be in protected mode).
  89.     //    Undoubtedly, this is the case since we must be in protected
  90.     //        mode to use WINSOCK services, but just to be anal....
  91.     //  GetWinFlags() has been removed in MSVC 2.0 and the analog doesn't
  92.     //      look like it does the same thing.  chouck 29-Dec-94
  93.     if(!(GetWinFlags() & WF_PMODE))    {
  94.         //    Not in protected mode, can not continue with DDEML
  95.         return;
  96.     }
  97. #endif
  98.     
  99.     //    Set up our callback function to be registered with DDEML.
  100.     CDDEWrapper::m_pfnCallBack = (FARPROC)NetscapeDDECallBack;
  101.         
  102.     //    DDEML initialization, don't do anything on failure.
  103.     if(DdeInitialize(&CDDEWrapper::m_dwidInst,
  104.         (PFNCALLBACK)CDDEWrapper::m_pfnCallBack,
  105.         CDDEWrapper::m_dwafCmd, 0L))    {
  106.         //    Unable to initialize, don't continue.
  107.         return;
  108.     }
  109.     
  110.     //    We're DDEed.
  111.     CDDEWrapper::m_bDDEActive = TRUE;
  112.     
  113.     //    Load in all frequently used HSZs.
  114.     //    Unfortunately, there is really no good way to detect any errors
  115.     //        on these string intializations, so let the blame land
  116.     //        where it will if something fails; we could actually just
  117.     //        call shutdown and return if need be....
  118.     // Ugh.  I hate CStrings reason #59:  passing it as a (char *) requires
  119.     //   a nasty cast like the one below.  Chouck 29-Dec-94
  120.     CString CS;
  121.     
  122.     CS.LoadString(IDS_DDE_SERVICE_NAME);
  123.     CDDEWrapper::m_hsz[CDDEWrapper::m_ServiceName] =
  124.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  125.         (char *)(const char *)CS, CP_WINANSI);
  126.     CS.LoadString(IDS_DDE_OPENURL);
  127.     CDDEWrapper::m_hsz[CDDEWrapper::m_OpenURL] =
  128.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  129.         (char *)(const char *)CS, CP_WINANSI);
  130.     CS.LoadString(IDS_DDE_SHOWFILE);
  131.     CDDEWrapper::m_hsz[CDDEWrapper::m_ShowFile] =
  132.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  133.         (char *)(const char *)CS, CP_WINANSI);
  134.     CS.LoadString(IDS_DDE_ACTIVATE);
  135.     CDDEWrapper::m_hsz[CDDEWrapper::m_Activate] =
  136.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  137.         (char *)(const char *)CS, CP_WINANSI);
  138.     CS.LoadString(IDS_DDE_LISTWINDOWS);
  139.     CDDEWrapper::m_hsz[CDDEWrapper::m_ListWindows] =
  140.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  141.         (char *)(const char *)CS, CP_WINANSI);
  142.     CS.LoadString(IDS_DDE_GETWINDOWINFO);
  143.     CDDEWrapper::m_hsz[CDDEWrapper::m_GetWindowInfo] =
  144.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  145.         (char *)(const char *)CS, CP_WINANSI);
  146.     CS.LoadString(IDS_DDE_PARSEANCHOR);
  147.     CDDEWrapper::m_hsz[CDDEWrapper::m_ParseAnchor] =
  148.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  149.         (char *)(const char *)CS, CP_WINANSI);
  150.     CS.LoadString(IDS_DDE_EXIT);
  151.     CDDEWrapper::m_hsz[CDDEWrapper::m_Exit] =
  152.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  153.         (char *)(const char *)CS, CP_WINANSI);
  154.     CS.LoadString(IDS_DDE_REGISTERPROTOCOL);
  155.     CDDEWrapper::m_hsz[CDDEWrapper::m_RegisterProtocol] =
  156.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  157.         (char *)(const char *)CS, CP_WINANSI);
  158.     CS.LoadString(IDS_DDE_UNREGISTERPROTOCOL);
  159.     CDDEWrapper::m_hsz[CDDEWrapper::m_UnRegisterProtocol] =
  160.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  161.         (char *)(const char *)CS, CP_WINANSI);
  162.     CS.LoadString(IDS_DDE_REGISTERVIEWER);
  163.     CDDEWrapper::m_hsz[CDDEWrapper::m_RegisterViewer] =
  164.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  165.         (char *)(const char *)CS, CP_WINANSI);
  166.     CS.LoadString(IDS_DDE_QUERYVIEWER);
  167.     CDDEWrapper::m_hsz[CDDEWrapper::m_QueryViewer] =
  168.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  169.         (char *)(const char *)CS, CP_WINANSI);
  170.     CS.LoadString(IDS_DDE_VIEWDOCFILE);
  171.     CDDEWrapper::m_hsz[CDDEWrapper::m_ViewDocFile] =
  172.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  173.         (char *)(const char *)CS, CP_WINANSI);
  174.     CS.LoadString(IDS_DDE_UNREGISTERVIEWER);
  175.     CDDEWrapper::m_hsz[CDDEWrapper::m_UnRegisterViewer] =
  176.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  177.         (char *)(const char *)CS, CP_WINANSI);
  178.     CS.LoadString(IDS_DDE_REGISTERURLECHO);
  179.     CDDEWrapper::m_hsz[CDDEWrapper::m_RegisterURLEcho] =
  180.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  181.         (char *)(const char *)CS, CP_WINANSI);
  182.     CS.LoadString(IDS_DDE_URLECHO);
  183.     CDDEWrapper::m_hsz[CDDEWrapper::m_URLEcho] =
  184.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  185.         (char *)(const char *)CS, CP_WINANSI);
  186.     CS.LoadString(IDS_DDE_UNREGISTERURLECHO);
  187.     CDDEWrapper::m_hsz[CDDEWrapper::m_UnRegisterURLEcho] =
  188.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  189.         (char *)(const char *)CS, CP_WINANSI);
  190.     CS.LoadString(IDS_DDE_REGISTERWINDOWCHANGE);
  191.     CDDEWrapper::m_hsz[CDDEWrapper::m_RegisterWindowChange] =
  192.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  193.         (char *)(const char *)CS, CP_WINANSI);
  194.     CS.LoadString(IDS_DDE_WINDOWCHANGE);
  195.     CDDEWrapper::m_hsz[CDDEWrapper::m_WindowChange] =
  196.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  197.         (char *)(const char *)CS, CP_WINANSI);
  198.     CS.LoadString(IDS_DDE_UNREGISTERWINDOWCHANGE);
  199.     CDDEWrapper::m_hsz[CDDEWrapper::m_UnRegisterWindowChange] =
  200.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  201.         (char *)(const char *)CS, CP_WINANSI);
  202.     CS.LoadString(IDS_DDE_BEGINPROGRESS);
  203.     CDDEWrapper::m_hsz[CDDEWrapper::m_BeginProgress] =
  204.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  205.         (char *)(const char *)CS, CP_WINANSI);
  206.     CS.LoadString(IDS_DDE_SETPROGRESSRANGE);
  207.     CDDEWrapper::m_hsz[CDDEWrapper::m_SetProgressRange] =
  208.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  209.         (char *)(const char *)CS, CP_WINANSI);
  210.     CS.LoadString(IDS_DDE_MAKINGPROGRESS);
  211.     CDDEWrapper::m_hsz[CDDEWrapper::m_MakingProgress] =
  212.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  213.         (char *)(const char *)CS, CP_WINANSI);
  214.     CS.LoadString(IDS_DDE_ENDPROGRESS);
  215.     CDDEWrapper::m_hsz[CDDEWrapper::m_EndProgress] =
  216.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  217.         (char *)(const char *)CS, CP_WINANSI);
  218.     CS.LoadString(IDS_DDE_ALERT);
  219.     CDDEWrapper::m_hsz[CDDEWrapper::m_Alert] =
  220.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  221.         (char *)(const char *)CS, CP_WINANSI);
  222.     CS.LoadString(IDS_DDE_VERSION);
  223.     CDDEWrapper::m_hsz[CDDEWrapper::m_Version] =
  224.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  225.         (char *)(const char *)CS, CP_WINANSI);
  226.     CS.LoadString(IDS_DDE_CANCELPROGRESS);
  227.     CDDEWrapper::m_hsz[CDDEWrapper::m_CancelProgress] =
  228.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  229.         (char *)(const char *)CS, CP_WINANSI);
  230.     CS.LoadString(IDS_DDE_QUERYURLFILE);
  231.     CDDEWrapper::m_hsz[CDDEWrapper::m_QueryURLFile] =
  232.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  233.         (char *)(const char *)CS, CP_WINANSI);
  234.     CS.LoadString(IDS_DDE_LISTFRAMECHILDREN);
  235.     CDDEWrapper::m_hsz[CDDEWrapper::m_ListFrameChildren] =
  236.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  237.         (char *)(const char *)CS, CP_WINANSI);
  238.     CS.LoadString(IDS_DDE_GETFRAMEPARENT);
  239.     CDDEWrapper::m_hsz[CDDEWrapper::m_GetFrameParent] =
  240.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  241.         (char *)(const char *)CS, CP_WINANSI);
  242.     CS.LoadString(IDS_DDE_REGISTERSTATUSBARCHANGE);
  243.     CDDEWrapper::m_hsz[CDDEWrapper::m_RegisterStatusBarChange] =
  244.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  245.         (char *)(const char *)CS, CP_WINANSI);
  246.     CS.LoadString(IDS_DDE_STATUSBARCHANGE);
  247.     CDDEWrapper::m_hsz[CDDEWrapper::m_StatusBarChange] =
  248.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  249.         (char *)(const char *)CS, CP_WINANSI);
  250.     CS.LoadString(IDS_DDE_UNREGISTERSTATUSBARCHANGE);
  251.     CDDEWrapper::m_hsz[CDDEWrapper::m_UnRegisterStatusBarChange] =
  252.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  253.         (char *)(const char *)CS, CP_WINANSI);
  254.     CS.LoadString(IDS_DDE_NAVIGATEBACK);
  255.     CDDEWrapper::m_hsz[CDDEWrapper::m_NavigateBack] =
  256.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  257.         (char *)(const char *)CS, CP_WINANSI);
  258.     CS.LoadString(IDS_DDE_NAVIGATEFORWARD);
  259.     CDDEWrapper::m_hsz[CDDEWrapper::m_NavigateForward] =
  260.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  261.         (char *)(const char *)CS, CP_WINANSI);
  262.     CS.LoadString(IDS_DDE_RELOAD);
  263.     CDDEWrapper::m_hsz[CDDEWrapper::m_Reload] =
  264.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  265.         (char *)(const char *)CS, CP_WINANSI);
  266.     CS.LoadString(IDS_DDE_STOP);
  267.     CDDEWrapper::m_hsz[CDDEWrapper::m_Stop] =
  268.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  269.         (char *)(const char *)CS, CP_WINANSI);
  270.     CS.LoadString(IDS_DDE_GETDOCWIDTH);
  271.     CDDEWrapper::m_hsz[CDDEWrapper::m_GetDocumentWidth] =
  272.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  273.         (char *)(const char *)CS, CP_WINANSI);
  274.     CS.LoadString(IDS_DDE_GETDOCHEIGHT);
  275.     CDDEWrapper::m_hsz[CDDEWrapper::m_GetDocumentHeight] =
  276.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  277.         (char *)(const char *)CS, CP_WINANSI);
  278.     CS.LoadString(IDS_DDE_USERAGENT);
  279.     CDDEWrapper::m_hsz[CDDEWrapper::m_UserAgent] =
  280.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  281.         (char *)(const char *)CS, CP_WINANSI);
  282.     CS.LoadString(IDS_DDE_CACHE_CLEARCACHE);
  283.     CDDEWrapper::m_hsz[CDDEWrapper::m_Cache_ClearCache] =
  284.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  285.         (char *)(const char *)CS, CP_WINANSI);
  286.     CS.LoadString(IDS_DDE_CACHE_FILENAME);
  287.     CDDEWrapper::m_hsz[CDDEWrapper::m_Cache_Filename] =
  288.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  289.         (char *)(const char *)CS, CP_WINANSI);
  290.     CS.LoadString(IDS_DDE_CACHE_INCACHE);
  291.     CDDEWrapper::m_hsz[CDDEWrapper::m_Cache_InCache] =
  292.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  293.         (char *)(const char *)CS, CP_WINANSI);
  294.     CS.LoadString(IDS_DDE_CACHE_REMOVEURL);
  295.     CDDEWrapper::m_hsz[CDDEWrapper::m_Cache_RemoveURL] =
  296.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  297.         (char *)(const char *)CS, CP_WINANSI);
  298.     CS.LoadString(IDS_DDE_CACHE_ADDURL);
  299.     CDDEWrapper::m_hsz[CDDEWrapper::m_Cache_AddURL] =
  300.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  301.         (char *)(const char *)CS, CP_WINANSI);
  302.     CS.LoadString(IDS_DDE_HISTORY_REMOVEURL);
  303.     CDDEWrapper::m_hsz[CDDEWrapper::m_History_RemoveURL] =
  304.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  305.         (char *)(const char *)CS, CP_WINANSI);
  306.     CS.LoadString(IDS_DDE_HISTORY_ADDURL);
  307.     CDDEWrapper::m_hsz[CDDEWrapper::m_History_AddURL] =
  308.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  309.         (char *)(const char *)CS, CP_WINANSI);
  310.     CS.LoadString(IDS_DDE_HISTORY_INHISTORY);
  311.     CDDEWrapper::m_hsz[CDDEWrapper::m_History_InHistory] =
  312.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  313.         (char *)(const char *)CS, CP_WINANSI);
  314.     CS.LoadString(IDS_DDE_HISTORY_CLEARHISTORY);
  315.     CDDEWrapper::m_hsz[CDDEWrapper::m_History_ClearHistory] =
  316.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  317.         (char *)(const char *)CS, CP_WINANSI);
  318.     CS.LoadString(IDS_DDE_HISTORY_NUMENTRIES);
  319.     CDDEWrapper::m_hsz[CDDEWrapper::m_History_NumEntries] =
  320.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  321.         (char *)(const char *)CS, CP_WINANSI);
  322.     CS.LoadString(IDS_DDE_HISTORY_GETENTRY);
  323.     CDDEWrapper::m_hsz[CDDEWrapper::m_History_GetEntry] =
  324.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  325.         (char *)(const char *)CS, CP_WINANSI);
  326.  
  327.     CS.LoadString(IDS_DDE_GETWINDOWID);
  328.     CDDEWrapper::m_hsz[CDDEWrapper::m_GetWindowID] =
  329.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  330.         (char *)(const char *)CS, CP_WINANSI);
  331.     CS.LoadString(IDS_DDE_SUPPORTSMIMETYPE);
  332.     CDDEWrapper::m_hsz[CDDEWrapper::m_SupportsMimeType] =
  333.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  334.         (char *)(const char *)CS, CP_WINANSI);
  335.     CS.LoadString(IDS_DDE_EXECUTEJAVASCRIPT);
  336.     CDDEWrapper::m_hsz[CDDEWrapper::m_ExecuteJavaScript] =
  337.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  338.         (char *)(const char *)CS, CP_WINANSI);
  339.     CS.LoadString(IDS_DDE_PRINTWINDOW);
  340.     CDDEWrapper::m_hsz[CDDEWrapper::m_PrintWindow] =
  341.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  342.         (char *)(const char *)CS, CP_WINANSI);
  343.     CS.LoadString(IDS_DDE_PRINTURL);
  344.     CDDEWrapper::m_hsz[CDDEWrapper::m_PrintURL] =
  345.         DdeCreateStringHandle(CDDEWrapper::m_dwidInst,
  346.         (char *)(const char *)CS, CP_WINANSI);
  347.  
  348.     //    Register our Name Service with DDEML; we are prepared to rock.
  349.     //    Ignore any error, we could call shutdown if need really be....
  350.     DdeNameService(CDDEWrapper::m_dwidInst,
  351.         CDDEWrapper::m_hsz[CDDEWrapper::m_ServiceName], NULL,
  352.         DNS_REGISTER);
  353.     
  354.     TRACE("DDE started, forgive me, father....\n");
  355. }
  356.  
  357. //    Purpose:    Shut down any intitialization that occurred previously
  358. //    Arguments:    void
  359. //    Returns:    void
  360. //    Comments:    Won't call any DDE functions if there is no need.
  361. //    Revision History:
  362. //        12-28-94    created GAB
  363. void DDEShutdown()
  364. {
  365.     //    First see if we're DDEed.
  366.         if(CDDEWrapper::m_bDDEActive == TRUE) {
  367.  
  368.         //    Turn off all our name services.
  369.         DdeNameService(CDDEWrapper::m_dwidInst,
  370.             CDDEWrapper::m_hsz[CDDEWrapper::m_ServiceName], NULL,
  371.             DNS_UNREGISTER);
  372.         
  373.         //    Get rid of all our HSZ strings.
  374.         //    We have to finish up all DDE calls before we call DdeUnInitialize
  375.         //        (that's the current theory), so just do this and don't
  376.         //        worry about the side effects if we can't unitialize.
  377.         for(int i_counter = 0; i_counter < CDDEWrapper::m_MaxHSZ;
  378.             i_counter++)    {
  379.             if(CDDEWrapper::m_hsz[i_counter] != NULL)    {
  380.                 //    Ignore errors.  No proper way to handle them on wind
  381.                 //        down.  Will not hurt initialization at a later
  382.                 //        time as Windows recycles these strings.
  383.                 DdeFreeStringHandle(CDDEWrapper::m_dwidInst,
  384.                     CDDEWrapper::m_hsz[i_counter]);
  385.                 CDDEWrapper::m_hsz[i_counter] = NULL;
  386.             }
  387.         }        
  388.     
  389.         //    We have no real way of recognizing why we can't deinitialize
  390.         //        our DDE layer, so just return if unable....
  391.         if(DdeUninitialize(CDDEWrapper::m_dwidInst) == 0)    {
  392.             //    System won't let us unitialize.
  393.             //    Just return without disabling the callback and current
  394.             //        conversations; it will be up to the system to clean
  395.             //        this up and handle the abscense of any missing HSZs...
  396.             TRACE("Couldn't shut down DDE.\n");
  397.             return;
  398.         }
  399.         
  400.         //    Reset value for consistancy....  Someone, one day, might
  401.         //        for some reason shut us down, and then restart.  Best
  402.         //        not to keep state between periods.
  403.         CDDEWrapper::m_dwidInst = 0L;
  404.         CDDEWrapper::m_bDDEActive = FALSE;
  405.         CDDEWrapper::m_dwafCmd = 0L;
  406.     }
  407.     
  408.     //    Erase the pointer to the callback.
  409.     CDDEWrapper::m_pfnCallBack = NULL;
  410.     
  411.     //    DDEML and the CallBack are dead.
  412.     //    Kill off any dead conversation objects that we have, unbiased.
  413.     //    Chances are, that if we receive appropriate disconnects when
  414.     //        deinitializing, that we won't have any conversations anyhow,
  415.     //        though I can't guarantee windows is so well thought out in
  416.     //        this regard.
  417.     //    It should be noted here that the list management is actually
  418.     //        maintained by the CDDEWrapper constructor, and destructor,
  419.     //        respectively.
  420.     CDDEWrapper *pWrap;
  421.     void *vp_dump, *vp_wrap;
  422.     POSITION pos;
  423.     while(CDDEWrapper::m_ConvList.IsEmpty() != 0)    {
  424.         pos = CDDEWrapper::m_ConvList.GetStartPosition();
  425.         
  426.         if(pos == NULL)    {
  427.             //    don't know how this would happen.
  428.             //    don't let it happen though.
  429.             break;
  430.         }
  431.  
  432.         //    Get the valid pointer to the DDEWrapper
  433.         CDDEWrapper::m_ConvList.GetNextAssoc(pos, vp_dump, vp_wrap);
  434.         pWrap = (CDDEWrapper *)vp_wrap;
  435.             
  436.         //    Is this a valid entry anyhow?
  437.         if(pWrap != NULL)    {
  438.             //    Actually remove the object from memory
  439.             delete pWrap;
  440.         }
  441.     }
  442.     
  443.     //    Shutdown complete.
  444.     //    If someone needed to, they could call our startup function
  445.     //        again and start this whole thing over again now.
  446.     TRACE("DDE shutdown is complete.\n");
  447. }
  448.  
  449. //    Purpose:    A callback function for the DDEML DLL, and to possibly
  450. //                    multiplex custom calls in from our own application.
  451. //    Arguments:    type    Specifies the type of the current transation.
  452. //                fmt        Specifies the format in which data is to be sent
  453. //                            or received
  454. //                hconv    Identifies the conversation associated with the
  455. //                            current transaction
  456. //                hsz1    Identifies a string, the context of which is
  457. //                            decided by the current transaction type
  458. //                hsz2    ditto
  459. //                hData    Identifies some DDE data, the context of which is
  460. //                            decided by the current transaction type
  461. //                dwData1    Specifies tranaction specific data
  462. //                dwData2    ditto
  463. //    Returns:    HDDEDATA    The actual return type is relative to the
  464. //                                type of the transaction.
  465. //    Comments:    Multiplexes all conversations to their appropriate
  466. //                    CDDEWrapper instance, or ignores them.
  467. //                Due to the nature of Callbacks, and exported functions,
  468. //                    DO NOT USE TRACES HERE, or GPF.
  469. //                The code will have to be air tight first time through,
  470. //                    be careful.
  471. //    Revision History:
  472. //        12-28-94    created GAB
  473. //        12-30-94    Began fleshing out else ifs and switch statement
  474. //                        to multiplex DDE transactions.
  475. //                    This is likely to be one of the most monstrous
  476. //                        functions I'll ever write.
  477. HDDEDATA 
  478. CALLBACK 
  479. #ifndef XP_WIN32
  480. _export 
  481. #endif
  482. NetscapeDDECallBack(UINT type, UINT fmt,
  483.     HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hData, DWORD dwData1,
  484.     DWORD dwData2)
  485. {
  486.     //    First, are we correctly initialized?
  487.     if(CDDEWrapper::m_bDDEActive == FALSE)    {
  488.         return(NULL);
  489.     }
  490.     
  491.     //    Do we support the format they are requesting?
  492.     //    Fall through on not specified.
  493.     if(fmt)    {
  494.         //    Look through our list of supported formats, until we hit
  495.         //        NULL at the end.
  496.         for(int i_counter = 0; 1; i_counter++)    {
  497.             if(CDDEWrapper::m_cfFmts[i_counter] == 0)    {
  498.                 //    End of list, and no match, fail.
  499.                 return(NULL);
  500.             }
  501.             if(CDDEWrapper::m_cfFmts[i_counter] == fmt)    {
  502.                 //    Matched, so break.
  503.                 break;
  504.             }
  505.         }
  506.     }
  507.     
  508.     //    Depending on the class of transaction, we return different data.
  509.     if(type & XCLASS_BOOL)    {
  510.         //    Must return (HDDEDATA)TRUE or (HDDEDATA)FALSE
  511.         switch(type)    {
  512.         case XTYP_ADVSTART:    {
  513.             //    We are the server.
  514.             //    A client specified the XTYP_ADVSTART in a call to
  515.             //        DdeClientTransaction
  516.             break;
  517.         }
  518.         case XTYP_CONNECT:    {
  519.             //    We are the server.
  520.             //    A client call the DdeConnect specifying a service and
  521.             //        topic name which we support.
  522.             HSZ& hszTopic = hsz1;
  523.             HSZ& hszService = hsz2;
  524.             
  525.             //    Deny the connection if the service name is not the
  526.             //        one we are taking connections for.
  527.             if(hszService !=
  528.                 CDDEWrapper::m_hsz[CDDEWrapper::m_ServiceName])    {
  529.                 return((HDDEDATA)FALSE);
  530.             }
  531.             
  532.             //    Now, the topic can be NULL, or it can be any one of our
  533.             //        topic names to be accepted.
  534.             if(hszTopic == NULL)    {
  535.                 return((HDDEDATA)TRUE);
  536.             }
  537.             
  538.             //    Go through all our topics, see if we match.
  539.             if(0 != CDDEWrapper::EnumTopic(hszTopic))    {
  540.                 return((HDDEDATA)TRUE);
  541.             }
  542.             
  543.             //    Topic not supported
  544.             return((HDDEDATA)FALSE);
  545.         }
  546.         default:
  547.             //    unknown
  548.             return((HDDEDATA)FALSE);
  549.         }
  550.         
  551.         //    Break handled here
  552.         return((HDDEDATA)FALSE);
  553.     }
  554.     else if(type & XCLASS_DATA)    {
  555.         //    Must return DDE data handle, CBR_BLOCK, or NULL
  556.         switch(type)    {
  557.         case XTYP_ADVREQ:    {
  558.             //    We are the server.
  559.             //    We called DdePostAdvise indicating that the data of
  560.             //        an item in the advise loop had changed.
  561.             break;
  562.         }
  563.         case XTYP_REQUEST:    {
  564.             //    We are the server.
  565.             //    A client said XTYP_REQUEST in DdeClientTransaction
  566.             HSZ& hszTopic = hsz1;
  567.             HSZ& hszItem = hsz2;
  568.             
  569.             //    Get the object associated with this conversation,
  570.             //        and let it handle the request.
  571.             CDDEWrapper *pWrap = CDDEWrapper::GetConvObj(hconv);
  572.             if(pWrap != NULL)    {
  573.                 return(pWrap->RequestHandler(hszTopic, hszItem));
  574.             }            
  575.             break;
  576.         }
  577.         case XTYP_WILDCONNECT:    {
  578.             //    We are the server
  579.             //    A client called DdeConnect or DdeConnectList specifying
  580.             //        NULL for the service name, the topic name, or both
  581.             HSZ& hszTopic = hsz1;
  582.             HSZ& hszService = hsz2;
  583.             
  584.             //    One way we can deny this type of connection is
  585.             //        if the service name is not null, and is not our
  586.             //        service name.
  587.             if(hszService != NULL)    {
  588.                 if(hszService !=
  589.                     CDDEWrapper::m_hsz[CDDEWrapper::m_ServiceName])    {
  590.                     return(NULL);
  591.                 }
  592.             }
  593.             
  594.             //    The only other way we can deny this type of connection
  595.             //        is if the topic name is not one that we support.
  596.             //    Skip the service name.
  597.             if(hszTopic != NULL)    {
  598.                 if(0 == CDDEWrapper::EnumTopic(hszTopic))    {
  599.                     //    Topic wasn't matched.
  600.                     return(NULL);
  601.                 }
  602.             }
  603.             
  604.             //    Obviously, we're going to be accepting this connection.
  605.             //    We have to return all matching service/topic pairs
  606.             //        that were given to us.
  607.             //    Get an array of HSZPAIRs that is big enough to take
  608.             //        all our topics.
  609.             HSZPAIR ahszpair[CDDEWrapper::m_MaxHSZ + 1 -
  610.                 CDDEWrapper::m_TopicStart];
  611.                 
  612.             //    Match up all service/topic matches.
  613.             int i_depth = 0;
  614.             for(int i_counter = CDDEWrapper::m_TopicStart; i_counter <
  615.                 CDDEWrapper::m_MaxHSZ; i_counter++)    {                
  616.                 //    See if we are over an appropriate topic.
  617.                 if(hszTopic == NULL || hszTopic ==
  618.                     CDDEWrapper::m_hsz[i_counter])    {
  619.                     //    Assign stuff over, don't care about service name,
  620.                     //        we only have one.
  621.                     ahszpair[i_depth].hszSvc =
  622.                         CDDEWrapper::m_hsz[CDDEWrapper::m_ServiceName];
  623.                     ahszpair[i_depth].hszTopic =
  624.                         CDDEWrapper::m_hsz[i_counter];
  625.                         
  626.                     //    We are one further in the array.
  627.                     i_depth++;
  628.                 }
  629.             }
  630.             
  631.             //    Cap off the list with some NULLs, i_depth is correctly
  632.             //        set.
  633.             ahszpair[i_depth].hszSvc = NULL;
  634.             ahszpair[i_depth].hszTopic = NULL;
  635.             i_depth++;
  636.             
  637.             //    Create the array in the DDE way.
  638.             HDDEDATA pData = DdeCreateDataHandle(CDDEWrapper::m_dwidInst,
  639.                 (unsigned char *) &ahszpair, 
  640.                 sizeof(HSZPAIR) * i_depth, 
  641.                 0L, 
  642.                 NULL,
  643.                 fmt,
  644.                 0);                
  645.             
  646.             //    Return it.  Don't care on failure, as it will be NULL
  647.             //        anyhow.
  648.             return(pData);
  649.         }
  650.         default:
  651.             //    unknown
  652.             return(NULL);
  653.         }
  654.         
  655.         //    Break handled here
  656.         return(NULL);
  657.     }
  658.     else if(type & XCLASS_FLAGS)    {
  659.         //    Must return DDE_FACK, DDE_BUSY, or DDE_FNOTPROCESSED
  660.         switch(type)    {
  661.         case XTYP_ADVDATA:    {
  662.             //    We are the client.
  663.             //    The server gave us a data handle.
  664.             break;
  665.         }
  666.         case XTYP_EXECUTE:    {
  667.             //    We are the server.
  668.             //    A client said XTYP_EXECUTE in DdeClientTransaction
  669.             break;
  670.         }
  671.         case XTYP_POKE:    {
  672.             //    We are the Server
  673.             //    A client said XTYP_POKE in DdeClientTransaction
  674.             HSZ& hszTopic = hsz1;
  675.             HSZ& hszItem = hsz2;
  676.             HDDEDATA& hDataPoke = hData;
  677.  
  678.             //    Get the object associated with this conversation,
  679.             //        and let it handle the request.
  680.             CDDEWrapper *pWrap = CDDEWrapper::GetConvObj(hconv);
  681.             if(pWrap != NULL)    {
  682.                 return(pWrap->PokeHandler(hszTopic, hszItem, hDataPoke));
  683.             }            
  684.             break;
  685.         }
  686.         default:
  687.             //    unknown
  688.             return(DDE_FNOTPROCESSED);
  689.         }
  690.         
  691.         //    Break handled here
  692.         return(DDE_FNOTPROCESSED);
  693.     }
  694.     else if(type & XCLASS_NOTIFICATION)    {
  695.         //    Must return NULL, as the return value is ignored
  696.         switch(type)    {
  697.         case XTYP_ADVSTOP:    {
  698.             //    We are the server
  699.             //    A client said XTYP_ADVSTOP in DdeClientTransaction
  700.             break;
  701.         }
  702.         case XTYP_CONNECT_CONFIRM:    {
  703.             //    We are the server.
  704.             //    We returned 1 to a XTYP_CONNECT transaction.
  705.             
  706.             //    This callback is mainly to inform us of the conversation
  707.             //        handle that now exists, but we will actually be
  708.             //        creating an instance of an object to handle this
  709.             //        conversation from now on.
  710.             HSZ& hszTopic = hsz1;
  711.             HSZ& hszService = hsz2;
  712.             
  713.             //    Create the object, correctly initialized so that
  714.             //        it understands the service, topic, and conversation
  715.             //        it is handling.
  716.             //    It will add itself to the conversation list.
  717.             CDDEWrapper *pObject = new CDDEWrapper(hszService, hszTopic,
  718.                 hconv);
  719.             break;
  720.         }
  721.         case XTYP_DISCONNECT:    {
  722.             //    We are either client/server
  723.             //    The partner in the conversation called DdeDisconnect
  724.             //        causing both client/server to receive this.
  725.             
  726.             //    Find out which conversation object we are dealing with.
  727.             CDDEWrapper *pWrapper = CDDEWrapper::GetConvObj(hconv);
  728.             
  729.             //    Simply delete it.
  730.             //    The object takes care of removing itself from the list.
  731.             if(pWrapper != NULL)    {
  732.                 delete pWrapper;
  733.             }
  734.             break;
  735.         }
  736.         case XTYP_ERROR:    {
  737.             //    We are either client/server
  738.             //    A serious error has occurred.
  739.             //    DDEML doesn't have any resources left to guarantee
  740.             //        good communication.
  741.             break;
  742.         }
  743.         case XTYP_REGISTER:    {
  744.             //    We are either client/server
  745.             //    A server application used DdeNameService to register
  746.             //        a new service name.
  747.             break;
  748.         }
  749.         case XTYP_UNREGISTER:    {
  750.             //    We are either client/server
  751.             //    A server applciation used DdeNameService to unregister
  752.             //        an old service name.
  753.             break;
  754.         }
  755.         case XTYP_XACT_COMPLETE:    {
  756.             //    We are the client
  757.             //    An asynchronous tranaction, sent when the client specified
  758.             //        the TIMEOUT_ASYNC flag in DdeClientTransaction has
  759.             //        concluded.
  760.             break;
  761.         }
  762.         default:
  763.             //    unknown
  764.             return(NULL);
  765.         }
  766.         return(NULL);
  767.     }
  768.  
  769.     //    Unknown class type
  770.     return(NULL);
  771. }
  772.  
  773.  
  774. //    Purpose:    Construct a DDEWrapper object
  775. //    Arguments:    hszService    The name of the service we are handling.
  776. //                hszTopic    The name of the topic we are handling.
  777. //                hConv        The handle of the conversation we are
  778. //                                handling.
  779. //    Returns:    nothing
  780. //    Comments:    Handles all created objects internally through a map.
  781. //    Revision History:
  782. //        12-30-94    created GAB
  783. CDDEWrapper::CDDEWrapper(HSZ hszService, HSZ hszTopic, HCONV hConv)
  784. {
  785.     //    Set our members passed in.
  786.     m_hszService = hszService;
  787.     m_hszTopic = hszTopic;
  788.     m_hConv = hConv;
  789.     
  790.     //    Figure out our enumerated service number.
  791.     //    We know this anyhow, we only have one service name at this
  792.     //        point.
  793.     m_iService = m_ServiceName;
  794.     
  795.     //    Figure out our enumerated topic number.
  796.     m_iTopic = EnumTopic(hszTopic);
  797.     
  798.     //    Add ourselves to the current map of conversations.
  799.     m_ConvList.SetAt((void *)hConv, this);
  800. }
  801.  
  802. //    Purpose:    Destory a CDDEWrapper object
  803. //    Arguments:    void
  804. //    Returns:    nothing
  805. //    Comments:    Removes us from the internally handled list
  806. //    Revision History:
  807. //        12-30-94    created GAB
  808. CDDEWrapper::~CDDEWrapper()
  809. {
  810.     //    Remove ourselves from the list of current conversations.
  811.     m_ConvList.RemoveKey((void *)m_hConv);
  812. }
  813.  
  814. //    Purpose:    Figure out which wrapper is associated with a conversation.
  815. //    Arguments:    hConv    The conversation to find out about.
  816. //    Returns:    CDDEWrapper *    A pointer to the CDDEWrapper that is
  817. //                                    handling the conversation, or NULL
  818. //                                    if none is present.
  819. //    Comments:    Shouldn't ever return NULL really.
  820. //    Revision History:
  821. //        12-30-94    created GAB
  822. CDDEWrapper *CDDEWrapper::GetConvObj(HCONV hConv)
  823. {
  824.     //    Query our static map of conversations for the object.
  825.     void *pWrap;
  826.     
  827.     if(m_ConvList.Lookup((void *)hConv, pWrap) == 0)    {
  828.         return(NULL);
  829.     }
  830.     return((CDDEWrapper *)pWrap);
  831. }
  832.  
  833. //    Purpose:    Return the offset of the hsz topic string in our static
  834. //                    m_hsz array
  835. //    Arguments:    hsz    The HSZ string to find in our array
  836. //    Returns:    int    The offset into the array, also correlating to
  837. //                        it's enumerated value.  If not found, the
  838. //                        returned failure value is 0.
  839. //    Comments:    Mainly coded to remove redundant lookups.  Modularity...
  840. //    Revision History:
  841. //        12-30-94    created GAB
  842. int CDDEWrapper::EnumTopic(HSZ& hsz)
  843. {
  844.     int i_retval = 0;
  845.     int i_counter;
  846.     
  847.     //    Just start looking for the HSZ string in our static array.
  848.     for(i_counter = m_TopicStart; i_counter < m_MaxHSZ; i_counter++)
  849.     {
  850.         if(m_hsz[i_counter] == hsz)    {
  851.             i_retval = i_counter;
  852.             break;
  853.         }
  854.     }
  855.     
  856.     return(i_retval);
  857. }
  858.  
  859. //    Purpose:    Scan in the arguments with a specified format.
  860. //    Arguments:    hszArgs    The string containing the arguments, in string
  861. //                            format.
  862. //                pFormat    The format (order) that the strings will be
  863. //                            scanned in.
  864. //                ...        Variable number of parameters, decided by
  865. //                            pFormat, that the values will be stored in.
  866. //    Returns:    void
  867. //    Comments:    Data should always be an exact match, no need for
  868. //                    errors, do it right the first time.
  869. //                See below, as there will be some funky heuristics
  870. //                    going on regarding some parameters and how they
  871. //                    are represented.
  872. //                Of course, only pointers should be passed in as the
  873. //                    variable number of arguments.
  874. //                ->Appropriate type casting here is a must, as we could
  875. //                    possibly overwrite, or underwrite, data.  This
  876. //                    also means that all the parameters passed in must
  877. //                    be correct!
  878. //                Never call this function with an empty format!
  879. //    Revision History:
  880. //        12-31-94    created GAB
  881. void CDDEWrapper::ScanArgs(HSZ& hszArgs, const char *pFormat, ...)
  882. {
  883.     //    Initialize variable number of argumetns.
  884.     va_list VarList;
  885.     va_start(VarList, pFormat);    
  886.     
  887.     //    Set up some variables we are going to use.
  888.     int i_ArgNum = 0;
  889.     char *pScan = (char *)pFormat;
  890.     char *pExtract;
  891.     
  892.     //    Loop through the arguments we are going to parse.
  893.     while(pScan && *pScan)    {
  894.         //    What argument are we currently looking for?
  895.         //    Extract it's value from our HSZ
  896.         i_ArgNum++;
  897.         pExtract = ExtractArg(hszArgs, i_ArgNum);
  898.     
  899.         //    Check it for currently supported types
  900.         if(0 == strncmp(pScan, "DW", 2))    {
  901.             //    Why, it's a DWORD.
  902.             //    Take the pointer to it off our argument list.
  903.             DWORD *pWord;
  904.             pWord = va_arg(VarList, DWORD *);
  905.             
  906.             //    If there is nothing to scan, use a default value.
  907.             if(pExtract == NULL)    {
  908.                 *pWord = 0x0;
  909.             }
  910.             else    {
  911.                 //    Take the value.
  912.                 *pWord = strtoul(pExtract, NULL, 0);
  913.                 //sscanf(pExtract, "%lu", pWord);
  914.             }
  915.         }
  916.         else if(0 == strncmp(pScan, "QCS", 3))    {
  917.             //    A quoted CString
  918.             CString *pCS = va_arg(VarList, CString *);
  919.             
  920.             if(pExtract == NULL)    {
  921.                 pCS->Empty();
  922.             }
  923.             else    {
  924.                 //    Fun thing about a qouted string, is that we need
  925.                 //        to compress and '\"' into '"'.
  926.                 //    Extractions took off the leading and ending quotes.
  927.                 char *pCopy = pExtract;
  928.                 while(*pCopy)    {
  929.                     if(*pCopy == '\\' && *(pCopy + 1) == '\"')    {
  930.                         pCopy++;
  931.                     }
  932.                     
  933.                     *pCS += *pCopy;
  934.                     pCopy++;
  935.                 }
  936.             }
  937.         }
  938.         else if(0 == strncmp(pScan, "CS", 2))    {
  939.             //    A CString
  940.             CString *pCS = va_arg(VarList, CString *);
  941.  
  942.             if(pExtract == NULL)    {
  943.                 pCS->Empty();
  944.             }
  945.             else    {
  946.                 //    Just copy.
  947.                 *pCS = pExtract;
  948.             }
  949.         }
  950.         else if(0 == strncmp(pScan, "BL", 2))    {
  951.             //    A boolean
  952.             TwoByteBool *pBool = va_arg(VarList, TwoByteBool *);
  953.             
  954.             if(pExtract == NULL)    {
  955.                 *pBool = FALSE;
  956.             }
  957.             else    {
  958.                 //    Compare for a TRUE or a FALSE
  959.                 if(0 == stricmp(pExtract, "TRUE"))    {
  960.                     *pBool = TRUE;
  961.                 }
  962.                 else    {
  963.                     *pBool = FALSE;
  964.                 }
  965.             }
  966.         }
  967.         else    {
  968.             //    Doh!, not supported, just break out of the while loop.
  969.             ASSERT(0);
  970.             break;
  971.         }
  972.         
  973.         //    Go on to the next argument in our format string.
  974.         pScan = SkipToNextFormat(pScan);
  975.         
  976.         //    Free the memory that was used during extraction.
  977.         if(pExtract != NULL)    {
  978.             delete pExtract;
  979.         }
  980.     }
  981.     
  982.     //    Done with variable number of arguments
  983.     va_end(VarList);
  984. }
  985.  
  986.  
  987. //    Purpose:    Scan in the arguments with a specified format.
  988. //    Arguments:    hArgs    The string containing the arguments, in string
  989. //                            format (must convert to HSZ first).
  990. //                pFormat    The format (order) that the strings will be
  991. //                            scanned in.
  992. //                ...        Variable number of parameters, decided by
  993. //                            pFormat, that the values will be stored in.
  994. //    Returns:    void
  995. //    Comments:    Data should always be an exact match, no need for
  996. //                    errors, do it right the first time.
  997. //                See below, as there will be some funky heuristics
  998. //                    going on regarding some parameters and how they
  999. //                    are represented.
  1000. //                Of course, only pointers should be passed in as the
  1001. //                    variable number of arguments.
  1002. //                ->Appropriate type casting here is a must, as we could
  1003. //                    possibly overwrite, or underwrite, data.  This
  1004. //                    also means that all the parameters passed in must
  1005. //                    be correct!
  1006. //                Never call this function with an empty format!
  1007. //    Revision History:
  1008. //        01-05-95    created GAB
  1009. void CDDEWrapper::ScanDataArgs(HDDEDATA& hArgs, const char *pFormat, ...)
  1010. {
  1011.     char *pDataArgs = (char *)DdeAccessData(hArgs, NULL);
  1012.     
  1013.     //    Initialize variable number of argumetns.
  1014.     va_list VarList;
  1015.     va_start(VarList, pFormat);    
  1016.     
  1017.     //    With DATA args, it will be possible that with only one argument,
  1018.     //        that we are receiving raw data.
  1019.     //    Use this method.
  1020.     if(strchr(pFormat, ',') == NULL)    {
  1021.         //    Only one argument.
  1022.         if(strcmp(pFormat, "DW") == 0)    {
  1023.             DWORD *pWord;
  1024.             pWord = va_arg(VarList, DWORD *);
  1025.             *pWord = *(DWORD *)pDataArgs;
  1026.             DdeUnaccessData(hArgs);
  1027.             va_end(VarList);
  1028.             return;
  1029.         }
  1030.         else if(strcmp(pFormat, "BL") == 0)    {
  1031.             TwoByteBool *pBool;
  1032.             pBool = va_arg(VarList, TwoByteBool *);
  1033.             *pBool = *(TwoByteBool *)pDataArgs;
  1034.             DdeUnaccessData(hArgs);
  1035.             va_end(VarList);
  1036.             return;
  1037.         }
  1038.     }
  1039.  
  1040.     //    Convert our hArgs to HSZ format.
  1041.     HSZ hszArgs = DdeCreateStringHandle(m_dwidInst, pDataArgs,
  1042.         CP_WINANSI);
  1043.     DdeUnaccessData(hArgs);    
  1044.  
  1045.     //    Set up some variables we are going to use.
  1046.     int i_ArgNum = 0;
  1047.     char *pScan = (char *)pFormat;
  1048.     char *pExtract;
  1049.     
  1050.     //    Loop through the arguments we are going to parse.
  1051.     while(pScan && *pScan)    {
  1052.         //    What argument are we currently looking for?
  1053.         //    Extract it's value from our HSZ
  1054.         i_ArgNum++;
  1055.         pExtract = ExtractArg(hszArgs, i_ArgNum);
  1056.     
  1057.         //    Check it for currently supported types
  1058.         if(0 == strncmp(pScan, "DW", 2))    {
  1059.             //    Why, it's a DWORD.
  1060.             //    Take the pointer to it off our argument list.
  1061.             DWORD *pWord;
  1062.             pWord = va_arg(VarList, DWORD *);
  1063.             
  1064.             //    If there is nothing to scan, use a default value.
  1065.             if(pExtract == NULL)    {
  1066.                 *pWord = 0x0;
  1067.             }
  1068.             else    {
  1069.                 //    Take the value.
  1070.                 *pWord = strtoul(pExtract, NULL, 0);
  1071.                 //sscanf(pExtract, "%lu", pWord);
  1072.             }
  1073.         }
  1074.         else if(0 == strncmp(pScan, "QCS", 3))    {
  1075.             //    A quoted CString
  1076.             CString *pCS = va_arg(VarList, CString *);
  1077.             
  1078.             if(pExtract == NULL)    {
  1079.                 pCS->Empty();
  1080.             }
  1081.             else    {
  1082.                 //    Fun thing about a qouted string, is that we need
  1083.                 //        to compress and '\"' into '"'.
  1084.                 //    Extractions took off the leading and ending quotes.
  1085.                 char *pCopy = pExtract;
  1086.                 while(*pCopy)    {
  1087.                     if(*pCopy == '\\' && *(pCopy + 1) == '\"')    {
  1088.                         pCopy++;
  1089.                     }
  1090.                     
  1091.                     *pCS += *pCopy;
  1092.                     pCopy++;
  1093.                 }
  1094.             }
  1095.         }
  1096.         else if(0 == strncmp(pScan, "CS", 2))    {
  1097.             //    A CString
  1098.             CString *pCS = va_arg(VarList, CString *);
  1099.  
  1100.             if(pExtract == NULL)    {
  1101.                 pCS->Empty();
  1102.             }
  1103.             else    {
  1104.                 //    Just copy.
  1105.                 *pCS = pExtract;
  1106.             }
  1107.         }
  1108.         else if(0 == strncmp(pScan, "BL", 2))    {
  1109.             //    A boolean
  1110.             TwoByteBool *pBool = va_arg(VarList, TwoByteBool *);
  1111.             
  1112.             if(pExtract == NULL)    {
  1113.                 *pBool = FALSE;
  1114.             }
  1115.             else    {
  1116.                 //    Compare for a TRUE or a FALSE
  1117.                 if(0 == stricmp(pExtract, "TRUE"))    {
  1118.                     *pBool = TRUE;
  1119.                 }
  1120.                 else    {
  1121.                     *pBool = FALSE;
  1122.                 }
  1123.             }
  1124.         }
  1125.         else    {
  1126.             //    Doh!, not supported, just break out of the while loop.
  1127.             ASSERT(0);
  1128.             break;
  1129.         }
  1130.         
  1131.         //    Go on to the next argument in our format string.
  1132.         pScan = SkipToNextFormat(pScan);
  1133.         
  1134.         //    Free the memory that was used during extraction.
  1135.         if(pExtract != NULL)    {
  1136.             delete pExtract;
  1137.         }
  1138.     }
  1139.     
  1140.     //    Done with variable number of arguments
  1141.     va_end(VarList);
  1142.     
  1143.     //    Free off our created HSZ string.
  1144.     DdeFreeStringHandle(m_dwidInst, hszArgs);
  1145. }
  1146.  
  1147.  
  1148. //    Purpose:    Create an argument list, as HDDEDATA
  1149. //    Arguments:    pFormat    The format of the argument list
  1150. //                ...        The viarables correlating to the format
  1151. //    Returns:    HSZ    The argument list (a string, really)
  1152. //    Comments:    HSZ is the return type because this will mainly
  1153. //                    be used to create return values back to the
  1154. //                    server.
  1155. //                Do not screw up and pass in the wrong arguments, or
  1156. //                    a wrong format.
  1157. //                Only pointers are accepted as arguments, because if
  1158. //                    a NULL is passed in, then it will be considered
  1159. //                    an optional non-existant argument.  If this is
  1160. //                    not the case, then pass in a valid pointer,
  1161. //                    pointing to a valid argument.
  1162. //    Revision History:
  1163. //        01-05-95    created GAB
  1164. HSZ CDDEWrapper::MakeItemArgs(const char *pFormat, ...)
  1165. {
  1166.     //    Safety dance
  1167.     char *pTraverse = (char *)pFormat;    
  1168.     if(pTraverse == NULL || *pTraverse == '\0')    {
  1169.         return(NULL);
  1170.     }
  1171.  
  1172.     //    Set up for variable number of arguments.
  1173.     va_list VarList;
  1174.     va_start(VarList, pFormat);
  1175.  
  1176.     //    Real simple.
  1177.     //    Go through our format, and append the string representation
  1178.     //        to our developing return value.
  1179.     char caNumpad[64];
  1180.     CString csBuffer;
  1181.     CString csRetval;
  1182.     
  1183.     while(*pTraverse)    {
  1184.         //    Erase temp data from our last pass.
  1185.         caNumpad[0] = '\0';
  1186.         csBuffer.Empty();
  1187.     
  1188.         //    Compare our current format to the known formats
  1189.         if(0 == strncmp(pTraverse, "DW", 2))    {
  1190.             //    A DWORD.
  1191.             DWORD *pWord = va_arg(VarList, DWORD *);
  1192.             
  1193.             if(pWord != NULL)    {            
  1194.                 sprintf(caNumpad, "%lu", *pWord);
  1195.                 csRetval += caNumpad;
  1196.             }
  1197.         }
  1198.         else if(0 == strncmp(pTraverse, "CS", 2))    {
  1199.             //    A CString, not quoted
  1200.             CString *pCS = va_arg(VarList, CString *);
  1201.             
  1202.             if(pCS != NULL)    {
  1203.                 csRetval += *pCS;
  1204.             }
  1205.         }
  1206.         else if(0 == strncmp(pTraverse, "QCS", 3))    {
  1207.             //    A quoted CString
  1208.             CString *pQCS = va_arg(VarList, CString *);
  1209.             
  1210.             if(pQCS != NULL)    {
  1211.                 csRetval += '\"';
  1212.                 
  1213.                 //    Need to escape any '"' to '\"', literally.
  1214.                 char *pConvert = (char *)(const char *)*pQCS;
  1215.                 while(*pConvert != '\0')    {
  1216.                     if(*pConvert == '\"')    {
  1217.                         csRetval += '\\';
  1218.                     }
  1219.                     csRetval += *pConvert;
  1220.                     pConvert++;
  1221.                 }
  1222.                 csRetval += '\"';
  1223.             }
  1224.         }
  1225.         else if(0 == strncmp(pTraverse, "BL", 2))    {
  1226.             //    A boolean
  1227.             TwoByteBool *pBool = va_arg(VarList, TwoByteBool *);
  1228.             
  1229.             if(pBool != NULL)    {
  1230.                 if(*pBool != FALSE)    {
  1231.                     csRetval += "TRUE";
  1232.                 }
  1233.                 else    {
  1234.                     csRetval += "FALSE";
  1235.                 }
  1236.             }
  1237.         }
  1238.         else    {
  1239.             //    Unhandled format, just get out of loop.
  1240.             ASSERT(0);
  1241.             break;
  1242.         }
  1243.         
  1244.         //    Go on to next type
  1245.         pTraverse = SkipToNextFormat(pTraverse);
  1246.         
  1247.         //    See if we need a comma
  1248.         if(*pTraverse != '\0')    {
  1249.             csRetval += ',';
  1250.         }
  1251.     }
  1252.  
  1253.     //    Done with varargs.
  1254.     va_end(VarList);
  1255.     
  1256.     //    Make sure we're atleast returning something.
  1257.     if(csRetval.IsEmpty())    {
  1258.         return(NULL);
  1259.     }
  1260.  
  1261.     //    Return our resultant HSZ, created from our string, and
  1262.     //        the DDEML will own this once we return it.
  1263.     HSZ Final = DdeCreateStringHandle(m_dwidInst, (char *)
  1264.         (const char *)csRetval, CP_WINANSI);
  1265.     return(Final);
  1266. }
  1267.  
  1268.  
  1269. //    Purpose:    Create an argument list, as HDDEDATA
  1270. //    Arguments:    pFormat    The format of the argument list
  1271. //                ...        The viarables correlating to the format
  1272. //    Returns:    HDDEDATA    The argument list (a string, really)
  1273. //    Comments:    HDDEDATA is the return type because this will mainly
  1274. //                    be used to create return values back to the
  1275. //                    client.
  1276. //                Do not screw up and pass in the wrong arguments, or
  1277. //                    a wrong format.
  1278. //                Only pointers are accepted as arguments, because if
  1279. //                    a NULL is passed in, then it will be considered
  1280. //                    an optional non-existant argument.  If this is
  1281. //                    not the case, then pass in a valid pointer,
  1282. //                    pointing to a valid argument.
  1283. //    Revision History:
  1284. //        01-02-95    created GAB
  1285. HDDEDATA CDDEWrapper::MakeArgs(const char *pFormat, ...)
  1286. {
  1287.     //    Safety dance
  1288.     char *pTraverse = (char *)pFormat;    
  1289.     if(pTraverse == NULL || *pTraverse == '\0')    {
  1290.         return(NULL);
  1291.     }
  1292.  
  1293.     //    Set up for variable number of arguments.
  1294.     va_list VarList;
  1295.     va_start(VarList, pFormat);
  1296.  
  1297.     //    Real simple.
  1298.     //    Go through our format, and append the string representation
  1299.     //        to our developing return value.
  1300.     char caNumpad[64];
  1301.     CString csBuffer;
  1302.     CString csRetval;
  1303.     
  1304.     while(*pTraverse)    {
  1305.         //    Erase temp data from our last pass.
  1306.         caNumpad[0] = '\0';
  1307.         csBuffer.Empty();
  1308.     
  1309.         //    Compare our current format to the known formats
  1310.         if(0 == strncmp(pTraverse, "DW", 2))    {
  1311.             //    A DWORD.
  1312.             DWORD *pWord = va_arg(VarList, DWORD *);
  1313.             
  1314.             if(pWord != NULL)    {            
  1315.                 sprintf(caNumpad, "%lu", *pWord);
  1316.                 csRetval += caNumpad;
  1317.             }
  1318.         }
  1319.         else if(0 == strncmp(pTraverse, "CS", 2))    {
  1320.             //    A CString, not quoted
  1321.             CString *pCS = va_arg(VarList, CString *);
  1322.             
  1323.             if(pCS != NULL)    {
  1324.                 csRetval += *pCS;
  1325.             }
  1326.         }
  1327.         else if(0 == strncmp(pTraverse, "QCS", 3))    {
  1328.             //    A quoted CString
  1329.             CString *pQCS = va_arg(VarList, CString *);
  1330.             
  1331.             if(pQCS != NULL)    {
  1332.                 csRetval += '\"';
  1333.                 
  1334.                 //    Need to escape any '"' to '\"', literally.
  1335.                 char *pConvert = (char *)(const char *)*pQCS;
  1336.                 while(*pConvert != '\0')    {
  1337.                     if(*pConvert == '\"')    {
  1338.                         csRetval += '\\';
  1339.                     }
  1340.                     csRetval += *pConvert;
  1341.                     pConvert++;
  1342.                 }
  1343.                 csRetval += '\"';
  1344.             }
  1345.         }
  1346.         else if(0 == strncmp(pTraverse, "BL", 2))    {
  1347.             //    A boolean
  1348.             TwoByteBool *pBool = va_arg(VarList, TwoByteBool *);
  1349.             
  1350.             if(pBool != NULL)    {
  1351.                 if(*pBool != FALSE)    {
  1352.                     csRetval += "TRUE";
  1353.                 }
  1354.                 else    {
  1355.                     csRetval += "FALSE";
  1356.                 }
  1357.             }
  1358.         }
  1359.         else    {
  1360.             //    Unhandled format, just get out of loop.
  1361.             ASSERT(0);
  1362.             break;
  1363.         }
  1364.         
  1365.         //    Go on to next type
  1366.         pTraverse = SkipToNextFormat(pTraverse);
  1367.         
  1368.         //    See if we need a comma
  1369.         if(*pTraverse != '\0')    {
  1370.             csRetval += ',';
  1371.         }
  1372.     }
  1373.  
  1374.     //    Done with varargs.
  1375.     va_end(VarList);
  1376.     
  1377.     //    Make sure we're atleast returning something.
  1378.     if(csRetval.IsEmpty())    {
  1379.         return(NULL);
  1380.     }
  1381.  
  1382.     //    Return our resultant HDDEDATA, created from our string, be
  1383.     //        sure to copy over the terminating NULL, no offset, no
  1384.     //        item association, this is text, and the DDEML will own
  1385.     //        this once we return it.
  1386.     HDDEDATA Final;
  1387.     TRACE("Returning HDDEDATA:  %s\n", (const char *)csRetval);
  1388.     Final = DdeCreateDataHandle(m_dwidInst,
  1389. #ifdef XP_WIN16
  1390.         (void *)(const char *)csRetval, 
  1391. #else
  1392.         (LPBYTE)(const char *)csRetval,
  1393. #endif     
  1394.          csRetval.GetLength() + 1, 0, m_hsz[m_ServiceName],
  1395.         CF_TEXT, 0);
  1396.  
  1397.     //    Okay, we're not supposed to know this, but the minimum data size of this
  1398.     //        object is in increments of 32.  So we're going to do a little proactive
  1399.     //        writing to it if need be.
  1400.     //    THIS IS A HACK.
  1401.     //    I just recently figured out that we need to return actual raw data to the
  1402.     //        calling application, so handle it here for now.
  1403.     //    This only happens if we have only one argument, check for commas.
  1404.     //    Forget the speed considerations, anyone using DDE is insane anyhow.
  1405.     if(strchr(pFormat, ',') == NULL)    {
  1406.         if(strcmp(pFormat, "BL") == 0)    {
  1407.             //    Scan in the value.
  1408.             TwoByteBool bData = FALSE;
  1409.             if(csRetval == "TRUE")    {
  1410.                 bData = TRUE;
  1411.             }
  1412.             DdeFreeDataHandle(Final);
  1413.             
  1414.             Final = DdeCreateDataHandle(m_dwidInst, (unsigned char *) &bData, sizeof(TwoByteBool), 0, m_hsz[m_ServiceName], CF_TEXT, 0);            
  1415.         }
  1416.         else if(strcmp(pFormat, "DW") == 0)    {
  1417.             //    Scan in the value.
  1418.             DWORD dwData;
  1419.             dwData = strtoul(csRetval, NULL, 0);
  1420.             //sscanf(csRetval, "%lu", &dwData);
  1421.             DdeFreeDataHandle(Final);
  1422.             
  1423.             //    Reset the value in a binary way.
  1424.             Final = DdeCreateDataHandle(m_dwidInst, (unsigned char *) &dwData, sizeof(DWORD), 0, m_hsz[m_ServiceName], CF_TEXT, 0);            
  1425.         }
  1426.     }
  1427.  
  1428.     return(Final);
  1429. }
  1430.  
  1431.  
  1432. //    Purpose:    Move the pointer passed in to the next argument
  1433. //    Arguments:    pFormat    the format string wanting to be incremented
  1434. //    Returns:    char *    The next format.
  1435. //    Comments:    
  1436. //    Revision History:
  1437. //        01-01-95    created GAB
  1438. char *CDDEWrapper::SkipToNextFormat(char *pFormat)
  1439. {
  1440.     //    Safety dance
  1441.     if(pFormat == NULL || *pFormat == '\0')    {
  1442.         return(pFormat);
  1443.     }
  1444.  
  1445.     //    The next format is directly after a ','
  1446.     while(*pFormat != ',' && *pFormat != '\0')    {
  1447.         pFormat++;
  1448.     }
  1449.     if(*pFormat == ',')    {
  1450.         pFormat++;
  1451.     }
  1452.     
  1453.     return(pFormat);
  1454. }
  1455.  
  1456.  
  1457. //    Purpose:    Return an allocated char array conatining the contents
  1458. //                    of a specified argument.
  1459. //    Arguments:    hszArgs    The HSZ of all arguments
  1460. //                iArg    Integer specifying which argument to extract.
  1461. //    Returns:    char *    The allocated array containing the contents of
  1462. //                            argument iArg, or NULL if there is no such
  1463. //                            argument or if the argument was empty.
  1464. //    Comments:    Quoted strings are counted as only one argument, though
  1465. //                    the quotes are not copied into the return string.
  1466. //    Revision History:
  1467. //        01-01-95    created GAB
  1468. char *CDDEWrapper::ExtractArg(HSZ& hszArgs, int iArg)
  1469. {
  1470.     //    Allocate some memory to retrieve infomation from out HSZ.
  1471.     DWORD dwLength = DdeQueryString(m_dwidInst, hszArgs, NULL, 0L,
  1472.         CP_WINANSI) + 1;
  1473.     char *pTraverse = new char[dwLength];
  1474.     char *pRemove = pTraverse;
  1475.     if(pTraverse == NULL)    {
  1476.         return(NULL);
  1477.     }    
  1478.     DdeQueryString(m_dwidInst, hszArgs, pTraverse, dwLength, CP_WINANSI);
  1479.     
  1480.     //    safety dance
  1481.     if(*pTraverse == '\0' || iArg < 1)    {
  1482.         delete(pRemove);
  1483.         return(NULL);
  1484.     }
  1485.     
  1486.     //    Need to decrement the argument we're looking for, as the very
  1487.     //        first argument has no ',' at the beginning.
  1488.     iArg--;
  1489.     
  1490.     //    Search through the arguments, seperated by ','.
  1491.     while(iArg)    {
  1492.         //    Special handling of quoted strings.
  1493.         if(*pTraverse == '\"')    {
  1494.             //    Find the ending quote.
  1495.             while(*pTraverse != '\0')    {
  1496.                 pTraverse++;
  1497.                 if(*pTraverse == '\"')    {
  1498.                     pTraverse++;    //    One beyond, please
  1499.                     break;
  1500.                 }
  1501.                 else if(*pTraverse == '\\')    {
  1502.                     //    Attempting to embed a quoted, perhaps....
  1503.                     if(*(pTraverse + 1) == '\"')    {
  1504.                         pTraverse++;
  1505.                     }
  1506.                 }
  1507.             }
  1508.         }
  1509.         //    Find the next comma
  1510.         while(*pTraverse != '\0' && *pTraverse != ',')    {
  1511.             pTraverse++;
  1512.         }
  1513.  
  1514.         //    Go beyond a comma
  1515.         if(*pTraverse == ',')    {
  1516.             pTraverse++;
  1517.         }
  1518.         
  1519.         //    Okay, we're at the next argument, decrement our argument
  1520.         //        count.
  1521.         iArg--;
  1522.         
  1523.         //    By chance, if we're at the end of the string, break out of
  1524.         //        the loop.
  1525.         if(*pTraverse == '\0')    {
  1526.             break;
  1527.         }
  1528.     }
  1529.     
  1530.     //    Handle empty arguments here.
  1531.     if(*pTraverse == ',' || *pTraverse == '\0')    {
  1532.         delete(pRemove);
  1533.         return(NULL);
  1534.     }
  1535.     
  1536.     //    Count chars up to next comma, plus 1 (end of string stuff)
  1537.     int iLength = 1;
  1538.     char *pCounter = pTraverse;
  1539.     TwoByteBool bQuoted = FALSE;
  1540.     
  1541.     //    specially handle quoted strings
  1542.     if(*pCounter == '\"')    {
  1543.         //    Go past initial quote.
  1544.         pCounter++;
  1545.         bQuoted = TRUE;
  1546.  
  1547.         //    Find the ending quote.
  1548.         while(*pCounter != '\0')    {
  1549.             if(*pCounter == '\"')    {
  1550.                 break;
  1551.             }
  1552.             else if(*pCounter == '\\')    {
  1553.                 //    Attempting to embed a quoted, perhaps....
  1554.                 if(*(pCounter + 1) == '\"')    {
  1555.                     pCounter++;
  1556.                     iLength++;
  1557.                 }
  1558.             }
  1559.             
  1560.             pCounter++;
  1561.             iLength++;
  1562.         }
  1563.     }
  1564.     //    Go to next comma
  1565.     while(*pCounter != '\0' && *pCounter != ',')    {
  1566.         iLength++;
  1567.         pCounter++;
  1568.     }
  1569.     
  1570.     //    Subtrace one to ignore ending quote if we were quoted....
  1571.     if(bQuoted == TRUE)    {
  1572.         iLength--;
  1573.     }
  1574.     
  1575.     //    Argument's of length 1 are of no interest.
  1576.     if(iLength == 1)    {
  1577.         delete(pRemove);
  1578.         return(NULL);
  1579.     }
  1580.     
  1581.     //    Okay, allocate some memory for the string, we'll copy it over.
  1582.     char *pRetVal = new char[iLength];
  1583.     
  1584.     if(*pTraverse == '\"')    {
  1585.         pTraverse++;
  1586.     }    
  1587.     strncpy(pRetVal, pTraverse, iLength - 1);
  1588.     pRetVal[iLength - 1] = '\0';
  1589.     
  1590.     delete(pRemove);
  1591.  
  1592.     //    If pRetval begins with a caret, then detect if this is a file.
  1593.     //    We will substitue in file data if this is the case.
  1594.     if(pRetVal && *pRetVal == '^')    {
  1595.         char *pFilename = pRetVal + 1;
  1596.  
  1597.         if(*pFilename)    {
  1598.             CFileStatus cfs;
  1599.             BOOL bValid = CFile::GetStatus(pFilename, cfs);
  1600.             if(bValid)    {
  1601.                 //    We have a file.
  1602.                 //    Allocate the number of bytes + 1 (for null termination).
  1603.                 char *pFileData = NULL;
  1604.                 TRY    {
  1605.                     pFileData = new char[cfs.m_size + 1];
  1606.                 }
  1607.                 CATCH(CException, e)    {
  1608.                     pFileData = NULL;
  1609.                 }
  1610.                 END_CATCH
  1611.  
  1612.                 if(pFileData != NULL)    {
  1613.                     TRY    {
  1614.                         //  Leave as shared readable for DDE apps looking into the file early.
  1615.                         CFile cf(pFilename, CFile::modeRead | CFile::shareDenyWrite);
  1616.  
  1617.                         //    Read in the data.
  1618.                         cf.Read(pFileData, CASTSIZE_T(cfs.m_size));
  1619.  
  1620.                         //    Null terminate.
  1621.                         pFileData[cfs.m_size] = '\0';
  1622.                     }
  1623.                     CATCH(CException, e)    {
  1624.                         //    Opening or reading of the file failed.
  1625.                         delete pFileData;
  1626.                         pFileData = NULL;
  1627.                     }
  1628.                     END_CATCH
  1629.                 }
  1630.  
  1631.                 //    If we have file data, swap with the return value.
  1632.                 if(pFileData)    {
  1633.                     delete(pRetVal);
  1634.                     pRetVal = pFileData;
  1635.                 }
  1636.             }
  1637.         }
  1638.     }
  1639.  
  1640.     return(pRetVal);
  1641. }
  1642.  
  1643.  
  1644. //    Purpose:    Handle XTYP_REQUEST calls for this conversation.
  1645. //    Arguments:    hszTopic    The topic-name of the conversation
  1646. //                hszItem        The item-name under this topic
  1647. //    Returns:    HDDEDATA    Mainly, we will just pass back the return
  1648. //                                values of functions that we call
  1649. //                                depending upon our topic name.  Look
  1650. //                                there.
  1651. //    Comments:    Second level muliplexor, for topics under an already
  1652. //                    multiplexed conversation.
  1653. //                Server only code, here.
  1654. //                I would have used function tables to index into the
  1655. //                    appropriate function on topic type, but the
  1656. //                    topics are not neccessarily grouped together in
  1657. //                    the same range as thier topic number.
  1658. //    Revision History:
  1659. //        12-30-94    created GAB
  1660. HDDEDATA CDDEWrapper::RequestHandler(HSZ& hszTopic, HSZ& hszItem)
  1661. {
  1662.     //    Ensure this conversation is about the topic we think it is.
  1663.     if(m_hsz[m_iTopic] != hszTopic)    {
  1664.         return(NULL);
  1665.     }
  1666.  
  1667.     TRACE("REQUEST topic %d\n", m_iTopic);
  1668.     
  1669.     //    Switch on all possible request topics, and pass params on down.
  1670.     switch(m_iTopic)    {
  1671.     case m_OpenURL:
  1672.         return(OpenURL(hszItem));
  1673.     case m_ShowFile:
  1674.         return(ShowFile(hszItem));
  1675.     case m_Activate:
  1676.         return(Activate(hszItem));
  1677.     case m_ListWindows:
  1678.         return(ListWindows(hszItem));
  1679.     case m_GetWindowInfo:
  1680.         return(GetWindowInfo(hszItem));
  1681.     case m_ParseAnchor:
  1682.         return(ParseAnchor(hszItem));
  1683.     case m_RegisterProtocol:
  1684.         return(RegisterProtocol(hszItem));
  1685.     case m_UnRegisterProtocol:
  1686.         return(UnRegisterProtocol(hszItem));
  1687.     case m_RegisterViewer:
  1688.         return(RegisterViewer(hszItem));
  1689.     case m_UnRegisterViewer:
  1690.         return(UnRegisterViewer(hszItem));
  1691.     case m_RegisterWindowChange:
  1692.         return(RegisterWindowChange(hszItem));
  1693.     case m_UnRegisterWindowChange:
  1694.         return(UnRegisterWindowChange(hszItem));
  1695.     case m_BeginProgress:
  1696.         return(BeginProgress(hszItem));
  1697.     case m_MakingProgress:
  1698.         return(MakingProgress(hszItem));
  1699.     case m_EndProgress:
  1700.         return(EndProgress(hszItem));
  1701.     case m_Version:
  1702.         return(Version(hszItem));
  1703.     case m_QueryURLFile:
  1704.         return(QueryURLFile(hszItem));
  1705.     case m_ListFrameChildren:
  1706.         return(ListFrameChildren(hszItem));
  1707.     case m_GetFrameParent:
  1708.         return(GetFrameParent(hszItem));
  1709.     // Start of the Netscape 5.0 topics (Dave Hyatt - 8/13/97)
  1710.     case m_RegisterStatusBarChange: 
  1711.         return(RegisterStatusBarChange(hszItem));
  1712.     case m_UnRegisterStatusBarChange:
  1713.         return(UnRegisterStatusBarChange(hszItem)); 
  1714.     case m_NavigateBack:
  1715.         return(NavigateBack(hszItem));    
  1716.     case m_NavigateForward:
  1717.         return (NavigateForward(hszItem));    
  1718.     case m_Stop:
  1719.         return (Stop(hszItem));
  1720.     case m_Reload:
  1721.         return (Reload(hszItem));
  1722.     case m_UserAgent:
  1723.         return (UserAgent(hszItem));
  1724.     case m_Cache_ClearCache:
  1725.         return (ClearCache(hszItem));
  1726.     case m_Cache_Filename:
  1727.         return (CacheFilename(hszItem));
  1728.     case m_Cache_InCache:
  1729.         return (InCache(hszItem));
  1730.     case m_Cache_RemoveURL:
  1731.         return (CacheRemoveURL(hszItem));
  1732.     case m_Cache_AddURL:
  1733.         return (CacheAddURL(hszItem));
  1734.     case m_History_ClearHistory:
  1735.         return (ClearHistory(hszItem));
  1736.     case m_History_AddURL:
  1737.         return (HistoryAddURL(hszItem));
  1738.     case m_History_RemoveURL:
  1739.         return (HistoryRemoveURL(hszItem));
  1740.     case m_History_InHistory:
  1741.         return (InHistory(hszItem));
  1742.     case m_History_NumEntries:
  1743.         return (HistoryNumEntries(hszItem));
  1744.     case m_History_GetEntry:
  1745.         return (HistoryGetEntry(hszItem));
  1746.     case m_GetWindowID:
  1747.         return (GetWindowID(hszItem));
  1748.     case m_SupportsMimeType:
  1749.         return (SupportsMimeType(hszItem));
  1750.     case m_ExecuteJavaScript:
  1751.         return (ExecuteJavaScript(hszItem));
  1752.     case m_PrintWindow:
  1753.         return (PrintWindow(hszItem));
  1754.     case m_PrintURL:
  1755.         return (PrintURL(hszItem));
  1756.  
  1757.     }
  1758.  
  1759.     //    Default, should never reach.
  1760.     return(NULL);
  1761. }
  1762.  
  1763. //    Purpose:    Handle XTYP_POKE calls for this conversation.
  1764. //    Arguments:    hszTopic    The topic-name of the conversation
  1765. //                hszItem        The item-name under this topic
  1766. //                hData        Identifies data the client is sending to
  1767. //                                this server conversation.
  1768. //    Returns:    HDDEDATA    Mainly, we will just pass back the return
  1769. //                                values of functions that we call
  1770. //                                depending upon our topic name.  Look
  1771. //                                there.
  1772. //    Comments:    Second level muliplexor, for topics under an already
  1773. //                    multiplexed conversation.
  1774. //                Server only code, here.
  1775. //                I would have used function tables to index into the
  1776. //                    appropriate function on topic type, but the
  1777. //                    topics are not neccessarily grouped together in
  1778. //                    the same range as thier topic number.
  1779. //    Revision History:
  1780. //        12-30-94    created GAB
  1781. HDDEDATA CDDEWrapper::PokeHandler(HSZ& hszTopic, HSZ& hszItem,
  1782.     HDDEDATA& hData)
  1783. {
  1784.     //    Ensure this conversation is about the topic we think it is.
  1785.     if(m_hsz[m_iTopic] != hszTopic)    {
  1786.         return(NULL);
  1787.     }
  1788.     
  1789.     TRACE("POKE topic %d\n", m_iTopic);
  1790.     
  1791.     //    Switch on all possible poke topics, and pass params on down.
  1792.     switch(m_iTopic)    {
  1793.     case m_Exit:
  1794.         return(Exit(hszItem, hData));
  1795.     case m_SetProgressRange:
  1796.         return(SetProgressRange(hszItem, hData));
  1797.     case m_RegisterURLEcho:
  1798.         return(RegisterURLEcho(hszItem, hData));
  1799.     case m_UnRegisterURLEcho:
  1800.         return(UnRegisterURLEcho(hszItem, hData));
  1801.     case m_WindowChange:
  1802.         return(WindowChange(hszItem, hData));
  1803.     case m_CancelProgress:
  1804.         return(CancelProgress(hszItem, hData));
  1805.     }
  1806.  
  1807.     //    Default, should never reach.
  1808.     return((HDDEDATA)DDE_FNOTPROCESSED);
  1809. }
  1810.  
  1811. //    Purpose:    Bring Netscape to the top of all other applications,
  1812. //                    and show the windows specified.  This will restore
  1813. //                    minimized Netscape icons.
  1814. //    Arguments:    hszItem    A string representing our real parameters.
  1815. //    Returns:    HDDEDATA    Returns the ID of the window that was
  1816. //                                activated and has focus.
  1817. //                            NULL on failure.
  1818. //    Comments:    Parameters within hszItem are
  1819. //                    WindowID,Flags
  1820. //                WindowID is the handle of the window to restore, or bring
  1821. //                    to the top.  -1 means don't care, I suppose.
  1822. //                Flags is currently reserved for later use, so just
  1823. //                    ignore it.
  1824. //    Revision History:
  1825. //        12-31-94    created GAB
  1826. HDDEDATA CDDEWrapper::Activate(HSZ& hszItem)
  1827. {
  1828.     DWORD ReturnID = 0L;
  1829.  
  1830.     //    Obtain our arguments.
  1831.     DWORD WindowID;
  1832.     DWORD Flags;
  1833.     ScanArgs(hszItem, "DW,DW", &WindowID, &Flags);
  1834.     
  1835.     //    If we have a specified WindowID, attempt to activate it.
  1836.     if(WindowID != 0xFFFFFFFF && WindowID != 0x0)    {
  1837.         //    See if it's a valid Window ID
  1838.         CFrameWnd *pWnd = FEU_FindFrameByID(WindowID, MWContextBrowser);
  1839.         if(pWnd != NULL)    {
  1840.             if(pWnd->IsIconic())    {
  1841.                 pWnd->ShowWindow(SW_RESTORE);
  1842.             }
  1843.             ::SetWindowPos(pWnd->GetSafeHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  1844. #ifdef XP_WIN32
  1845.             pWnd->SetForegroundWindow();
  1846. #endif
  1847.             
  1848.             //    Success, set the return value.
  1849.             ReturnID = WindowID;
  1850.         }
  1851.     }
  1852.     else if(WindowID != 0x0)    {
  1853.         //    If we have no windows, then it's time to create a new one.
  1854.         //    This is a valid possibility, since we could be doing some
  1855.         //        type of background work through OLE.
  1856.         if(XP_ContextCount(MWContextBrowser, TRUE) == 0)    {
  1857.             CFE_CreateNewDocWindow(NULL, NULL);
  1858.         }
  1859.     
  1860.         //    We're just supposed to bring ourselves to the front.
  1861.         //    Return the WindowID of the window up front.
  1862.         //    Since if there wasn't an active window, then we created one,
  1863.         //        the value returned by the below should never be NULL.
  1864.         CFrameWnd *pWnd = FEU_GetLastActiveFrame(MWContextBrowser);
  1865.         if(pWnd != NULL)    {
  1866.             if(pWnd->IsIconic())    {
  1867.                 pWnd->ShowWindow(SW_RESTORE);
  1868.             }
  1869.             ::SetWindowPos(pWnd->GetSafeHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  1870. #ifdef XP_WIN32
  1871.             pWnd->SetForegroundWindow();
  1872. #endif
  1873.  
  1874.             //    Success, set the return value.
  1875.             CFrameGlue *pGlue = CFrameGlue::GetFrameGlue(pWnd);
  1876.             if(pGlue != NULL)    {
  1877.                 if(pGlue->GetActiveContext() != NULL)    {
  1878.                     ReturnID = pGlue->GetActiveContext()->GetContextID();
  1879.                 }
  1880.                 else if(pGlue->GetMainContext() != NULL)    {
  1881.                     ReturnID = pGlue->GetMainContext()->GetContextID();
  1882.                 }
  1883.             }
  1884.         }
  1885.     }
  1886.  
  1887.     if(ReturnID)    {
  1888.         //  Activate it for real.
  1889.         CAbstractCX *pCX = CAbstractCX::FindContextByID(ReturnID);
  1890.         if(pCX && pCX->IsFrameContext() && pCX->GetContext()->type == MWContextBrowser)  {
  1891.             CWinCX *pWinCX = (CWinCX *)pCX;
  1892.             if(pWinCX->GetFrame() && pWinCX->GetFrame()->GetFrameWnd())   {
  1893.                 pWinCX->
  1894.                     GetFrame()->
  1895.                     GetFrameWnd()->
  1896.                     SetActiveView(pWinCX->GetView(), TRUE);
  1897.             }
  1898.         }
  1899.     }
  1900.     
  1901.     // HDDEDATA hData = DdeCreateDataHandle(m_dwidInst, &ReturnID, sizeof(DWORD), 0, NULL, 0, 0);
  1902.     HDDEDATA hData = MakeArgs("DW", &ReturnID);
  1903.     return(hData);
  1904. }
  1905.  
  1906.  
  1907. //    Purpose:    Retrieves a URL from the net, and either dumps it into
  1908. //                    a file, or displays it in a given frame.
  1909. //    Arguments:    hszArgs    A string representing our real parameters.
  1910. //    Returns:    HDDEDATA    Returns the actual WindowID of the window
  1911. //                                the performed the open, where 0 means
  1912. //                                the operation failed, and 0xFFFFFFFF
  1913. //                                means the data was not of an appropriate
  1914. //                                MIME type to display in a Web browser....
  1915. //    Comments:    Parameters within hszItem are
  1916. //                    URL,[FileSpec],WindowID,Flags,[FormData],[MIMEType],
  1917. //                        [ProgressApp]
  1918. //                        URL is the location to load
  1919. //                        FileSpec is the file to dump the load to
  1920. //                        WindowID is the window to load into, 0 meaning
  1921. //                            a new window, 0xFFFFFFFF means the default
  1922. //                            window.
  1923. //                        Flags are:
  1924. //                            0x1    Ignore document cache
  1925. //                            0x2    Ignore image cache
  1926. //                            0x4    Operate in the background (?)
  1927. //                        FormData allows the POSTing of a form.
  1928. //                        MIMEType specifies the form data mime type.
  1929. //                        ProgressApp can be named, which is a DDE server
  1930. //                            that will handle progress messages....
  1931. //                        
  1932. //    Revision History:
  1933. //        01-02-95    created GAB
  1934. HDDEDATA CDDEWrapper::OpenURL(HSZ& hszArgs)
  1935. {
  1936.     DWORD dwReturn = 0L;
  1937.     
  1938.     //    Obtain our arguments.
  1939.     CString csURL;
  1940.     CString csFileSpec;
  1941.     DWORD dwWindowID;
  1942.     DWORD dwFlags;
  1943.     CString csFormData;
  1944.     CString csMimeType;
  1945.     CString csProgressApp;
  1946.     ScanArgs(hszArgs, "QCS,QCS,DW,DW,QCS,QCS,CS", &csURL, &csFileSpec,
  1947.         &dwWindowID, &dwFlags, &csFormData, &csMimeType,
  1948.         &csProgressApp);
  1949.         
  1950.     //    This is very important.
  1951.     //    If the client specified a server callback service, then we need
  1952.     //        to save this right now.
  1953.     //    It will be used in WWW_Alert, WWW_BeginProgress,
  1954.     //        WWW_SetProgressRange, WWW_MakingProgress, and WWW_EndProgress.
  1955.     m_csProgressApp = csProgressApp;
  1956.     
  1957.     //    Get the appropriate window.
  1958.     if(dwWindowID == 0)    {
  1959.         //    They want a new window.
  1960.         if(NULL != CFE_CreateNewDocWindow(NULL, NULL))    {
  1961.             //    Window ID is no longer 0.
  1962.             dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
  1963.         }
  1964.     }
  1965.     else if(dwWindowID == 0xFFFFFFFF)    {
  1966.         //    They want the current frame....
  1967.         //    See if we even have one.
  1968.         if(XP_ContextCount(MWContextBrowser, TRUE) == 0)    {
  1969.             if(NULL != CFE_CreateNewDocWindow(NULL, NULL))    {
  1970.                 //    Window ID is no longer 0.
  1971.                 dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
  1972.             }
  1973.             else    {
  1974.                 dwWindowID = 0;
  1975.             }
  1976.         }
  1977.         else    {
  1978.             if(FEU_GetLastActiveFrame(MWContextBrowser) != NULL)    {
  1979.                 //    Should be safe.
  1980.                 dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
  1981.             }
  1982.             else    {
  1983.                 //  No last active frame, but more than one window....
  1984.                 //  Just create a new one.  Can't pick one up arbitrarily.
  1985.                 if(NULL != CFE_CreateNewDocWindow(NULL, NULL))  {
  1986.                     dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
  1987.                 }
  1988.                 else {
  1989.                     dwWindowID = 0;
  1990.                 }
  1991.             }
  1992.         }
  1993.     }
  1994.     else    {
  1995.         //    They are requesting a specific frame.
  1996.         //    See if we've got it.
  1997.         if(FEU_FindFrameByID(dwWindowID, MWContextBrowser) == NULL)    {
  1998.             dwWindowID = 0;
  1999.         }
  2000.     }
  2001.     
  2002.     //    Get the frame
  2003.     CAbstractCX *pCX = CAbstractCX::FindContextByID(dwWindowID);
  2004.     if(!pCX || !pCX->IsFrameContext() || !pCX->GetContext() || pCX->GetContext()->type != MWContextBrowser)
  2005.     {
  2006.         dwWindowID = 0;
  2007.     }
  2008.     
  2009.     //    See if the window exists, a value of 0 means failure at this
  2010.     //        point.
  2011.     if(dwWindowID == 0)    {
  2012.         //    Well, either the window didn't exist, or we couldn't create
  2013.         //        a new window.
  2014.         return(MakeArgs("DW", &dwWindowID));
  2015.     }
  2016.     
  2017.     //    So far so good.  Our current return value will be the window ID,
  2018.     //        until another failure further along.
  2019.     dwReturn = dwWindowID;
  2020.     
  2021.     //    Decide whether or not to force a reload.
  2022.     NET_ReloadMethod Reload = NET_DONT_RELOAD;
  2023.     if(dwFlags & 0x1 || dwFlags & 0x2)    {
  2024.         Reload = NET_NORMAL_RELOAD;
  2025.     }
  2026.     
  2027.     //    Create the URL structure to load up the URL.
  2028.     URL_Struct *pURL = NET_CreateURLStruct(csURL,  Reload);
  2029.     
  2030.     //    See if we've got some form to POST.
  2031.     if(csFormData.IsEmpty() != TRUE)    {
  2032.         //    We don't allow anything but a post....
  2033.         pURL->method = URL_POST_METHOD;
  2034.         
  2035.         //    We need to fill in the post data, memory is freed by netlib.
  2036.         char *cp_FormData = (char *)XP_ALLOC(csFormData.GetLength() + 1);
  2037.         strcpy(cp_FormData, csFormData);
  2038.         pURL->post_data = cp_FormData;
  2039.  
  2040.         //    Set the length of the data, don't include our final NULL
  2041.         //        I suppose.
  2042.         pURL->post_data_size = csFormData.GetLength();
  2043.         
  2044.         //    We need to manually fill in the Content-type:
  2045.         //    If there's not one specified, we default to
  2046.         //        applications/x-www-form-urlencoded
  2047.         if(csMimeType.IsEmpty() != TRUE)    {
  2048.             StrAllocCopy(pURL->post_headers, "Content-type: ");
  2049.             StrAllocCat(pURL->post_headers, csMimeType);            
  2050.         }
  2051.         else    {
  2052.             StrAllocCopy(pURL->post_headers,
  2053.                 "Content-type: application/x-www-form-urlencoded");
  2054.         }
  2055.         StrAllocCat(pURL->post_headers, CRLF);
  2056.  
  2057.         //    Also now need to fill in content-length....
  2058.         char aBuffer[1024];
  2059.         sprintf(aBuffer, "Content-length: %d", csFormData.GetLength());
  2060.         StrAllocCat(pURL->post_headers, aBuffer);
  2061.         StrAllocCat(pURL->post_headers, CRLF);
  2062.     }
  2063.     
  2064.     //    Have the URL load.  We simply can't block our return value until
  2065.     //        all connections are completed for the window because we
  2066.     //        hose all the messaging.
  2067.     MWContext *pContext = pCX->GetContext();
  2068.     
  2069.     //    Here we should set up all progress callbacks.
  2070.     //    So whenever we get an Alert, or any progress messages, we'll
  2071.     //        be sending it on down to this callback.
  2072.     //    This must be cleared in GetURL_exit_routine
  2073.     if(csProgressApp.IsEmpty() == FALSE && pContext != NULL)    {
  2074.         //    Set up a progress app for this one.
  2075.         CNcapiUrlData *pNcapi = new CNcapiUrlData(ABSTRACTCX(pContext), pURL);
  2076.         pNcapi->SetProgressServer(csProgressApp);
  2077.     }
  2078.  
  2079.     if(pContext != NULL)    {
  2080.         if(csFileSpec.IsEmpty())    {
  2081.             //    Load up.
  2082.             ABSTRACTCX(pContext)->GetUrl(pURL, FO_CACHE_AND_PRESENT);
  2083.         }
  2084.         else    {
  2085.             //    Load to file.        
  2086.             //    Protect against re-entrancy
  2087.             if(pContext->save_as_name)    {
  2088.                 XP_FREE(pContext->save_as_name);
  2089.                 pContext->save_as_name = NULL;
  2090.             }
  2091.             pContext->save_as_name = strdup(csFileSpec);
  2092.  
  2093.             //    Load up.
  2094.             ABSTRACTCX(pContext)->GetUrl(pURL, FO_CACHE_AND_SAVE_AS);
  2095.         }
  2096.     }
  2097.     
  2098.     return(MakeArgs("DW", &dwReturn));
  2099. }
  2100.  
  2101.  
  2102. //    Purpose:    Register a DDE viewer
  2103. //    Arguments:    hszItem    The arguement string.
  2104. //    Returns:    HDDEDATA    A boolean indicating success or failure of
  2105. //                                the registration.
  2106. //    Comments:    Parameters withing hszItem are
  2107. //                    qcsApplication    The DDE server which will handle
  2108. //                                        the requests.
  2109. //                    qcsMIMEType        The mime type that the viewer wants
  2110. //                                        to handle.
  2111. //                    dwFlags    Flags on how to handle:
  2112. //                                0x00000001    Platform specific open document command.
  2113. //                                0x00000002    Use of a QueryViewer DDE command, to ask for a file spec.
  2114. //                                0x00000004    Use ViewDocFile DDE command.
  2115. //                                0x00000008    Use ViewDocData, not supported.
  2116. //                The only registration we allow will be FO_PRESENT
  2117. //                There is a default if the flags is 0, which is
  2118. //                    ViewDocFile method.
  2119. //    Revision History:
  2120. //        01-06-94    created GAB
  2121. HDDEDATA CDDEWrapper::RegisterViewer(HSZ& hszItem)
  2122. {
  2123.     //    Scan in our arguments.
  2124.     CString csApplication;
  2125.     CString csMimeType;
  2126.     DWORD dwFlags;
  2127.     ScanArgs(hszItem, "QCS,QCS,DW", &csApplication, &csMimeType, &dwFlags);
  2128.     
  2129.     TwoByteBool bRetval = TRUE;
  2130.     
  2131.     //    Extract out if we are going to be using the QueryViewer command.
  2132.     TwoByteBool bQueryViewer = (dwFlags & 0x2UL) != 0UL ? TRUE : FALSE;
  2133.     if(bQueryViewer == TRUE)    {
  2134.         dwFlags ^= 0x2;
  2135.     }
  2136.     
  2137.     //    Screen any flags we don't support
  2138.     if(dwFlags != 0x1 && dwFlags != 0x4)    {
  2139.         bRetval = FALSE;
  2140.         return(MakeArgs("BL", &bRetval));
  2141.     }
  2142.     
  2143.     //    Make sure the application and mime type aren't empty.
  2144.     if(csApplication.IsEmpty() || csMimeType.IsEmpty())    {
  2145.         bRetval = FALSE;
  2146.         return(MakeArgs("BL", &bRetval));
  2147.     }
  2148.     
  2149.     //    Build a special data object to be handed to each stream.
  2150.     //    Basically this will contain the DDE server to contact once we
  2151.     //        are receiving data, and will contain the flag representing
  2152.     //        how the data should be handled.
  2153.     //    We will also be marking this MimeType as un overrideable, until
  2154.     //        it is unregistered.
  2155.     CDDEStreamData *pCData = new CDDEStreamData(csApplication, csMimeType,
  2156.         dwFlags, bQueryViewer);
  2157.  
  2158.     //    Register a special converter for the mime type.
  2159.     if(FALSE == WPM_RegisterContentTypeConverter(
  2160.         (char *)(const char *)csMimeType, FO_PRESENT,
  2161.         (void *)pCData, dde_stream, TRUE))    {
  2162.  
  2163.         //    Couldn't do it, another remote control client is already
  2164.         //        using this mime type.
  2165.         delete pCData;
  2166.         bRetval = FALSE;        
  2167.     }
  2168.     
  2169.     return(MakeArgs("BL", &bRetval));
  2170. }
  2171.  
  2172.  
  2173. //    Purpose:    Determine the URL a temp file came from.
  2174. //    Arguments:    hszItem    The arguement string.
  2175. //    Returns:    HDDEDATA    The URL, or NULL on failure.
  2176. //    Comments:    Parameters withing hszItem are
  2177. //                    qcsFileName    The file name to look up.
  2178. //    Revision History:
  2179. //        03-21-95    created GAB
  2180. HDDEDATA CDDEWrapper::QueryURLFile(HSZ& hszItem)
  2181. {
  2182.     //    Scan in our arguments.
  2183.     CString csFileName;
  2184.     ScanArgs(hszItem, "QCS", &csFileName);
  2185.     csFileName.MakeLower();
  2186.     
  2187.     CString csRetval;
  2188.     
  2189.     //  Find out if the file name is one we know about.
  2190.     csRetval = theApp.GetProfileString("Temporary File URL Resolution", csFileName, "");
  2191.  
  2192.     if(csRetval.IsEmpty())  {
  2193.         return(NULL);
  2194.     }
  2195.     
  2196.     return(MakeArgs("QCS", &csRetval));
  2197. }
  2198.  
  2199.  
  2200. //    Purpose:    Unregisters on the fly a DDE content type converter.
  2201. //    Arguments:    hszItem    Our arguments, in a string
  2202. //    Returns:    HDDEDATA    A boolean indicating the success of the
  2203. //                                operation, which should always be TRUE.
  2204. //    Comments:    Our real arguments inside hszItem are
  2205. //                    qcsApplication    The DDE server to unregister
  2206. //                    qcsMimeType        The Mime type to unregister
  2207. //                The only registration we allow will be FO_PRESENT
  2208. //    Revision History:
  2209. //        01-06-95    created GAB
  2210. HDDEDATA CDDEWrapper::UnRegisterViewer(HSZ& hszItem)
  2211. {
  2212.     //    Retrieve our arguments.
  2213.     CString csApplication;
  2214.     CString csMimeType;
  2215.     ScanArgs(hszItem, "QCS,QCS", &csApplication, &csMimeType);
  2216.     
  2217.     TwoByteBool bRetval = TRUE;
  2218.  
  2219.     if(csApplication.IsEmpty() || csMimeType.IsEmpty())    {
  2220.         bRetval = FALSE;
  2221.         return(MakeArgs("BL", &bRetval));
  2222.     }
  2223.     
  2224.     CDDEStreamData *pCData =
  2225.         (CDDEStreamData *)WPM_UnRegisterContentTypeConverter(csApplication,
  2226.         csMimeType, FO_PRESENT);
  2227.         
  2228.     if(pCData == NULL)    {
  2229.         bRetval = FALSE;
  2230.     }
  2231.     else    {
  2232.         delete pCData;
  2233.     }
  2234.  
  2235.     return(MakeArgs("BL", &bRetval));
  2236. }
  2237.  
  2238.  
  2239. //    Purpose:    Connect to a service using a specific topic
  2240. //    Arguments:    cpService    The service name of the DDE server
  2241. //                hszTopic    The topic of the conversation to the server
  2242. //    Returns:    CDDEWrapper *    The conversation object if established,
  2243. //                                    otherwise NULL.
  2244. //    Comments:    Generic connection establishment.
  2245. //    Revision History:
  2246. //        01-05-95    created GAB
  2247. CDDEWrapper *CDDEWrapper::ClientConnect(const char *cpService,
  2248.     HSZ& hszTopic)
  2249. {
  2250.     CDDEWrapper *pConv = NULL;
  2251.  
  2252.     //    Make the service name into an HSZ.
  2253.     HSZ hszService = DdeCreateStringHandle(m_dwidInst, 
  2254.                                            (char *) cpService,
  2255.                                            CP_WINANSI);
  2256.     if(hszService == NULL)    {
  2257.         return(NULL);
  2258.     }
  2259.     
  2260.     //    Establish the connection.
  2261.     HCONV hConv = DdeConnect(m_dwidInst, hszService, hszTopic, NULL);
  2262.     if(hConv != NULL)    {
  2263.         //    We have a connection, all that's left to do is to create
  2264.         //        a CDDEWrapper, we'll be creating it with the wrong
  2265.         //        service name of course, but client connections no
  2266.         //        longer really care about the service connection number,
  2267.         //        all they need is the conversation handle.
  2268.         pConv = new CDDEWrapper(m_hsz[m_ServiceName], hszTopic, hConv);
  2269.     }
  2270.         
  2271.     //    Free off our created hsz.
  2272.     DdeFreeStringHandle(m_dwidInst, hszService);
  2273.     
  2274.     //    Our return value, sir.
  2275.     return(pConv);
  2276. }
  2277.  
  2278.  
  2279. //    Purpose:    Send the service app a begin progress verb.
  2280. //    Arguments:    pNcapi    The url data causing this to occur.
  2281. //                pService    The service name to connect to.
  2282. //                dwWindowID    The windowID which has progressed.
  2283. //                pMessage    The message to show in the server.
  2284. //    Returns:    DWORD    The transaction ID that the server sends us
  2285. //                            to use in all other progress verbs.
  2286. //    Comments:    Netscape is a DDE client in this function.
  2287. //    Revision History:
  2288. //        01-05-95    created GAB
  2289. //        10-17-95    modified to use CNcapiUrlData
  2290. DWORD CDDEWrapper::BeginProgress(CNcapiUrlData *pNcapi, const char *pService,
  2291.     DWORD dwWindowID, const char *pMessage)
  2292. {
  2293.     DWORD dwTransactionID;
  2294.  
  2295.     //    Get the conversation going.
  2296.     CDDEWrapper *pConv = ClientConnect(pService, m_hsz[m_BeginProgress]);
  2297.     
  2298.     //    If we didn't connect, don't let the document try this again
  2299.     //        for this progress.
  2300.     if(pConv == NULL)    {
  2301.         pNcapi->ClearProgressServer();
  2302.         return(0L);
  2303.     }    
  2304.  
  2305.     //    Save our conversation, in case the server decides to disconnect
  2306.     //        behind our backs.
  2307.     HCONV hSaveConv = pConv->m_hConv;
  2308.  
  2309.     //    Create our Item arguemnts.
  2310.     CString csTemp = pMessage;
  2311.     HSZ hszItem = MakeItemArgs("DW,QCS", &dwWindowID, &csTemp);
  2312.     
  2313.     //    Do the transaction, expect a transaction ID back.
  2314.     HDDEDATA ddeTransaction = DdeClientTransaction(NULL, 0L,
  2315.         hSaveConv, hszItem, CF_TEXT, XTYP_REQUEST, m_Timeout, NULL);
  2316.     
  2317.     //    Cut the cord.
  2318.     DdeFreeStringHandle(m_dwidInst, hszItem);
  2319.     DdeDisconnect(hSaveConv);
  2320.     
  2321.     //    Make sure we still have a conversation, if so, delete the object.
  2322.     pConv = GetConvObj(hSaveConv);
  2323.     if(pConv != NULL)    {
  2324.         delete pConv;
  2325.     }
  2326.     
  2327.     if(ddeTransaction == NULL)    {
  2328.         //    Server didn't want to process this.
  2329.         //    Don't try them again.
  2330.         pNcapi->ClearProgressServer();
  2331.     
  2332.         dwTransactionID = 0L;
  2333.     }
  2334.     else    {
  2335.         //    Scan in the progress ID, and get rid of the handle.
  2336.         //    Well, it would seem that they're not following their own
  2337.         //        spec.  They send us raw data, get it that way.
  2338.         //ScanArgs(ddeTransaction, "DW", &dwTransactionID);
  2339.         if(ddeTransaction != NULL)    {
  2340.             ScanDataArgs(ddeTransaction, "DW", &dwTransactionID);
  2341.             DdeFreeDataHandle(ddeTransaction);
  2342.         }
  2343.         else    {
  2344.             dwTransactionID = 0L;
  2345.         }
  2346.     }
  2347.  
  2348.     //    If the transaction ID is 0, then they don't want progress.
  2349.     if(dwTransactionID == 0)    {
  2350.         pNcapi->ClearProgressServer();
  2351.     }
  2352.     
  2353.     return(dwTransactionID);
  2354. }
  2355.  
  2356.  
  2357. //    Purpose:    Tell the DDE server our progress range.
  2358. //    Arguments:    pNcapi    The url data initiating this request.
  2359. //                pService    The server's service name.
  2360. //                dwTransactionID    The transaction ID of this progress.
  2361. //                dwMaxRange    The max range that we can achieve.
  2362. //    Returns:    void
  2363. //    Comments:    Netscape is the DDE client.
  2364. //    Revision History:
  2365. //        01-05-94    created GAB
  2366. //        10-17-95    modified to use CNcapiUrlData
  2367. void CDDEWrapper::SetProgressRange(CNcapiUrlData *pNcapi, const char *pService,
  2368.     DWORD dwTransactionID, DWORD dwMaxRange)
  2369. {
  2370.     //    Get the conversation going.
  2371.     CDDEWrapper *pConv = ClientConnect(pService,
  2372.         m_hsz[m_SetProgressRange]);
  2373.     
  2374.     //    If we didn't connect, don't let the document try this again
  2375.     //        for this progress.
  2376.     if(pConv == NULL)    {
  2377.         pNcapi->ClearProgressServer();
  2378.         return;
  2379.     }
  2380.  
  2381.     //    Save the conversation, in case the DDE server disconnects behind
  2382.     //        our backs.
  2383.     HCONV hSaveConv = pConv->m_hConv;
  2384.     
  2385.     //    Create our item arguments.
  2386.     HSZ hszItem = MakeItemArgs("DW,DW", &dwTransactionID, &dwMaxRange);
  2387.  
  2388.     //    Do the transaction, expect nothing back XTYP_POKE
  2389.     if(FALSE == DdeClientTransaction(NULL, 0L, hSaveConv, hszItem,
  2390.         CF_TEXT, XTYP_POKE, m_Timeout, NULL))    {
  2391.         //    For some reason, this didn't fly.
  2392.         //    Don't let the document try this again.
  2393.         pNcapi->ClearProgressServer();
  2394.     }
  2395.  
  2396.     //    Cut the cord.
  2397.     DdeFreeStringHandle(m_dwidInst, hszItem);
  2398.     DdeDisconnect(hSaveConv);
  2399.     
  2400.     pConv = GetConvObj(hSaveConv);
  2401.     if(pConv != NULL)    {
  2402.         delete pConv;
  2403.     }
  2404. }
  2405.  
  2406.  
  2407. //    Purpose:    Tell the DDE server that we have made progress.
  2408. //    Arguments:    pNcapi    The document initiating this request.
  2409. //                pServic    The server's service name
  2410. //                dwTransactionID    The transaction ID to send with the
  2411. //                            message, aquired by a begin progress call.
  2412. //                pMessage    A message to send to the server, explaining
  2413. //                                the progress message.
  2414. //                dwCurrent    A number, representing a range, which
  2415. //                                was set by a set progress range call.
  2416. //    Returns:    TwoByteBool    TRUE    The server would like to discontinue
  2417. //                                    the download.
  2418. //                        FALSE    Continue downloading.
  2419. //    Comments:    Netscape is a DDE client.
  2420. //    Revision History:
  2421. //        01-05-95    created GAB
  2422. //        10-17-95    modified to use CNcapiUrlData
  2423. TwoByteBool CDDEWrapper::MakingProgress(CNcapiUrlData *pNcapi, const char *pService,
  2424.     DWORD dwTransactionID, const char *pMessage, DWORD dwCurrent)
  2425. {
  2426.     //    Get the conversation going.
  2427.     CDDEWrapper *pConv = ClientConnect(pService,
  2428.         m_hsz[m_MakingProgress]);
  2429.     
  2430.     //    If we didn't connect, don't let the document try this again
  2431.     //        for this progress.
  2432.     if(pConv == NULL)    {
  2433.         pNcapi->ClearProgressServer();
  2434.         return(FALSE);
  2435.     }
  2436.  
  2437.     //    Save the conversation, in case the DDE server disconnects behind
  2438.     //        our backs.
  2439.     HCONV hSaveConv = pConv->m_hConv;
  2440.     
  2441.     //    Create our item arguments.
  2442.     CString csMessage = pMessage;
  2443.     HSZ hszItem = MakeItemArgs("DW,QCS,DW", &dwTransactionID, &csMessage,
  2444.         &dwCurrent);
  2445.  
  2446.     //    Do the transaction, expect a TwoByteBool back.
  2447.     HDDEDATA ddeTransaction = DdeClientTransaction(NULL, 0L,
  2448.         hSaveConv, hszItem, CF_TEXT, XTYP_REQUEST, m_Timeout, NULL);
  2449.  
  2450.     //    Cut the cord.
  2451.     DdeFreeStringHandle(m_dwidInst, hszItem);
  2452.     DdeDisconnect(hSaveConv);
  2453.     
  2454.     //    Make sure we still have a conversation, if so, delete the object.
  2455.     pConv = GetConvObj(hSaveConv);
  2456.     if(pConv)    {
  2457.         delete pConv;
  2458.     }
  2459.     
  2460.     TwoByteBool bResult = FALSE;
  2461.     
  2462.     if(ddeTransaction == NULL)    {
  2463.         //    Server didn't want to process this.
  2464.         //    Don't try them again.
  2465.         pNcapi->ClearProgressServer();
  2466.     }
  2467.     else    {
  2468.         //    Scan in the progress ID, and get rid of the handle.
  2469.         if(ddeTransaction != NULL)    {
  2470.             ScanDataArgs(ddeTransaction, "BL", &bResult);
  2471.             DdeFreeDataHandle(ddeTransaction);
  2472.         }
  2473.         else    {
  2474.             bResult = FALSE;
  2475.         }
  2476.     }
  2477.     
  2478.     return(bResult);
  2479. }
  2480.  
  2481.  
  2482. //    Purpose:    Tell the DDE server that the progress is ending.
  2483. //    Arguments:    pNcapi    The document initiating the request
  2484. //                pService    The server's service name
  2485. //                dwTransactionID    The transaction ID of these progress
  2486. //                                    messages.
  2487. //    Returns:    TwoByteBool    A success or failure boolean, we really don't
  2488. //                            care, and will always end.
  2489. //                BUT WAIT, the spec says this, but in reality, it isn't
  2490. //                            done.
  2491. //    Comments:    Netscape is the DDE client.
  2492. //    Revision History:
  2493. //        01-05-95    created GAB
  2494. //        10-17-95    modified to use CNcapiUrlData
  2495. void CDDEWrapper::EndProgress(CNcapiUrlData *pNcapi, const char *pService,
  2496.     DWORD dwTransactionID)
  2497. {
  2498.     //    Get the conversation going.
  2499.     CDDEWrapper *pConv = ClientConnect(pService,
  2500.         m_hsz[m_EndProgress]);
  2501.     
  2502.     //    If we didn't connect, don't let the document try this again
  2503.     //        for this progress.
  2504.     if(pConv == NULL)    {
  2505.         pNcapi->ClearProgressServer();
  2506.         return;
  2507.     }
  2508.  
  2509.     //    Save the conversation, in case the DDE server disconnects behind
  2510.     //        our backs.
  2511.     HCONV hSaveConv = pConv->m_hConv;
  2512.     
  2513.     //    Create our item arguments.
  2514.     HSZ hszItem = MakeItemArgs("DW", &dwTransactionID);
  2515.  
  2516.     //    Do the transaction, expect nothing.
  2517.     DdeClientTransaction(NULL, 0L,
  2518.         hSaveConv, hszItem, CF_TEXT, XTYP_POKE, m_Timeout, NULL);
  2519.  
  2520.     //    Cut the cord.
  2521.     DdeFreeStringHandle(m_dwidInst, hszItem);
  2522.     DdeDisconnect(hSaveConv);
  2523.     
  2524.     //    Make sure we still have a conversation, if so, delete the object.
  2525.     pConv = GetConvObj(hSaveConv);
  2526.     if(pConv)    {
  2527.         delete pConv;
  2528.     }
  2529. }
  2530.  
  2531.  
  2532. //    Purpose:    Send our progress app an error message.
  2533. //    Arguments:    pDoc    The document requesting this action
  2534. //                pService    The server's service name
  2535. //                pMessage    The message to send
  2536. //    Returns:    DWORD    The button pushed by the remote app, or error (0)
  2537. //                            on failuer.
  2538. //    Comments:    All servers should consider this message as a failure to
  2539. //                    load.
  2540. //    Revision History:
  2541. //        01-05-95    created GAB
  2542. //        10-17-95    modified to use CNcapiUrlData
  2543. DWORD CDDEWrapper::AlertProgress(CNcapiUrlData *pNcapi, const char *pService,
  2544.     const char *pMessage)
  2545. {
  2546.     //    Get the conversation going.
  2547.     CDDEWrapper *pConv = ClientConnect(pService,
  2548.         m_hsz[m_Alert]);
  2549.     
  2550.     //    If we didn't connect, simply return, not everyone will have
  2551.     //        this verb.
  2552.     if(pConv == NULL)    {
  2553.         return(m_PushedError);
  2554.     }
  2555.  
  2556.     //    Save the conversation, in case the DDE server disconnects behind
  2557.     //        our backs.
  2558.     HCONV hSaveConv = pConv->m_hConv;
  2559.     
  2560.     //    Create our item arguments.
  2561.     CString csMessage = pMessage;
  2562.     DWORD dwType = m_AlertError;    // error box
  2563.     DWORD dwButtons = m_ButtonOk;    //    What buttons to show
  2564.     HSZ hszItem = MakeItemArgs("QCS,DW,DW", &csMessage, &dwType,
  2565.         &dwButtons);
  2566.  
  2567.     //    Do the transaction
  2568.     HDDEDATA ddeTransaction = DdeClientTransaction(NULL, 0L,
  2569.         hSaveConv, hszItem, CF_TEXT, XTYP_REQUEST, m_Timeout, NULL);
  2570.  
  2571.     //    Cut the cord.
  2572.     DdeFreeStringHandle(m_dwidInst, hszItem);
  2573.     DdeDisconnect(hSaveConv);
  2574.     
  2575.     //    Make sure we still have a conversation, if so, delete the object.
  2576.     pConv = GetConvObj(hSaveConv);
  2577.     if(pConv)    {
  2578.         delete pConv;
  2579.     }
  2580.     
  2581.     DWORD dwResult = 0L;
  2582.     
  2583.     if(ddeTransaction != NULL)    {
  2584.         //    Scan in the return value, and get rid of the handle.
  2585.         ScanDataArgs(ddeTransaction, "DW", &dwResult);
  2586.         DdeFreeDataHandle(ddeTransaction);
  2587.     }
  2588.     
  2589.     return(dwResult);
  2590. }
  2591.  
  2592. //    Purpose:    Send our progress app a confirmation message.
  2593. //    Arguments:    pNcapi    The document requesting this action
  2594. //                pService    The server's service name
  2595. //                pMessage    The message to send
  2596. //    Returns:    DWORD    The button pushed by the remote app, or error (0)
  2597. //                            on failuer.
  2598. //    Comments:
  2599. //    Revision History:
  2600. //        10-17-95    created
  2601. DWORD CDDEWrapper::ConfirmProgress(CNcapiUrlData *pNcapi, const char *pService,
  2602.     const char *pMessage)
  2603. {
  2604.     //    Get the conversation going.
  2605.     CDDEWrapper *pConv = ClientConnect(pService,
  2606.         m_hsz[m_Alert]);
  2607.     
  2608.     //    If we didn't connect, simply return, not everyone will have
  2609.     //        this verb.
  2610.     if(pConv == NULL)    {
  2611.         return(m_PushedError);
  2612.     }
  2613.  
  2614.     //    Save the conversation, in case the DDE server disconnects behind
  2615.     //        our backs.
  2616.     HCONV hSaveConv = pConv->m_hConv;
  2617.     
  2618.     //    Create our item arguments.
  2619.     CString csMessage = pMessage;
  2620.     DWORD dwType = m_AlertQuestion;    // error box
  2621.     DWORD dwButtons = m_ButtonYesNo;    //    What buttons to show
  2622.     HSZ hszItem = MakeItemArgs("QCS,DW,DW", &csMessage, &dwType,
  2623.         &dwButtons);
  2624.  
  2625.     //    Do the transaction
  2626.     HDDEDATA ddeTransaction = DdeClientTransaction(NULL, 0L,
  2627.         hSaveConv, hszItem, CF_TEXT, XTYP_REQUEST, m_Timeout, NULL);
  2628.  
  2629.     //    Cut the cord.
  2630.     DdeFreeStringHandle(m_dwidInst, hszItem);
  2631.     DdeDisconnect(hSaveConv);
  2632.     
  2633.     //    Make sure we still have a conversation, if so, delete the object.
  2634.     pConv = GetConvObj(hSaveConv);
  2635.     if(pConv)    {
  2636.         delete pConv;
  2637.     }
  2638.     
  2639.     DWORD dwResult = 0L;
  2640.     
  2641.     if(ddeTransaction != NULL)    {
  2642.         //    Scan in the return value, and get rid of the handle.
  2643.         ScanDataArgs(ddeTransaction, "DW", &dwResult);
  2644.         DdeFreeDataHandle(ddeTransaction);
  2645.     }
  2646.     
  2647.     return(dwResult);
  2648. }
  2649.  
  2650.  
  2651. //    Purpose:    Ask a DDE server what file we should save a file under,
  2652. //                    one that we just downloaded.
  2653. //    Arguments:    pDData    Our download data, will hold everything needed
  2654. //                            to establish the conversation.
  2655. //    Returns:    void
  2656. //    Comments:    Another topic should be called after this one in order
  2657. //        to tell the registered viewer that it's document is now ready.
  2658. //    Revision History:
  2659. //        01-06-95    created GAB
  2660. void CDDEWrapper::QueryViewer(CDDEDownloadData *pDData)
  2661. {
  2662.     //    Get our parameters to establish the conversation.
  2663.     CString csService = pDData->m_pCData->m_csServerName;
  2664.     
  2665.     //    Get the conversation going.
  2666.     CDDEWrapper *pConv = ClientConnect(csService, m_hsz[m_QueryViewer]);
  2667.         
  2668.     if(pConv == NULL)    {
  2669.         //    There's not much else we can do here, simply return.
  2670.         return;
  2671.     }
  2672.     
  2673.     //    Save the conversation, in case the DDE server disconnects behind
  2674.     //        our backs.
  2675.     HCONV hSaveConv = pConv->m_hConv;
  2676.     
  2677.     //    Create our argument list.
  2678.     CString csURL;
  2679.     CString csMimeType;
  2680.     csMimeType = pDData->m_pCData->m_csMimeType;
  2681.     csURL = pDData->m_csURL;
  2682.     HSZ hszItem = MakeItemArgs("QCS,QCS", &csURL, &csMimeType); 
  2683.     
  2684.     //    Do the transaction, expect a FileSpec back.
  2685.     HDDEDATA ddeTransaction = DdeClientTransaction(NULL, 0L,
  2686.         hSaveConv, hszItem, CF_TEXT, XTYP_REQUEST, m_Timeout, NULL);    
  2687.  
  2688.     //    Get rid of our string handle, don't need it anymore; same with the
  2689.     //        connection.
  2690.     DdeFreeStringHandle(m_dwidInst, hszItem);
  2691.     DdeDisconnect(hSaveConv);
  2692.  
  2693.     //    Make sure we still have a conversation, if so, delete the object.
  2694.     pConv = GetConvObj(hSaveConv);
  2695.     if(pConv)    {
  2696.         delete pConv;
  2697.     }
  2698.  
  2699.     if(ddeTransaction == NULL)    {
  2700.         //    There's not much else we can do here, simply return.
  2701.         return;
  2702.     }
  2703.  
  2704.     //    Get the file name out of the data returned by the DDE server.
  2705.     CString csFileName;
  2706.     ScanDataArgs(ddeTransaction, "QCS", &csFileName);
  2707.     DdeFreeDataHandle(ddeTransaction);
  2708.     
  2709.     //    Move it over to where the server wants it.
  2710.     TRY    {
  2711.         CFile::Rename(pDData->m_csFileName, csFileName);
  2712.     }
  2713.     CATCH(CFileException, e)    {
  2714.         //    Couldn't rename for some reason.
  2715.         return;
  2716.     }
  2717.     END_CATCH
  2718.  
  2719.     //    Tell the download data, that it won't be necessary to delete this file.
  2720.     //    The viewer will take care of it.
  2721.     pDData->m_bDelete = FALSE;
  2722.     
  2723.     //    Change the name.
  2724.     pDData->m_csFileName = csFileName;
  2725.     
  2726.     //    Done.
  2727.     return;
  2728. }
  2729.  
  2730.  
  2731. //    Purpose:         Tell a registered viewer that a document of it's type is loaded
  2732. //                        and in a certain file.
  2733. //    Arguments:    pDData    The download instance specific data, contains
  2734. //                            the file name.
  2735. //    Returns:    void
  2736. //    Comments:    Function will unregister any viewers that don't respond in
  2737. //                    a fashion that we deem fit.
  2738. //    Revision History:
  2739. //        01-08-95    created GAB
  2740. void CDDEWrapper::ViewDocFile(CDDEDownloadData *pDData)
  2741. {
  2742.     //    Get our parameters to establish the conversation.
  2743.     CString csService = pDData->m_pCData->m_csServerName;
  2744.     
  2745.     //    Get the conversation going.
  2746.     CDDEWrapper *pConv = ClientConnect(csService, m_hsz[m_ViewDocFile]);
  2747.         
  2748.     if(pConv == NULL)    {
  2749.         //    Well, Doh!, the server isn't responding.
  2750.         //    Disable it from further being our registered app.
  2751.         CString csMimeType = pDData->m_pCData->m_csMimeType;
  2752.         WPM_UnRegisterContentTypeConverter(csService, csMimeType,
  2753.             FO_PRESENT);
  2754.         delete pDData->m_pCData;
  2755.         
  2756.         //    There's not much else we can do here, simply return.
  2757.         return;
  2758.     }
  2759.     
  2760.     //    Save the conversation, in case the DDE server disconnects behind
  2761.     //        our backs.
  2762.     HCONV hSaveConv = pConv->m_hConv;
  2763.     
  2764.     //    Create our argument list.
  2765.     CString csFileSpec = pDData->m_csFileName;
  2766.     CString csURL = pDData->m_csURL;
  2767.     CString csMimeType = pDData->m_pCData->m_csMimeType;
  2768.     DWORD dwWindowID = pDData->m_dwFrameID;
  2769.     HSZ hszItem = MakeItemArgs("QCS,QCS,QCS,DW", &csFileSpec, &csURL,
  2770.         &csMimeType, &dwWindowID);
  2771.         
  2772.     //    Do the transaction, expect nothing.
  2773.     DdeClientTransaction(NULL, 0L, hSaveConv, hszItem, CF_TEXT,
  2774.         XTYP_POKE, m_Timeout, NULL);        
  2775.  
  2776.     //    Cut the cord.
  2777.     DdeFreeStringHandle(m_dwidInst, hszItem);
  2778.     DdeDisconnect(hSaveConv);
  2779.  
  2780.     //    Make sure we still have a conversation, if so, delete the object.
  2781.     pConv = GetConvObj(hSaveConv);
  2782.     if(pConv)    {
  2783.         delete pConv;
  2784.     }
  2785.     
  2786.     //    Done here.
  2787.     return;
  2788. }
  2789.  
  2790. //    Purpose:    Use a shell open to open the file name in our download data.
  2791. //    Arguments:    pDData    Data specific to this download.
  2792. //    Returns:    void
  2793. //    Comments:    Support of another RegisterViewer command.
  2794. //    Revision History:
  2795. //        01-14-95    created GAB
  2796. void CDDEWrapper::OpenDocument(CDDEDownloadData *pDData)
  2797. {
  2798.     //    Well, we don't really do any DDE per se here, but this is where the
  2799.     //        funciton logically belongs.
  2800.     //    Attempt to have windows open the file specified.
  2801.     //    This is a fire and forget mechanism, though we will unregister the
  2802.     //        DDE content type converter on an error.
  2803.     HINSTANCE hReturns = ::ShellExecute(::GetDesktopWindow(), NULL, pDData->m_csFileName, NULL, NULL, SW_SHOW);
  2804.     if(hReturns <= (HINSTANCE)32)    {
  2805.         //    There seemed to have been an error.
  2806.         //    Unregister the content type converter now.
  2807.         CString csService = pDData->m_pCData->m_csServerName;
  2808.         CString csMimeType = pDData->m_pCData->m_csMimeType;
  2809.         WPM_UnRegisterContentTypeConverter(csService, csMimeType,
  2810.             FO_PRESENT);
  2811.         delete pDData->m_pCData;
  2812.     }
  2813. }
  2814.  
  2815.  
  2816. //    Purpose:    Exit the Netscape application.
  2817. //    Arguments:    hszItem    Our arguments.
  2818. //                hData    Any data in particular that the server is sending us.
  2819. //    Returns:    HDDEDATA    Wether or not we completed this operation.
  2820. //    Comments:    Netscape will not always exit on this command, since we may be automated.
  2821. //    Revision History:
  2822. //        01-13-95    created GAB
  2823. //        10-17-95    modified to send the last active frame, if around, the
  2824. //                        ID_APP_EXIT WM_COMMAND message.
  2825. HDDEDATA CDDEWrapper::Exit(HSZ& hszItem, HDDEDATA& hData)
  2826. {
  2827.     //    See if any frame windows are around.
  2828.     CFrameWnd *pWnd = FEU_GetLastActiveFrame();
  2829.     if(pWnd != NULL)    {
  2830.         //    Send it the app exit message.
  2831.         pWnd->PostMessage(WM_COMMAND, ID_APP_SUPER_EXIT);
  2832.         return((HDDEDATA)DDE_FACK);
  2833.     }
  2834.  
  2835.     return((HDDEDATA)DDE_FNOTPROCESSED);
  2836. }
  2837.  
  2838.  
  2839. //    Purpose:    Get some misc information about a Netscape window.
  2840. //    Arguments:    hstItem    Our arugments, see below.
  2841. //    Returns:    HDDEDATA    Contains
  2842. //                    qcsUrl    The current URL loaded in the window.
  2843. //                    qcsTitle    The current title of the window.
  2844. //    Comments:    This is useless, but implementable.
  2845. //    Revision History:
  2846. //        01-13-95    created GAB
  2847. HDDEDATA CDDEWrapper::GetWindowInfo(HSZ& hszItem)
  2848. {
  2849.     //    Retrieve our arguments.
  2850.     DWORD dwFrameID;
  2851.     ScanArgs(hszItem, "DW", &dwFrameID);
  2852.     
  2853.     //    We'll let dwFrameID be 0xffffffff for the default window.
  2854.     if(dwFrameID == 0xFFFFFFFF)    {
  2855.         dwFrameID = FEU_GetLastActiveFrameID(MWContextBrowser);
  2856.         if(dwFrameID == 0)    {
  2857.             //    This is going to fail, no active window.
  2858.             return(NULL);
  2859.         }
  2860.     }
  2861.     
  2862.     //    Okay, all we have left to do is obtain the current title of the window,
  2863.     //        and the current loaded URL.
  2864.     CAbstractCX *pCX = CAbstractCX::FindContextByID(dwFrameID);
  2865.     if(pCX && pCX->GetContext() && pCX->GetContext()->type != MWContextBrowser) {
  2866.         pCX = NULL;
  2867.     }
  2868.  
  2869.     if(pCX == NULL)    {
  2870.         return(NULL);
  2871.     }
  2872.     
  2873.     //    Get the stuff.
  2874.     CString csTitle;
  2875.     CString csUrl;
  2876.     CString csName;
  2877.  
  2878.     if(pCX->GetContext())   {
  2879.         if(pCX->GetContext()->title)    {
  2880.             csTitle = pCX->GetContext()->title;
  2881.         }
  2882.         if(pCX->GetContext()->hist.cur_doc_ptr)    {
  2883.             if(pCX->GetContext()->hist.cur_doc_ptr->address)    {
  2884.                 csUrl = pCX->GetContext()->hist.cur_doc_ptr->address;
  2885.             }
  2886.         }
  2887.         if(pCX->GetContext()->name)   {
  2888.             csName = pCX->GetContext()->name;
  2889.         }
  2890.     }
  2891.     
  2892.     //    Create our return arguments.
  2893.     return(MakeArgs("QCS,QCS,QCS", &csUrl, &csTitle, &csName));
  2894. }
  2895.  
  2896. //    Purpose:    List all the open Netscape windows.
  2897. //    Arguments:    hszItem    ignored.
  2898. //    Returns:    HDDEDATA    An array of DWORDs corresponding to the windows.
  2899. //    Comments:    We will manually create the return data in this function,
  2900. //                    as it follows no previously coded standard.
  2901. //                We will not return the ID of the minimized window.
  2902. //    Revision History:
  2903. //        01-13-94    created GAB
  2904. HDDEDATA CDDEWrapper::ListWindows(HSZ& hszItem)
  2905. {
  2906.     //    Count our windows.
  2907.     DWORD dwFrames = XP_ContextCount(MWContextBrowser, FALSE);
  2908.     
  2909.     //    No frames, don't do this.
  2910.     if(dwFrames == 0)    {
  2911.         return(NULL);
  2912.     }
  2913.     
  2914.     DWORD *pData = new DWORD[dwFrames + 1];
  2915.     DWORD dwCounter = 0;
  2916.     
  2917.     //    Loop through each context, taking only browser style contexts.
  2918.     MWContext *pTraverseContext = NULL;
  2919.     CAbstractCX *pTraverseCX = NULL;
  2920.     XP_List *pTraverse = XP_GetGlobalContextList();
  2921.     while (pTraverseContext = (MWContext *)XP_ListNextObject(pTraverse)) {
  2922.         if(pTraverseContext != NULL && ABSTRACTCX(pTraverseContext) != NULL)    {
  2923.             pTraverseCX = ABSTRACTCX(pTraverseContext);
  2924.  
  2925.             if(pTraverseCX->GetContext()->type == MWContextBrowser &&
  2926.                 pTraverseCX->IsFrameContext() == TRUE &&
  2927.                 pTraverseCX->IsDestroyed() == FALSE)    {
  2928.                 CWinCX *pWinCX = (CWinCX *)pTraverseCX;
  2929.                 if(pWinCX->GetFrame()->GetFrameWnd() != NULL)    {
  2930.                     //    Looks like this is the type of context we'll list.
  2931.                     *(pData + dwCounter) = pWinCX->GetContextID();
  2932.                     dwCounter++;
  2933.                 }
  2934.             }
  2935.  
  2936.         }
  2937.     }
  2938.  
  2939.     //    Null terminate the list.
  2940.     *(pData + dwCounter) = (DWORD)0;
  2941.  
  2942.     //    allocate some data to return to the caller.
  2943.     HDDEDATA hData = DdeCreateDataHandle(m_dwidInst, (unsigned char *)pData, (dwCounter + 1) * sizeof(DWORD), 0, m_hsz[m_ServiceName],
  2944.         CF_TEXT, 0);
  2945.  
  2946.     delete [] pData;    
  2947.     return(hData);
  2948. }
  2949.  
  2950.  
  2951. //    Purpose:    Parse a main, and relative URL, returning the fully qualified URL.
  2952. //    Arguments:    hszItem    The arguments.  See below.
  2953. //    Returns:    HDDEDATA    A null terminated string representing the fully qualified URL.
  2954. //    Comments:    Nothing special here, folks.
  2955. //    Revision History:
  2956. //        01-13-95    created GAB
  2957. HDDEDATA CDDEWrapper::ParseAnchor(HSZ& hszItem)
  2958. {
  2959.     //    Get our arguments.
  2960.     CString csMainURL;
  2961.     CString csRelativeURL;
  2962.     ScanArgs(hszItem, "QCS,QCS", &csMainURL, &csRelativeURL);
  2963.     
  2964.     //    create the URL.
  2965.     char *cpURL = NET_MakeAbsoluteURL((char *)(const char *)csMainURL, (char *)(const char *)csRelativeURL);
  2966.     CString csURL;
  2967.     if(cpURL != NULL)    {
  2968.         csURL = cpURL;
  2969.         XP_FREE(cpURL);
  2970.     }
  2971.     
  2972.     //    Create our return value.
  2973.     return(MakeArgs("QCS", &csURL));
  2974. }
  2975.  
  2976. //    Purpose:    Report the current DDE API version back to the caller.
  2977. //    Arguments:    hszItem    none and ignored.
  2978. //    Returns:    HDDEDATA which actually contains the version.
  2979. //    Comments:    Version control information for the API.
  2980. //    Revision History:
  2981. //        01-17-95    created GAB
  2982. HDDEDATA CDDEWrapper::Version(HSZ& hszItem)
  2983. {
  2984.     return(MakeArgs("DW", &dwDDEVersion));
  2985. }
  2986.  
  2987. //    Purpose:    Register a particular DDE server to handle URLs of a particular type.
  2988. //    Arguments:    hszItem    Arguments, see below.
  2989. //    Returns:    HDDEDATA    TRUE    registered
  2990. //                            FALSE    unable to register, another applciation is handling it.
  2991. //    Comments:
  2992. //    Revision History:
  2993. //        01-18-95    created GAB
  2994. HDDEDATA CDDEWrapper::RegisterProtocol(HSZ& hszItem)
  2995. {
  2996.     //    Get our arguments.
  2997.     CString csServer;
  2998.     CString csProtocol;
  2999.     ScanArgs(hszItem, "QCS,QCS", &csServer, &csProtocol);
  3000.     
  3001.     //    If either is empty, we'll just fail.
  3002.     if(csServer.IsEmpty() || csProtocol.IsEmpty())    {
  3003.         return(NULL);
  3004.     }
  3005.     
  3006.     //    Need to see if something is already registered to handle this protocol.
  3007.     TwoByteBool bRetval = CDDEProtocolItem::DDERegister(csProtocol, csServer);
  3008.     
  3009.     return(MakeArgs("BL", &bRetval));
  3010. }
  3011.  
  3012. //    Purpose:    Register a particular DDE server to handle URLs of a particular type.
  3013. //    Arguments:    hszItem    Arguments, see below.
  3014. //    Returns:    HDDEDATA    TRUE    registered
  3015. //                            FALSE    unable to register, another applciation is handling it.
  3016. //    Comments:
  3017. //    Revision History:
  3018. //        01-18-95    created GAB
  3019. HDDEDATA CDDEWrapper::UnRegisterProtocol(HSZ& hszItem)
  3020. {
  3021.     //    Get our arguments.
  3022.     CString csServer;
  3023.     CString csProtocol;
  3024.     ScanArgs(hszItem, "QCS,QCS", &csServer, &csProtocol);
  3025.     
  3026.     //    If either is empty, we'll just fail.
  3027.     if(csServer.IsEmpty() || csProtocol.IsEmpty())    {
  3028.         return(NULL);
  3029.     }
  3030.  
  3031.     TwoByteBool bRetval = CDDEProtocolItem::DDEUnRegister(csProtocol, csServer);
  3032.     return(MakeArgs("BL", &bRetval));    
  3033. }
  3034.  
  3035. //    Purpose:    Have an external protocol handler open a URL.
  3036. //    Arguments:    csServiceName    The name of the external service application.
  3037. //                pURL    The URL to perform the load on; contains possible form data also.
  3038. //                pContext    The context to load from (windowID).
  3039. //                iFormatOut    Wether or not to save the URL.
  3040. //    Returns:    TwoByteBool    TRUE    External application handling the request.
  3041. //                        FALSE    External application failed to handle.
  3042. //    Comments:    Will automatically deregister the external applciation if failure to connect.
  3043. //    Revision History:
  3044. //        01-18-94    created GAB
  3045. TwoByteBool CDDEWrapper::OpenURL(CString csProtocol, CString csServiceName, URL_Struct *pURL, MWContext *pContext, FO_Present_Types iFormatOut)
  3046. {
  3047.     //    Get the conversation going.
  3048.     CDDEWrapper *pConv = ClientConnect(csServiceName, m_hsz[m_OpenURL]);
  3049.  
  3050.     if(pConv == NULL)    {
  3051.         //    Well, Doh!, the server isn't responding.
  3052.         //    Disable it from further being our registered app.
  3053.         CDDEProtocolItem::DDEUnRegister(csProtocol, csServiceName);
  3054.         
  3055.         //    There's not much else we can do here, simply return.
  3056.         return(FALSE);
  3057.     }
  3058.     
  3059.     //    Save the conversation, in case the DDE server disconnects behind
  3060.     //        our backs.
  3061.     HCONV hSaveConv = pConv->m_hConv;
  3062.  
  3063.     //    See if we need to save the file.
  3064.     //  The filename was saved in the context some time ago.
  3065.     CString csSaveAs;
  3066.     if((iFormatOut & FO_SAVE_AS) == FO_SAVE_AS)   {
  3067.         if(pContext->save_as_name != NULL)    {
  3068.             csSaveAs = pContext->save_as_name;
  3069.  
  3070.             //    Steal it from the old context.
  3071.             free(pContext->save_as_name);
  3072.             pContext->save_as_name = NULL;
  3073.         }
  3074.         else    {
  3075.             //  There's no name to save it under, so that must mean that the user either
  3076.             //      cancelled a save, or we're simply broken.
  3077.  
  3078.             //  Be sure to get rid of the conversation too.
  3079.             //    Make sure we still have a conversation, if so, delete the object.
  3080.             DdeDisconnect(hSaveConv);
  3081.             pConv = GetConvObj(hSaveConv);
  3082.             if(pConv)    {
  3083.                 delete pConv;
  3084.             }
  3085.  
  3086.             return(FALSE);
  3087.         }
  3088.     }
  3089.     //  Screen types we don't want to handle.
  3090.     else if((iFormatOut & FO_PRESENT) != FO_PRESENT)    {
  3091.         //  Be sure to get rid of the conversation too.
  3092.         //    Make sure we still have a conversation, if so, delete the object.
  3093.         DdeDisconnect(hSaveConv);
  3094.         pConv = GetConvObj(hSaveConv);
  3095.         if(pConv)    {
  3096.             delete pConv;
  3097.         }
  3098.  
  3099.         return(FALSE);
  3100.     }
  3101.     
  3102.     //    Create our argument list.
  3103.     CString csURL = pURL->address;
  3104.     DWORD dwWindowID = FE_GetContextID(pContext);
  3105.     DWORD dwFlags = 0UL;
  3106.     CString csFormData;
  3107.     if(pURL->post_data != NULL)    {
  3108.         csFormData = pURL->post_data;
  3109.     }
  3110.     CString csPostMimeType;
  3111.     if(pURL->post_headers != NULL)    {
  3112.         //    Need to extract the content type.
  3113.         char *pFind = strcasestr(pURL->post_headers, "Content-type:");
  3114.         if(pFind != NULL)    {
  3115.             while(*pFind != ':')    {
  3116.                 pFind++;
  3117.             }
  3118.             pFind++;
  3119.             
  3120.             while(*pFind != '\0' && isspace(*pFind))    {
  3121.                 pFind++;
  3122.             }
  3123.             
  3124.             csPostMimeType = pFind;
  3125.             csPostMimeType = csPostMimeType.SpanExcluding("\r\n");
  3126.         }
  3127.     }
  3128.     CString csProgressApp;    //    leave empty for now.
  3129.     
  3130.     HSZ hszItem = MakeItemArgs("QCS,QCS,DW,DW,QCS,QCS,CS", &csURL, &csSaveAs, &dwWindowID, &dwFlags, &csFormData,
  3131.         &csPostMimeType, &csProgressApp);
  3132.         
  3133.     //    Do the transaction, expect return value.
  3134.     HDDEDATA hData = DdeClientTransaction(NULL, 0L, hSaveConv, hszItem, CF_TEXT,
  3135.         XTYP_REQUEST, m_Timeout, NULL);        
  3136.  
  3137.     //    Cut the cord.
  3138.     DdeFreeStringHandle(m_dwidInst, hszItem);
  3139.     DdeDisconnect(hSaveConv);
  3140.  
  3141.     //    Make sure we still have a conversation, if so, delete the object.
  3142.     pConv = GetConvObj(hSaveConv);
  3143.     if(pConv)    {
  3144.         delete pConv;
  3145.     }
  3146.     
  3147.     //    See if we've gotten a return value.  Failure to give us a value will cause use to unregister the app.
  3148.     if(hData == NULL)    {
  3149.         CDDEProtocolItem::DDEUnRegister(csProtocol, csServiceName);    
  3150.         return(FALSE);
  3151.     }
  3152.     
  3153.     //    We've got a return value.  Determine what it is.
  3154.     DWORD dwRetval;
  3155.     ScanDataArgs(hData, "DW", &dwRetval);
  3156.     DdeFreeDataHandle(hData);
  3157.     
  3158.     //    Check for failure.
  3159.     if(dwRetval == 0 || dwRetval == 0xFFFFFFFFUL)    {
  3160.         return(FALSE);
  3161.     }
  3162.     
  3163.     //    Done.
  3164.     //  Be sure to let the frame know it's not saving any file, regardless, since we
  3165.     //      may have handled it.
  3166.     return(TRUE);
  3167. }
  3168.  
  3169. //    Purpose:    Register a DDE server for URL echo.
  3170. //    Arguments:    hszItem    our arguments.
  3171. //                hData    Disregard, not used.
  3172. //    Returns:    HDDEDATA    Always DDE_FACK, acknowleding that we processed this.
  3173. //    Comments:
  3174. //    Revision History:
  3175. //        01-18-95    created GAB.
  3176. HDDEDATA CDDEWrapper::RegisterURLEcho(HSZ& hszItem, HDDEDATA& hData)
  3177. {
  3178.     //    Scan in our arguments.
  3179.     CString csServiceName;
  3180.     ScanArgs(hszItem, "QCS", &csServiceName);
  3181.  
  3182.     //    Have the URL echo class handle it.
  3183.     CDDEEchoItem::DDERegister(csServiceName);
  3184.  
  3185.     return((HDDEDATA)DDE_FACK);
  3186. }
  3187.  
  3188. //    Purpose:    Unregister a DDE server from URL echo.
  3189. //    Arguments:    hszItem    our arugumetns.
  3190. //                hData    Disregard.
  3191. //    Returns:    HDDEDATA    always DDE_FACK, unless invalid
  3192. //    Comments:
  3193. //    Revision History:
  3194. //        01-18-95    created GAB
  3195. HDDEDATA CDDEWrapper::UnRegisterURLEcho(HSZ& hszItem, HDDEDATA& hData)
  3196. {
  3197.     //    Scan in our arguments.
  3198.     CString csServiceName;
  3199.     ScanArgs(hszItem, "QCS", &csServiceName);
  3200.  
  3201.     //    Have the URL echo class handle it.
  3202.     if(CDDEEchoItem::DDEUnRegister(csServiceName) == TRUE)  {
  3203.         return((HDDEDATA)DDE_FACK);
  3204.     }
  3205.  
  3206.     return((HDDEDATA)DDE_FNOTPROCESSED);
  3207. }
  3208.  
  3209. //    Purpose:    Echo a URL event to a server.
  3210. //    Arguments:    pItem    The Echo object causing this (so we can get our service name out of it, and anything else.
  3211. //                csURL    The url loaded.
  3212. //                csMimeType    The mime type of the url.
  3213. //                dwWindowID    The window performing the load.
  3214. //                csReferrer    The referrer URL.
  3215. //    Returns:    void
  3216. //    Comments:
  3217. //    Revision History:
  3218. //        01-18-95    created GAB
  3219. void CDDEWrapper::URLEcho(CDDEEchoItem *pItem, CString& csURL, CString& csMimeType, DWORD dwWindowID, CString& csReferrer)
  3220. {
  3221.     //    Get the server name.
  3222.     CString csServiceName = pItem->GetServiceName();
  3223.     
  3224.     //    Establish the connection to homeworld.
  3225.     CDDEWrapper *pConv = ClientConnect(csServiceName, m_hsz[m_URLEcho]);
  3226.  
  3227.     if(pConv == NULL)    {
  3228.         //    Well, Doh!, the server isn't responding.
  3229.         //    Disable it from further being our registered app.
  3230.         CDDEEchoItem::DDEUnRegister(csServiceName);
  3231.         
  3232.         //    There's not much else we can do here, simply return.
  3233.         return;
  3234.     }
  3235.     
  3236.     //    Save the conversation, in case the DDE server disconnects behind
  3237.     //        our backs.
  3238.     HCONV hSaveConv = pConv->m_hConv;
  3239.  
  3240.     //    Create our argument list.
  3241.     HSZ hszItem = MakeItemArgs("QCS,QCS,DW,QCS", &csURL, &csMimeType, &dwWindowID, &csReferrer);
  3242.         
  3243.     //    Do the transaction, expect nothing.
  3244.     DdeClientTransaction(NULL, 0L, hSaveConv, hszItem, CF_TEXT,
  3245.         XTYP_POKE, m_Timeout, NULL);
  3246.  
  3247.     //    Cut the cord.
  3248.     DdeFreeStringHandle(m_dwidInst, hszItem);
  3249.     DdeDisconnect(hSaveConv);
  3250.  
  3251.     //    Make sure we still have a conversation, if so, delete the object.
  3252.     pConv = GetConvObj(hSaveConv);
  3253.     if(pConv)    {
  3254.         delete pConv;
  3255.     }
  3256. }
  3257.  
  3258. //    Purpose:    Register a DDE server to monitor a certain window's close.
  3259. //    Arguments:    hszItem    the argumetns, the server and the window
  3260. //    Returns:    HDDEDATA    TRUE or FALSE, FALSE there was no window.
  3261. //    Comments:
  3262. //    Revision History:
  3263. //        01-19-95    created GAB
  3264. //
  3265. //    Purpose:    Register a particular DDE server to handle URLs of a particular type.
  3266. //    Arguments:    hszItem    Arguments, see below.
  3267. //    Returns:    HDDEDATA    dwWindowID
  3268. //    Comments:
  3269. //    Revision History:
  3270. //        01-18-95    created GAB
  3271. HDDEDATA CDDEWrapper::RegisterWindowChange(HSZ& hszItem)
  3272. {
  3273.     //    Get our arguments.
  3274.     CString csServer;
  3275.     DWORD dwWindowID;
  3276.     ScanArgs(hszItem, "QCS,DW", &csServer, &dwWindowID);
  3277.     
  3278.     //    If server is empty, we'll just fail.
  3279.     if(csServer.IsEmpty())    {
  3280.         return(NULL);
  3281.     }
  3282.  
  3283.     //    Sign up to watch the window, this possibly fails.
  3284.     if(FALSE == CDDEWindowChangeItem::DDERegister(csServer, dwWindowID))    {
  3285.         dwWindowID = 0;
  3286.     }
  3287.  
  3288.     
  3289.     return(MakeArgs("DW", &dwWindowID));
  3290. }
  3291.  
  3292. //    Purpose:    Unregister a window to be monitored.
  3293. //    Arguments:    hszItem    The arguments, the server ,and the windowID.
  3294. //    Returns:    HDDEDATA TRUE or FALSE, FALSE there was no prior registration.
  3295. //    Comments:    
  3296. //    Revision History:
  3297. //        01-19-95    created GAB
  3298. HDDEDATA CDDEWrapper::UnRegisterWindowChange(HSZ& hszItem)
  3299. {
  3300.     //    Get our arguments.
  3301.     CString csServer;
  3302.     DWORD dwWindowID;
  3303.     ScanArgs(hszItem, "QCS,DW", &csServer, &dwWindowID);
  3304.     
  3305.     //    If server is empty, we'll just fail.
  3306.     if(csServer.IsEmpty())    {
  3307.         return(NULL);
  3308.     }
  3309.  
  3310.     //    Sign up to watch the window, this possibly fails.
  3311.     TwoByteBool bRetval = CDDEWindowChangeItem::DDEUnRegister(csServer, dwWindowID);    
  3312.     
  3313.     return(MakeArgs("BL", &bRetval));
  3314. }
  3315.  
  3316. //    Purpose:    Send a message to the registere monitoring server that the window is chaning.
  3317. //    Arguments:    pItem    The registry of window close monitors.
  3318. //              iChange The type of change ocurring.
  3319. //                bExiting    Wether or not we believe Netscape is actually exiting.
  3320. //              dwX The X position of the window.
  3321. //              dwY The Y position of the window.
  3322. //              dwCX    The width of the window.
  3323. //              dwCY    The height of the window.
  3324. //    Returns:    void
  3325. //    Comments:
  3326. //    Revision History:
  3327. //        01-19-95    created GAB
  3328. //      02-01-95    modified extensively to handle multiple different types of window actions.
  3329. void CDDEWrapper::WindowChange(CDDEWindowChangeItem *pItem, int iChange, TwoByteBool bExiting, DWORD dwX, DWORD dwY, DWORD dwCX, DWORD dwCY)
  3330. {
  3331.     //    Get the server name.
  3332.     CString csServiceName = pItem->GetServiceName();
  3333.     
  3334.     //    Establish the connection to homeworld.
  3335.     CDDEWrapper *pConv = ClientConnect(csServiceName, m_hsz[m_WindowChange]);
  3336.  
  3337.     if(pConv == NULL)    {
  3338.         //    Well, Doh!, the server isn't responding.
  3339.         //    There's not much else we can do here, simply return.
  3340.         //    Unregistration happens elsewhere.
  3341.         return;
  3342.     }
  3343.     
  3344.     //    Save the conversation, in case the DDE server disconnects behind
  3345.     //        our backs.
  3346.     HCONV hSaveConv = pConv->m_hConv;
  3347.  
  3348.     //  Construct the flags for the call, and our calling format.
  3349.     DWORD dwFlags = 0;
  3350.     const char *pFormat;
  3351.     switch(iChange) {
  3352.         case CDDEWindowChangeItem::m_Close: {
  3353.             dwFlags |= 0x00000010UL;
  3354.             if(bExiting == TRUE)    {
  3355.                 dwFlags |= 0x00010000UL;
  3356.             }
  3357.             pFormat = "DW,DW";
  3358.             break;
  3359.         }
  3360.         case CDDEWindowChangeItem::m_Size:  {
  3361.             dwFlags |= 0x00000001UL;
  3362.             pFormat = "DW,DW,DW,DW,DW,DW";
  3363.             break;
  3364.         }
  3365.         case CDDEWindowChangeItem::m_Maximize:  {
  3366.             dwFlags |= 0x00000002UL;
  3367.             pFormat = "DW,DW";
  3368.             break;
  3369.         }
  3370.         case CDDEWindowChangeItem::m_Minimize:  {
  3371.             dwFlags |= 0x00000008UL;
  3372.             pFormat = "DW,DW";
  3373.             break;
  3374.         }
  3375.         case CDDEWindowChangeItem::m_Normalize: {
  3376.             dwFlags |= 0x00000004UL;
  3377.             pFormat = "DW,DW";
  3378.             break;
  3379.         }
  3380.         default:    {
  3381.             //  Not handled, this is bad.
  3382.             pFormat = "DW,DW";
  3383.             ASSERT(0);
  3384.             break;
  3385.         }
  3386.     }
  3387.  
  3388.     //    Create our argument list.
  3389.     DWORD dwWindowID = pItem->GetWindowID();
  3390.     HSZ hszItem = MakeItemArgs(pFormat, &dwWindowID, &dwFlags, &dwX, &dwY, &dwCX, &dwCY);
  3391.         
  3392.     //    Do the transaction, expect nothing.
  3393.     DdeClientTransaction(NULL, 0L, hSaveConv, hszItem, CF_TEXT,
  3394.         XTYP_POKE, m_Timeout, NULL);
  3395.  
  3396.     //    Cut the cord.
  3397.     DdeFreeStringHandle(m_dwidInst, hszItem);
  3398.     DdeDisconnect(hSaveConv);
  3399.  
  3400.     //    Make sure we still have a conversation, if so, delete the object.
  3401.     pConv = GetConvObj(hSaveConv);
  3402.     if(pConv)    {
  3403.         delete pConv;
  3404.     }
  3405. }
  3406.  
  3407. //    Purpose:    Retrieves a file from the local file system and displays it in a given frame.
  3408. //    Arguments:    hszArgs    A string representing our real parameters.
  3409. //    Returns:    HDDEDATA    Returns the actual WindowID of the window
  3410. //                                the performed the open, where 0 means
  3411. //                                the operation failed, and 0xFFFFFFFF
  3412. //                                means the data was not of an appropriate
  3413. //                                MIME type to display in a Web browser....
  3414. //    Comments:    Parameters within hszItem are
  3415. //        qcsFileName    the file on the local file system that Netscape should attempt to load.
  3416. //        qcsMimeType is the mime type of the file.
  3417. //        dwWindowID is the Netscape window in which to perform the load.
  3418. //            A value of 0x0 requests Netscape to load into a new window.
  3419. //            A value of 0xFFFFFFFF requests Netscape to load into the last active window.
  3420. //        qcsURL is the original URL of the document to reload if necessary.  Will only attempt if can't
  3421. //            open the file for reading.
  3422. //    Revision History:
  3423. //        01-19-95    created GAB
  3424. HDDEDATA CDDEWrapper::ShowFile(HSZ& hszArgs)
  3425. {
  3426.     DWORD dwReturn = 0L;
  3427.     
  3428.     //    Obtain our arguments.
  3429.     CString csFileName;
  3430.     CString csMimeType;
  3431.     DWORD dwWindowID;
  3432.     CString csURL;
  3433.     ScanArgs(hszArgs, "QCS,QCS,DW,QCS", &csFileName, &csMimeType, &dwWindowID, &csURL);
  3434.         
  3435.     //    Get the appropriate window.
  3436.     if(dwWindowID == 0)    {
  3437.         //    They want a new window.
  3438.         if(NULL != CFE_CreateNewDocWindow(NULL, NULL))    {
  3439.             //    Window ID is no longer 0.
  3440.             dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
  3441.         }
  3442.     }
  3443.     else if(dwWindowID == 0xFFFFFFFF)    {
  3444.         //    They want the current frame....
  3445.         //    See if we even have one.
  3446.         if(XP_ContextCount(MWContextBrowser, TRUE) == 0)    {
  3447.             if(NULL != CFE_CreateNewDocWindow(NULL, NULL))    {
  3448.                 dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
  3449.             }
  3450.             else    {
  3451.                 dwWindowID = 0;
  3452.             }
  3453.         }
  3454.         else    {
  3455.             if(FEU_GetLastActiveFrame(MWContextBrowser) != NULL)    {
  3456.                 //    Should be safe.
  3457.                 dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
  3458.             }
  3459.             else    {
  3460.                 dwWindowID = 0;
  3461.                 if(NULL != CFE_CreateNewDocWindow(NULL, NULL))    {
  3462.                     dwWindowID = FEU_GetLastActiveFrameID(MWContextBrowser);
  3463.                 }
  3464.             }
  3465.         }
  3466.     }
  3467.     else    {
  3468.         //    They are requesting a specific frame.
  3469.         //    See if we've got it.
  3470.         if(FEU_FindFrameByID(dwWindowID, MWContextBrowser) == NULL)    {
  3471.             dwWindowID = 0;
  3472.         }
  3473.     }
  3474.     
  3475.     CAbstractCX *pCX = NULL;
  3476.     if(dwWindowID)  {
  3477.         pCX = CAbstractCX::FindContextByID(dwWindowID);
  3478.         if(NULL == pCX ||
  3479.             pCX->IsDestroyed() ||
  3480.             pCX->IsFrameContext() == FALSE ||
  3481.             pCX->GetContext()->type != MWContextBrowser)   {
  3482.             dwWindowID = 0;
  3483.             pCX = NULL;
  3484.         }
  3485.     }
  3486.  
  3487.     //    See if the window exists, a value of 0 means failure at this
  3488.     //        point.
  3489.     if(dwWindowID == 0)    {
  3490.         //    Well, either the window didn't exist, or we couldn't create
  3491.         //        a new window.
  3492.         return(MakeArgs("DW", &dwWindowID));
  3493.     }
  3494.     
  3495.     //    So far so good.  Our current return value will be the window ID,
  3496.     //        until another failure further along.
  3497.     dwReturn = dwWindowID;
  3498.     
  3499.     //    Create the URL structure to load up the URL.
  3500.     //    We do this first by seeing if we can access the file, if so go on, and if
  3501.     //        not use the URL that they presented us with.
  3502.     URL_Struct *pURL = NULL;
  3503.     if(_access(csFileName, 0x4) == -1)    {
  3504.         //    Use the URL
  3505.         pURL = NET_CreateURLStruct(csURL, NET_DONT_RELOAD);
  3506.     }
  3507.     else    {
  3508.         //    Use the file name.
  3509.         CString csURL;
  3510.         WFE_ConvertFile2Url(csURL, csFileName);
  3511.         pURL = NET_CreateURLStruct(csURL, NET_DONT_RELOAD);    
  3512.     }
  3513.     
  3514.     //    Manually assign in the mime type of the URL struct.
  3515.     if(csMimeType.IsEmpty() == FALSE)    {
  3516.         pURL->content_type = strdup(csMimeType);
  3517.     }
  3518.     
  3519.     //    Have the URL load.  We simply can't block our return value until
  3520.     //        all connections are completed for the window because we
  3521.     //        hose all the messaging.
  3522.     pCX->GetUrl(pURL, FO_CACHE_AND_PRESENT);
  3523.     
  3524.     return(MakeArgs("DW", &dwReturn));
  3525. }
  3526.  
  3527. //    Purpose:    Change our window position/attributes.
  3528. //    Arguments:  hszItem Our arguments.
  3529. //              hData   Data, ignored.
  3530. //    Returns:    HDDEDATA    TRUE or FALSE, depending on successful completion.
  3531. //    Comments:   This should probably by XTYP_REQUEST, as they may specify an invalid window ID, but they get the candy they want.
  3532. //              They could always check for valid IDs themselves.
  3533. //    Revision History:
  3534. //      02-01-95    created GAB
  3535. HDDEDATA CDDEWrapper::WindowChange(HSZ& hszItem, HDDEDATA& hData)
  3536. {
  3537.     //  Scan in our argumetnts.
  3538.     DWORD dwWindowID;
  3539.     DWORD dwFlags;
  3540.     DWORD dwX;
  3541.     DWORD dwY;
  3542.     DWORD dwCX;
  3543.     DWORD dwCY;
  3544.  
  3545.     ScanArgs(hszItem, "DW,DW,DW,DW,DW,DW", &dwWindowID, &dwFlags, &dwX, &dwY, &dwCX, &dwCY);
  3546.  
  3547.     //  Figure out if the frame exists.
  3548.     CAbstractCX *pCX = CAbstractCX::FindContextByID(dwWindowID);
  3549.     CFrameWnd *pFrame =  FEU_FindFrameByID(dwWindowID);
  3550.     if(pFrame == NULL || dwWindowID == 0 || NULL == pCX || pCX->IsGridCell())  {
  3551.         return((HDDEDATA)DDE_FNOTPROCESSED);
  3552.     }
  3553.  
  3554.     TwoByteBool bDidSomething = FALSE;
  3555.  
  3556.     //  Figure out, via the flags, what in the hell we are doing.
  3557.     if(dwFlags & 0x00000001UL)  {
  3558.         //  We're changing size.
  3559.         //  X and Y are always significant, though the others may not be....
  3560.         if(dwCX == 0)   {
  3561.             //  Determine what this should really be.
  3562.             RECT rDim;
  3563.             pFrame->GetWindowRect(&rDim);
  3564.             dwCX = rDim.right - rDim.left;
  3565.         }
  3566.         if(dwCY == 0)   {
  3567.             //  Determine what this should really be.
  3568.             RECT rDim;
  3569.             pFrame->GetWindowRect(&rDim);
  3570.             dwCX = rDim.bottom - rDim.top;
  3571.         }
  3572.  
  3573.         pFrame->MoveWindow(CASTINT(dwX), CASTINT(dwY), CASTINT(dwCX), CASTINT(dwCY));
  3574.         bDidSomething = TRUE;
  3575.     }
  3576.  
  3577.     if(dwFlags & 0x00000002UL)  {
  3578.         //  We're maximizing.
  3579.         pFrame->ShowWindow(SW_SHOWMAXIMIZED);
  3580.         bDidSomething = TRUE;
  3581.     }
  3582.  
  3583.     if(dwFlags & 0x00000004UL)  {   
  3584.         //  We're normalizing.
  3585.         pFrame->ShowWindow(SW_SHOWNORMAL);
  3586.         bDidSomething = TRUE;
  3587.     }
  3588.  
  3589.     if(dwFlags & 0x00000008UL)    {
  3590.         //  We're minimizing.
  3591.         pFrame->ShowWindow(SW_MINIMIZE);
  3592.         bDidSomething = TRUE;
  3593.     }
  3594.  
  3595.     if(dwFlags & 0x00000010UL)  {
  3596.         //  We're closing.
  3597.         pFrame->PostMessage(WM_CLOSE);
  3598.         bDidSomething = TRUE;
  3599.     }
  3600.  
  3601.     if(bDidSomething == TRUE)   {
  3602.         return((HDDEDATA)DDE_FACK);
  3603.     }
  3604.     else    {
  3605.         return((HDDEDATA)DDE_FNOTPROCESSED);
  3606.     }
  3607. }
  3608.  
  3609. //    Purpose:    Pure hell.
  3610. //    Arguments:  hszItem The arguments, the transaction ID to stop loading.
  3611. //              hData is ignored.
  3612. //    Returns:    HDDEDATA    TRUE, always work.
  3613. //    Comments:   We need to traverse all windows, hence all frames, and then documents, to find out the Transaction ID.
  3614. //    Revision History:
  3615. //      02-01-95    created GAB
  3616. //        10-17-95    Modified to search for the transaction ID in a different manner.
  3617. HDDEDATA CDDEWrapper::CancelProgress(HSZ& hszItem, HDDEDATA& hData)
  3618. {
  3619.     //  Get the argument.
  3620.     DWORD dwTransactionID;
  3621.     ScanArgs(hszItem, "DW", &dwTransactionID);
  3622.  
  3623.  
  3624.     //    Go through all contexts, searching for the one with the specific
  3625.     //        transaction ID.
  3626.     int iTraverseIndex;
  3627.     MWContext *pTraverseContext = NULL;
  3628.     CAbstractCX *pTraverseCX = NULL;
  3629.     XP_List *pTraverse = XP_GetGlobalContextList();
  3630.     while (pTraverseContext = (MWContext *)XP_ListNextObject(pTraverse)) {
  3631.         if(pTraverseContext != NULL && ABSTRACTCX(pTraverseContext) != NULL)    {
  3632.             pTraverseCX = ABSTRACTCX(pTraverseContext);
  3633.  
  3634.             if(pTraverseCX->m_pNcapiUrlData != NULL)    {
  3635.                 if(pTraverseCX->m_pNcapiUrlData->GetTransactionID())    {
  3636.                     if(pTraverseCX->m_pNcapiUrlData->GetTransactionID() == dwTransactionID)    {
  3637.                         //    Found it, cancel it.
  3638.                         pTraverseCX->Interrupt();
  3639.                         return((HDDEDATA)DDE_FACK);
  3640.                     }
  3641.                 }
  3642.             }
  3643.         }
  3644.     }
  3645.  
  3646.     //    Not found, not valid.
  3647.     return((HDDEDATA)DDE_FNOTPROCESSED);
  3648. }
  3649.  
  3650. HDDEDATA CDDEWrapper::ListFrameChildren(HSZ& hszItem)
  3651. {
  3652.     HDDEDATA hRetval = NULL;
  3653.     DWORD dwCXID;
  3654.     ScanArgs(hszItem, "DW", &dwCXID);
  3655.  
  3656.     CWinCX *pCX = GetContext(dwCXID);
  3657.     if(pCX && pCX->IsGridParent()) {
  3658.         XP_List *pChildren = pCX->GetContext()->grid_children;
  3659.         DWORD dwCount = XP_ListCount(pChildren);
  3660.         if(dwCount) {
  3661.             //  Allocate a buffer for the children IDs.
  3662.             DWORD *pBuf = new DWORD[dwCount + 1];
  3663.             if(pBuf)    {
  3664.                 memset(pBuf, 0, CASTSIZE_T(sizeof(DWORD) * (dwCount + 1)));
  3665.  
  3666.                 //  Go through the list figuring out the context ID and
  3667.                 //      assigning it in.
  3668.                 void *pTraverse;
  3669.                 DWORD dwIndex = 0;
  3670.                 while(pTraverse = XP_ListNextObject(pChildren)) {
  3671.                     CWinCX *pChildCX = WINCX(((MWContext *)pTraverse));
  3672.                     pBuf[dwIndex] = pChildCX->GetContextID();
  3673.                     dwIndex++;
  3674.                 }
  3675.  
  3676.                 //  Convert
  3677.                 hRetval = DdeCreateDataHandle(
  3678.                     m_dwidInst,
  3679.                     (unsigned char *)pBuf,
  3680.                     (dwCount + 1) * sizeof(DWORD),
  3681.                     0,
  3682.                     m_hsz[m_ServiceName],
  3683.                     CF_TEXT, 0);
  3684.  
  3685.                 delete [] pBuf;
  3686.                 pBuf = NULL;
  3687.             }
  3688.         }
  3689.     }
  3690.  
  3691.     return(hRetval);
  3692. }
  3693.  
  3694. HDDEDATA CDDEWrapper::GetFrameParent(HSZ& hszItem)
  3695. {
  3696.     DWORD dwCXID;
  3697.     ScanArgs(hszItem, "DW", &dwCXID);
  3698.  
  3699.     CWinCX *pCX = GetContext(dwCXID);
  3700.     if(pCX && pCX->IsGridCell()) {
  3701.         DWORD dwParentID = WINCX(pCX->GetParentContext())->GetContextID();
  3702.         return(MakeArgs("DW", &dwParentID));
  3703.     }
  3704.  
  3705.     return(NULL);
  3706. }
  3707.  
  3708. HDDEDATA CDDEWrapper::RegisterStatusBarChange(HSZ& hszItem)
  3709. {
  3710.     //    Get our arguments.
  3711.     CString csServer;
  3712.     DWORD dwWindowID;
  3713.     ScanArgs(hszItem, "QCS,DW", &csServer, &dwWindowID);
  3714.     
  3715.     //    If server is empty, we'll just fail.
  3716.     if(csServer.IsEmpty())    {
  3717.         return(NULL);
  3718.     }
  3719.  
  3720.     if(FALSE == CDDEStatusBarChangeItem::DDERegister(csServer, dwWindowID))    {
  3721.         dwWindowID = 0;
  3722.     }
  3723.     
  3724.     return(MakeArgs("DW", &dwWindowID));
  3725. }
  3726.  
  3727. HDDEDATA CDDEWrapper::UnRegisterStatusBarChange(HSZ& hszItem)
  3728. {
  3729.     //    Get our arguments.
  3730.     CString csServer;
  3731.     DWORD dwWindowID;
  3732.     ScanArgs(hszItem, "QCS,DW", &csServer, &dwWindowID);
  3733.     
  3734.     //    If server is empty, we'll just fail.
  3735.     if(csServer.IsEmpty())    {
  3736.         return(NULL);
  3737.     }
  3738.  
  3739.     TwoByteBool bRetval = CDDEStatusBarChangeItem::DDEUnRegister(csServer, dwWindowID);    
  3740.     
  3741.     return(MakeArgs("BL", &bRetval));
  3742. }
  3743.  
  3744. void CDDEWrapper::StatusBarChange(CDDEStatusBarChangeItem *pItem, LPCSTR lpStatusMsg)
  3745. {
  3746.     CString csStatusMsg = lpStatusMsg;
  3747.  
  3748.     //    Get the server name.
  3749.     CString csServiceName = pItem->GetServiceName();
  3750.     
  3751.     //    Establish the connection to homeworld.
  3752.     CDDEWrapper *pConv = ClientConnect(csServiceName, m_hsz[m_StatusBarChange]);
  3753.  
  3754.     if(pConv == NULL)    {
  3755.         //    The server isn't responding.
  3756.         //    There's not much else we can do here, simply return.
  3757.         //    Unregistration happens elsewhere.
  3758.         return;
  3759.     }
  3760.     
  3761.     //    Save the conversation, in case the DDE server disconnects behind
  3762.     //        our backs.
  3763.     HCONV hSaveConv = pConv->m_hConv;
  3764.  
  3765.     //  Construct the flags for the call, and our calling format.
  3766.     DWORD dwFlags = 0;
  3767.     const char *pFormat = "DW,QCS";
  3768.  
  3769.     //    Create our argument list.
  3770.     DWORD dwWindowID = pItem->GetWindowID();
  3771.     HSZ hszItem = MakeItemArgs(pFormat, &dwWindowID, &csStatusMsg);
  3772.         
  3773.     //    Do the transaction, expect nothing.
  3774.     DdeClientTransaction(NULL, 0L, hSaveConv, hszItem, CF_TEXT,
  3775.         XTYP_POKE, m_Timeout, NULL);
  3776.  
  3777.     //    Cut the cord.
  3778.     DdeFreeStringHandle(m_dwidInst, hszItem);
  3779.     DdeDisconnect(hSaveConv);
  3780.  
  3781.     //    Make sure we still have a conversation, if so, delete the object.
  3782.     pConv = GetConvObj(hSaveConv);
  3783.     if(pConv)    {
  3784.         delete pConv;
  3785.     }
  3786. }
  3787.  
  3788. //Returns : 
  3789. //        0  - If incorrect WindowID 
  3790. //       -1  - If Can't go back
  3791. //       ID  - Id of window on which the operation was performed
  3792. HDDEDATA CDDEWrapper::NavigateBack(HSZ& hszItem)
  3793. {
  3794.     DWORD ReturnID = 0x0;
  3795.  
  3796.     //    Retrieve our arguments.
  3797.     DWORD WindowID;
  3798.     ScanArgs(hszItem, "DW", &WindowID);
  3799.  
  3800.    if (WindowID == 0xFFFFFFFF)
  3801.        WindowID = fetchLastActiveWindow();
  3802.  
  3803.    if(WindowID != 0x0)    
  3804.     {
  3805.         //    See if it's a valid Window ID
  3806.         CFrameGlue *pFrame = CFrameGlue::FindFrameByID(WindowID, MWContextBrowser);
  3807.         if(pFrame != NULL)    
  3808.         {
  3809.             MWContext *pContext = (pFrame->GetMainContext() != NULL) ? pFrame->GetMainContext()->GetContext() : NULL;
  3810.             if(pContext != NULL)    
  3811.             {
  3812.                 if(ABSTRACTCX(pContext)->CanAllBack())
  3813.                 {
  3814.                   ABSTRACTCX(pContext)->AllBack();
  3815.                   ReturnID = WindowID;
  3816.                 }
  3817.             }
  3818.         }
  3819.     }
  3820.  
  3821.     HDDEDATA hData = MakeArgs("DW", &ReturnID);
  3822.     return(hData);
  3823. }
  3824.  
  3825. //Returns : 
  3826. //        0  - If incorrect WindowID 
  3827. //       -1  - If Can't go forward
  3828. //       ID  - Id of window on which the operation was performed
  3829. HDDEDATA CDDEWrapper::NavigateForward(HSZ& hszItem)
  3830. {
  3831.     DWORD ReturnID = 0x0;
  3832.  
  3833.     //    Retrieve our arguments.
  3834.     DWORD WindowID;
  3835.     ScanArgs(hszItem, "DW", &WindowID);
  3836.  
  3837.    if (WindowID == 0xFFFFFFFF)
  3838.        WindowID = fetchLastActiveWindow();
  3839.  
  3840.    if(WindowID != 0x0)    
  3841.     {
  3842.         //    See if it's a valid Window ID
  3843.         CFrameGlue *pFrame = CFrameGlue::FindFrameByID(WindowID, MWContextBrowser);
  3844.         if(pFrame != NULL)    
  3845.         {
  3846.             MWContext *pContext = (pFrame->GetMainContext() != NULL) ? pFrame->GetMainContext()->GetContext() : NULL;
  3847.             if(pContext != NULL)    
  3848.             {
  3849.                 if(ABSTRACTCX(pContext)->CanAllForward())
  3850.                 {
  3851.                     ABSTRACTCX(pContext)->AllForward();
  3852.                     //Success, set the return value.
  3853.                     ReturnID = WindowID;
  3854.                 }
  3855.                 //else
  3856.                 // ReturnID = 0xFFFFFFFF;
  3857.             }
  3858.         }
  3859.     }
  3860.  
  3861.     HDDEDATA hData = MakeArgs("DW", &ReturnID);
  3862.     return(hData);
  3863. }
  3864.  
  3865. //Returns : 
  3866. //        0  - If incorrect WindowID 
  3867. //       -1  - If Can't Stop
  3868. //       ID  - Id of window on which the operation was performed
  3869. HDDEDATA CDDEWrapper::Stop(HSZ& hszItem)
  3870. {
  3871.     DWORD ReturnID = 0L;
  3872.  
  3873.     //    Retrieve our arguments.
  3874.     DWORD WindowID;
  3875.     ScanArgs(hszItem, "DW", &WindowID);
  3876.  
  3877.     if (WindowID == 0xFFFFFFFF)
  3878.        WindowID = fetchLastActiveWindow();
  3879.  
  3880.    if(WindowID != 0x0)    
  3881.     {
  3882.         //    See if it's a valid Window ID
  3883.         CFrameGlue *pFrame = CFrameGlue::FindFrameByID(WindowID, MWContextBrowser);
  3884.         if(pFrame != NULL)    
  3885.         {
  3886.             MWContext *pContext = (pFrame->GetMainContext() != NULL) ? pFrame->GetMainContext()->GetContext() : NULL;
  3887.             if(pContext != NULL)    
  3888.             {
  3889.                 if(ABSTRACTCX(pContext)->CanAllInterrupt())
  3890.                 {
  3891.                     ABSTRACTCX(pContext)->AllInterrupt();
  3892.                     //Success, set the return value.
  3893.                     ReturnID = WindowID;
  3894.                 }
  3895.                 else
  3896.                     ReturnID = 0xFFFFFFFF;
  3897.             }
  3898.         }
  3899.     }
  3900.  
  3901.     HDDEDATA hData = MakeArgs("DW", &ReturnID);
  3902.     return(hData);
  3903. }
  3904.  
  3905. //Returns : 
  3906. //        0  - If incorrect WindowID 
  3907. //       -1  - If Can't Reload
  3908. //       ID  - Id of window on which the operation was performed
  3909. HDDEDATA CDDEWrapper::Reload(HSZ& hszItem)
  3910. {
  3911.     DWORD ReturnID = 0L;
  3912.  
  3913.     //    Retrieve our arguments.
  3914.     DWORD WindowID;
  3915.     ScanArgs(hszItem, "DW", &WindowID);
  3916.  
  3917.     if (WindowID == 0xFFFFFFFF)
  3918.        WindowID = fetchLastActiveWindow();
  3919.  
  3920.    if(WindowID != 0x0)    
  3921.     {
  3922.         //    See if it's a valid Window ID
  3923.         CFrameGlue *pFrame = CFrameGlue::FindFrameByID(WindowID, MWContextBrowser);
  3924.         if(pFrame != NULL)    
  3925.         {
  3926.             MWContext *pContext = (pFrame->GetMainContext() != NULL) ? pFrame->GetMainContext()->GetContext() : NULL;
  3927.             if(pContext != NULL)    
  3928.             {
  3929.                 if(ABSTRACTCX(pContext)->CanAllReload())
  3930.                 {
  3931.                     ABSTRACTCX(pContext)->AllReload();
  3932.                     //Success, set the return value.
  3933.                     ReturnID = WindowID;
  3934.                 }
  3935.                 else
  3936.                     ReturnID = 0xFFFFFFFF;
  3937.             }
  3938.         }
  3939.     }
  3940.  
  3941.     HDDEDATA hData = MakeArgs("DW", &ReturnID);
  3942.     return(hData);
  3943. }
  3944.  
  3945. //Returns : 
  3946. //        0  - If incorrect WindowID 
  3947. //       -1  - If Can't Reload
  3948. //       ID  - Id of window on which the operation was performed
  3949. HDDEDATA CDDEWrapper::UserAgent(HSZ& hszItem)
  3950. {
  3951.     CString csVersion = theApp.ResolveAppVersion();
  3952.     return MakeArgs("QCS", &csVersion);
  3953. }
  3954.  
  3955. HDDEDATA CDDEWrapper::ClearCache(HSZ& hszItem)
  3956. {
  3957.     TwoByteBool returnVal = FALSE;
  3958.  
  3959.     int32 nSize;
  3960.  
  3961.     // This would fail if the pref were locked, but it's what is done
  3962.     // in the prefs dialog
  3963.     if (!PREF_PrefIsLocked("browser.cache.disk_cache_size"))
  3964.     {
  3965.       PREF_GetIntPref("browser.cache.disk_cache_size", &nSize);
  3966.       PREF_SetIntPref("browser.cache.disk_cache_size", 0);
  3967.       PREF_SetIntPref("browser.cache.disk_cache_size", nSize);
  3968.       returnVal = TRUE;
  3969.     }
  3970.  
  3971.     return MakeArgs("BL", &returnVal);
  3972. }
  3973.  
  3974. HDDEDATA CDDEWrapper::InCache(HSZ& hszItem)
  3975. {
  3976.     TwoByteBool retVal = FALSE;
  3977.     CString url;
  3978.     ScanArgs(hszItem, "QCS", &url);
  3979.  
  3980.     URL_Struct* url_s = NET_CreateURLStruct(url, NET_NORMAL_RELOAD); 
  3981.     int i;
  3982.     if (url_s) 
  3983.     {
  3984.         i = NET_FindURLInCache(url_s, NULL);
  3985.     }
  3986.     
  3987.     retVal = (i != 0);
  3988.  
  3989.     NET_FreeURLStruct(url_s);
  3990.  
  3991.     return MakeArgs("BL", &retVal);
  3992. }
  3993.  
  3994. HDDEDATA CDDEWrapper::CacheFilename(HSZ& hszItem)
  3995. {
  3996.     CString retVal = "";
  3997.     CString url;
  3998.     ScanArgs(hszItem, "QCS", &url);
  3999.  
  4000.     URL_Struct* url_s = NET_CreateURLStruct(url, NET_NORMAL_RELOAD); 
  4001.     if (url_s) 
  4002.     { 
  4003.         NET_FindURLInCache(url_s, NULL); 
  4004.     }
  4005.     if (url_s && url_s->cache_file && *url_s->cache_file)
  4006.     {
  4007.         retVal = WH_FileName(url_s->cache_file, xpCache);
  4008.     }
  4009.     
  4010.     
  4011.     NET_FreeURLStruct(url_s);
  4012.  
  4013.     return MakeArgs("QCS", &retVal);
  4014. }
  4015.  
  4016. HDDEDATA CDDEWrapper::CacheRemoveURL(HSZ& hszItem)
  4017. {
  4018.     TwoByteBool retVal = FALSE;
  4019.     CString url;
  4020.     ScanArgs(hszItem, "QCS", &url);
  4021.  
  4022.     URL_Struct* url_s = NET_CreateURLStruct(url, NET_NORMAL_RELOAD); 
  4023.     if (url_s) 
  4024.     {
  4025.         NET_RemoveURLFromCache(url_s);
  4026.         retVal = TRUE;
  4027.     }
  4028.  
  4029.     NET_FreeURLStruct(url_s);
  4030.  
  4031.  
  4032.     return MakeArgs("BL", &retVal);
  4033. }
  4034.  
  4035. HDDEDATA CDDEWrapper::CacheAddURL(HSZ& hszItem)
  4036. {
  4037.     TwoByteBool retVal = FALSE;
  4038.     CString url;
  4039.  
  4040.     ScanArgs(hszItem, "QCS", &url);
  4041.     CAbstractCX* theContext = CAbstractCX::FindContextByID(fetchLastActiveWindow());
  4042.     MWContext* mwContext = theContext->GetContext();
  4043.     URL_Struct* url_s = NET_CreateURLStruct(url, NET_NORMAL_RELOAD); 
  4044.     if (url_s) 
  4045.     {
  4046.         // Fetch and cache only
  4047.         ABSTRACTCX(mwContext)->GetUrl(url_s, FO_CACHE_ONLY);
  4048.         retVal = TRUE;
  4049.     }
  4050.  
  4051.     return MakeArgs("BL", &retVal);
  4052. }
  4053.  
  4054. HDDEDATA CDDEWrapper::ClearHistory(HSZ& hszItem)
  4055. {
  4056.     TwoByteBool returnVal = FALSE;
  4057.  
  4058.     int32 nSize;
  4059.  
  4060.     // This would fail if the pref were locked, but it's what is done
  4061.     // in the prefs dialog
  4062.     if (!PREF_PrefIsLocked("browser.link_expiration"))
  4063.     {
  4064.       PREF_GetIntPref("browser.link_expiration", &nSize);
  4065.       PREF_SetIntPref("browser.link_expiration", 0);
  4066.       PREF_SetIntPref("browser.link_expiration", nSize);
  4067.       returnVal = TRUE;
  4068.     }
  4069.     return MakeArgs("BL", &returnVal);
  4070. }
  4071.  
  4072. HDDEDATA CDDEWrapper::HistoryAddURL(HSZ& hszItem)
  4073. {
  4074.    TwoByteBool retVal = FALSE;
  4075.    CString url;
  4076.  
  4077.    ScanArgs(hszItem, "QCS", &url);
  4078.    URL_Struct* url_s = NET_CreateURLStruct(url, NET_NORMAL_RELOAD); 
  4079.    CAbstractCX *theContext = CAbstractCX::FindContextByID(fetchLastActiveWindow());
  4080.    //MWContext *mwContext = theContext->GetContext();
  4081.    
  4082.     if (url_s) 
  4083.     {
  4084.         theContext->GetUrl(url_s, FO_CACHE_ONLY);
  4085.         GH_UpdateGlobalHistory(url_s);
  4086.         GH_UpdateURLTitle(url_s, (char*)(const char*)url, FALSE);
  4087.         retVal = TRUE;
  4088.     }
  4089.     
  4090.     return MakeArgs("BL", &retVal);
  4091. }
  4092.  
  4093. HDDEDATA CDDEWrapper::HistoryRemoveURL(HSZ& hszItem)
  4094. {
  4095.    TwoByteBool retVal = FALSE;
  4096.    CString url;
  4097.  
  4098.    ScanArgs(hszItem, "QCS", &url);
  4099.    
  4100.    GHHANDLE theHistory = GH_GetContext(eGH_NameSort, NULL, NULL, NULL, NULL);
  4101.    int recNo = GH_GetRecordNum(theHistory, (char*)((const char*)url));
  4102.    if (recNo != -1)
  4103.    {
  4104.        GH_DeleteRecord(theHistory, recNo, FALSE);
  4105.        GH_ReleaseContext(theHistory, FALSE);
  4106.        retVal = TRUE;
  4107.    }
  4108.  
  4109.     return MakeArgs("BL", &retVal);
  4110. }
  4111.  
  4112. HDDEDATA CDDEWrapper::HistoryNumEntries(HSZ& hszItem)
  4113. {
  4114.  
  4115.    DWORD retVal = 0;
  4116.    GHHANDLE theHistory = GH_GetContext(eGH_NameSort, NULL, NULL, NULL, NULL);
  4117.    retVal = GH_GetNumRecords(theHistory);
  4118.    return MakeArgs("DW", &retVal);
  4119. }
  4120.  
  4121. HDDEDATA CDDEWrapper::HistoryGetEntry(HSZ& hszItem)
  4122. {
  4123.    CString title;
  4124.    CString url;
  4125.    DWORD lastAccessed = 0;
  4126.    DWORD firstAccessed = 0;
  4127.    DWORD visitCount = 0;
  4128.  
  4129.    DWORD recNo = 0;
  4130.    DWORD retVal = 0;
  4131.  
  4132.    ScanArgs(hszItem, "DW", &recNo);
  4133.    
  4134.    GHHANDLE theHistory = GH_GetContext(eGH_NameSort, NULL, NULL, NULL, NULL);
  4135.    gh_HistEntry* historyEntry = GH_GetRecord(theHistory, recNo);
  4136.    if (historyEntry != NULL)
  4137.    {
  4138.       title = historyEntry->pszName;
  4139.       url = historyEntry->address;
  4140.       lastAccessed = historyEntry->last_accessed;
  4141.       firstAccessed = historyEntry->first_accessed;
  4142.       visitCount = historyEntry->iCount;
  4143.       return MakeArgs("QCS,QCS,DW,DW,DW", &url, &title, &firstAccessed, &lastAccessed, &visitCount);
  4144.  
  4145.    }
  4146.    return MakeArgs("DW", &retVal);
  4147. }
  4148.  
  4149. HDDEDATA CDDEWrapper::InHistory(HSZ& hszItem)
  4150. {
  4151.    TwoByteBool retVal = FALSE;
  4152.    CString url;
  4153.  
  4154.    ScanArgs(hszItem, "QCS", &url);
  4155.    
  4156.     int i = GH_CheckGlobalHistory((char*)(const char*)url);
  4157.     if (i != -1)
  4158.            retVal = TRUE;
  4159.     
  4160.     return MakeArgs("BL", &retVal);
  4161. }
  4162.  
  4163. HDDEDATA CDDEWrapper::GetWindowID(HSZ& hszItem)
  4164. {
  4165.  
  4166.     CString name;
  4167.     DWORD WindowID;
  4168.  
  4169.     ScanArgs(hszItem, "QCS,DW", &name, &WindowID);
  4170.     if (WindowID == 0xFFFFFFFF)
  4171.        WindowID = fetchLastActiveWindow();
  4172.  
  4173.     DWORD retVal = 0x0;
  4174.  
  4175.     if(WindowID != 0x0)    
  4176.     {
  4177.         //    See if it's a valid Window ID
  4178.         CFrameGlue *pFrame = CFrameGlue::FindFrameByID(WindowID, MWContextBrowser);
  4179.         if(pFrame != NULL)    
  4180.         {
  4181.             MWContext *pContext = (pFrame->GetMainContext() != NULL) ? pFrame->GetMainContext()->GetContext() : NULL;
  4182.             if(pContext != NULL)    
  4183.             {
  4184.                 // We have a reference point.... find the named window
  4185.                 MWContext* returnContext = XP_FindNamedContextInList(pContext, (char*)(const char*)name);
  4186.                 if (returnContext != NULL)
  4187.                     retVal = WINCX(pContext)->GetContextID();
  4188.             }
  4189.         }
  4190.     }
  4191.  
  4192.     return MakeArgs("DW", &retVal);
  4193. }
  4194.  
  4195. HDDEDATA CDDEWrapper::SupportsMimeType(HSZ& hszItem)
  4196. {
  4197.  
  4198.  
  4199.   return 0;  
  4200. }
  4201. HDDEDATA CDDEWrapper::ExecuteJavaScript(HSZ& hszItem)
  4202. {
  4203.  
  4204.  
  4205.   return 0;
  4206. }
  4207.  
  4208. HDDEDATA CDDEWrapper::PrintWindow(HSZ& hszItem)
  4209. {
  4210.      DWORD ReturnID = 0L;
  4211.  
  4212.     //    Retrieve our arguments.
  4213.     DWORD WindowID;
  4214.     ScanArgs(hszItem, "DW", &WindowID);
  4215.  
  4216.     if (WindowID == 0xFFFFFFFF)
  4217.        WindowID = fetchLastActiveWindow();
  4218.  
  4219.     if(WindowID != 0x0)    
  4220.     {
  4221.         //    See if it's a valid Window ID
  4222.         CWinCX* pContext = GetContext(WindowID);
  4223.         if(pContext != NULL)    
  4224.         {
  4225.                 if(pContext->CanPrint())
  4226.                 {
  4227.                     pContext->Print();
  4228.                     //Success, set the return value.
  4229.                     ReturnID = WindowID;
  4230.                 }
  4231.                 else
  4232.                     ReturnID = 0xFFFFFFFF;
  4233.         }
  4234.     }
  4235.  
  4236.     HDDEDATA hData = MakeArgs("DW", &ReturnID);
  4237.     return(hData);
  4238. }
  4239.  
  4240. HDDEDATA CDDEWrapper::PrintURL(HSZ& hszItem)
  4241. {
  4242.  TwoByteBool retVal = TRUE;
  4243.  CString url;
  4244.  CString printer;
  4245.  CString driver;
  4246.  CString port;
  4247.  
  4248.  ScanArgs(hszItem, "QCS,QCS,QCS,QCS", &url, &printer, &driver, &port);
  4249.  
  4250.  char* pr = NULL;
  4251.  char* dr = NULL;
  4252.  char* pt = NULL;
  4253.  if (!printer.IsEmpty())
  4254.      pr = (char*)(const char*)printer;
  4255.  if (!driver.IsEmpty())
  4256.      dr = (char*)(const char*)driver;
  4257.  if (!port.IsEmpty())
  4258.      pt = (char*)(const char*)port; 
  4259.  
  4260.  CPrintCX::AutomatedPrint((char*)(const char*)url, pr, dr, pt);
  4261.  
  4262.  
  4263.  return MakeArgs("BL", &retVal);
  4264. }
  4265.  
  4266. CGenericView *CDDEWrapper::GetView(DWORD dwContextID)
  4267. {
  4268.     CGenericView *pRetval = NULL;
  4269.  
  4270.     CWinCX *pCX = GetContext(dwContextID);
  4271.     if(pCX) {
  4272.         pRetval = pCX->GetView();
  4273.     }
  4274.  
  4275.     return(pRetval);
  4276. }
  4277.  
  4278. CFrameGlue *CDDEWrapper::GetFrame(DWORD dwContextID)
  4279. {
  4280.     CFrameGlue *pRetval = NULL;
  4281.  
  4282.     CWinCX *pCX = GetContext(dwContextID);
  4283.     if(pCX) {
  4284.         pRetval = pCX->GetFrame();
  4285.     }
  4286.  
  4287.     return(pRetval);
  4288. }
  4289.  
  4290. CWinCX *CDDEWrapper::GetContext(DWORD dwContextID)
  4291. {
  4292.     CWinCX *pRetval = NULL;
  4293.  
  4294.     CAbstractCX *pAbstract = CAbstractCX::FindContextByID(dwContextID);
  4295.     if(pAbstract && pAbstract->IsDestroyed() == FALSE)   {
  4296.         //  Must be a window, and a MWContextBrowser.
  4297.         if(pAbstract->IsFrameContext() && pAbstract->GetContext()->type == MWContextBrowser)  {
  4298.             pRetval = VOID2CX(pAbstract, CWinCX);
  4299.         }
  4300.     }
  4301.  
  4302.     return(pRetval);
  4303. }
  4304.  
  4305. DWORD CDDEWrapper::fetchLastActiveWindow()
  4306. {
  4307.     return FEU_GetLastActiveFrameID(MWContextBrowser);
  4308. }
  4309.  
  4310.