1998-03-28 02:44:41 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
|
|
* http://www.mozilla.org/NPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* NPL.
|
|
|
|
*
|
|
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
|
|
* Reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
//Created Abe Jarrett: Most of the methods in this class were taken from
|
|
|
|
//Garrett's code in dde.cpp. This file is intended only as
|
|
|
|
//a means of detecting seconds instance criteria and handling processing
|
|
|
|
//of it and any command line content as well.
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
|
|
|
#include "ddecmd.h"
|
|
|
|
#include "ddectc.h"
|
|
|
|
|
|
|
|
|
|
|
|
// Our DDE instance identifier.
|
|
|
|
DWORD CDDECMDWrapper::m_dwidInst;
|
|
|
|
|
|
|
|
// Wether or not DDE was successfully initialized.
|
|
|
|
BOOL CDDECMDWrapper::m_bDDEActive;
|
|
|
|
|
|
|
|
// Our array of hsz strings.
|
|
|
|
HSZ CDDECMDWrapper::m_hsz[CDDECMDWrapper::m_MaxHSZ];
|
|
|
|
|
|
|
|
// A list of all current conversations. The PtrToPtr map was used since
|
|
|
|
// the pointers are known to be 32 bits long, and the HCONV is a
|
|
|
|
// DWORD or possibly a pointer, and WordToPtr just wouldn't cut it
|
|
|
|
// with 16 bits and all.
|
|
|
|
// Sounds good to me!
|
|
|
|
CMapPtrToPtr CDDECMDWrapper::m_ConvList;
|
|
|
|
|
|
|
|
// Command filter for DDEML
|
|
|
|
DWORD CDDECMDWrapper::m_dwafCmd;
|
|
|
|
|
|
|
|
// Call back function for use with DDEML
|
|
|
|
FARPROC CDDECMDWrapper::m_pfnCallBack;
|
|
|
|
|
|
|
|
|
|
|
|
//This kicks it all off.
|
|
|
|
void DDEInitCmdLineConversation()
|
|
|
|
{
|
|
|
|
|
|
|
|
CDDECMDWrapper::m_pfnCallBack = NULL;
|
|
|
|
|
|
|
|
#ifdef XP_WIN16
|
|
|
|
// Find out if we can even use DDEML (must be in protected mode).
|
|
|
|
// Undoubtedly, this is the case since we must be in protected
|
|
|
|
// mode to use WINSOCK services, but just to be anal....
|
|
|
|
// GetWinFlags() has been removed in MSVC 2.0 and the analog doesn't
|
|
|
|
// look like it does the same thing. chouck 29-Dec-94
|
|
|
|
if(!(GetWinFlags() & WF_PMODE)) {
|
|
|
|
// Not in protected mode, can not continue with DDEML
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Set up our callback function to be registered with DDEML.
|
|
|
|
CDDECMDWrapper::m_pfnCallBack = (FARPROC)CmdLineDdeCallBack;
|
|
|
|
|
|
|
|
|
|
|
|
if(DdeInitialize(&CDDECMDWrapper::m_dwidInst,
|
|
|
|
(PFNCALLBACK)CDDECMDWrapper::m_pfnCallBack,
|
|
|
|
CDDECMDWrapper::m_dwafCmd, 0L)) {
|
|
|
|
// Unable to initialize, don't continue.
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CDDECMDWrapper::m_bDDEActive = TRUE;
|
|
|
|
|
|
|
|
// Load in all HSZs.
|
|
|
|
// Unfortunately, there is really no good way to detect any errors
|
|
|
|
// on these string intializations, so let the blame land
|
|
|
|
// where it will if something fails.
|
|
|
|
CString strCS;
|
|
|
|
|
|
|
|
strCS.LoadString(IDS_DDE_CMDLINE_SERVICE_NAME);
|
|
|
|
CDDECMDWrapper::m_hsz[CDDECMDWrapper::m_ServiceName] =
|
|
|
|
DdeCreateStringHandle(CDDECMDWrapper::m_dwidInst,
|
|
|
|
(char *)(const char *)strCS, CP_WINANSI);
|
|
|
|
|
|
|
|
strCS.LoadString(IDS_DDE_PROCESS_CMDLINE);
|
|
|
|
CDDECMDWrapper::m_hsz[CDDECMDWrapper::m_ProcessCmdLine] =
|
|
|
|
DdeCreateStringHandle(CDDECMDWrapper::m_dwidInst,
|
|
|
|
(char *)(const char *)strCS, CP_WINANSI);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Purpose: Construct a DDECMDWrapper object
|
|
|
|
// Arguments: hszService The name of the service we are handling.
|
|
|
|
// hszTopic The name of the topic we are handling.
|
|
|
|
// hConv The handle of the conversation we are
|
|
|
|
// handling.
|
|
|
|
// Returns: nothing
|
|
|
|
// Comments: Handles all created objects internally through a map.
|
|
|
|
// Revision History:
|
|
|
|
//
|
|
|
|
CDDECMDWrapper::CDDECMDWrapper(HSZ hszService, HSZ hszTopic, HCONV hConv)
|
|
|
|
{
|
|
|
|
// Set our members passed in.
|
|
|
|
m_hszService = hszService;
|
|
|
|
m_hszTopic = hszTopic;
|
|
|
|
m_hConv = hConv;
|
|
|
|
|
|
|
|
// Figure out our enumerated service number.
|
|
|
|
// We know this anyhow, we only have one service name at this
|
|
|
|
// point.
|
|
|
|
m_iService = m_ServiceName;
|
|
|
|
|
|
|
|
// Figure out our enumerated topic number.
|
|
|
|
m_iTopic = EnumTopic(hszTopic);
|
|
|
|
|
|
|
|
// Add ourselves to the current map of conversations.
|
|
|
|
m_ConvList.SetAt((void *)hConv, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Purpose: Destory a CDDECMDWrapper object
|
|
|
|
// Arguments: void
|
|
|
|
// Returns: nothing
|
|
|
|
// Comments: Removes us from the internally handled list
|
|
|
|
// Revision History:
|
|
|
|
//
|
|
|
|
|
|
|
|
CDDECMDWrapper::~CDDECMDWrapper()
|
|
|
|
{
|
|
|
|
// Remove ourselves from the list of current conversations.
|
|
|
|
m_ConvList.RemoveKey((void *)m_hConv);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Purpose: Connect to a service using a specific topic
|
|
|
|
// Arguments: cpService The service name of the DDE server
|
|
|
|
// hszTopic The topic of the conversation to the server
|
|
|
|
// Returns: CDDECMDWrapper * The conversation object if established,
|
|
|
|
// otherwise NULL.
|
|
|
|
// Comments: Generic connection establishment.
|
|
|
|
// Revision History:
|
|
|
|
// 01-05-95 created GAB
|
|
|
|
CDDECMDWrapper *CDDECMDWrapper::ClientConnect(const char *cpService,
|
|
|
|
HSZ& hszTopic)
|
|
|
|
{
|
|
|
|
CDDECMDWrapper *pConv = NULL;
|
|
|
|
|
|
|
|
// Make the service name into an HSZ.
|
|
|
|
HSZ hszService = DdeCreateStringHandle(m_dwidInst,
|
|
|
|
(char *) cpService,
|
|
|
|
CP_WINANSI);
|
|
|
|
if(hszService == NULL) {
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Establish the connection.
|
|
|
|
HCONV hConv = DdeConnect(m_dwidInst, hszService, hszTopic, NULL);
|
|
|
|
if(hConv != NULL) {
|
|
|
|
// We have a connection, all that's left to do is to create
|
|
|
|
// a CDDECMDWrapper, we'll be creating it with the wrong
|
|
|
|
// service name of course, but client connections no
|
|
|
|
// longer really care about the service connection number,
|
|
|
|
// all they need is the conversation handle.
|
|
|
|
pConv = new CDDECMDWrapper(m_hsz[m_ServiceName], hszTopic, hConv);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Free off our created hsz.
|
|
|
|
DdeFreeStringHandle(m_dwidInst, hszService);
|
|
|
|
|
|
|
|
|
|
|
|
return(pConv);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Purpose: Figure out which wrapper is associated with a conversation.
|
|
|
|
// Arguments: hConv The conversation to find out about.
|
|
|
|
// Returns: CDDECMDWrapper * A pointer to the CDDECMDWrapper that is
|
|
|
|
// handling the conversation, or NULL
|
|
|
|
// if none is present.
|
|
|
|
// Comments: Shouldn't ever return NULL really.
|
|
|
|
// Revision History:
|
|
|
|
// 12-30-94 created GAB
|
|
|
|
// 12-04-96 reused by AJ. Probably not necessary, but you never know
|
|
|
|
// know when we may have to do more than one conversation.
|
|
|
|
CDDECMDWrapper *CDDECMDWrapper::GetConvObj(HCONV hConv)
|
|
|
|
{
|
|
|
|
// Query our static map of conversations for the object.
|
|
|
|
void *pWrap;
|
|
|
|
|
|
|
|
if(m_ConvList.Lookup((void *)hConv, pWrap) == 0) {
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
return((CDDECMDWrapper *)pWrap);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Purpose: Return the offset of the hsz topic string in our static
|
|
|
|
// m_hsz array
|
|
|
|
// Arguments: hsz The HSZ string to find in our array
|
|
|
|
// Returns: int The offset into the array, also correlating to
|
|
|
|
// it's enumerated value. If not found, the
|
|
|
|
// returned failure value is 0.
|
|
|
|
// Comments: Mainly coded to remove redundant lookups. Modularity...
|
|
|
|
// Revision History:
|
|
|
|
// 12-30-94 created GAB
|
|
|
|
// 12-04-96 reused by AJ. Probably not necessary, but you never know
|
|
|
|
// know when we may have to handle more than one topic.
|
|
|
|
int CDDECMDWrapper::EnumTopic(HSZ& hsz)
|
|
|
|
{
|
|
|
|
int i_retval = 0;
|
|
|
|
int i_counter;
|
|
|
|
|
|
|
|
// Just start looking for the HSZ string in our static array.
|
|
|
|
for(i_counter = m_TopicStart; i_counter < m_MaxHSZ; i_counter++)
|
|
|
|
{
|
|
|
|
if(m_hsz[i_counter] == hsz) {
|
|
|
|
i_retval = i_counter;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return(i_retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
HDDEDATA
|
|
|
|
CALLBACK
|
|
|
|
#ifndef XP_WIN32
|
|
|
|
_export
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CmdLineDdeCallBack(UINT type, UINT fmt,
|
|
|
|
HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hData, DWORD dwData1,
|
|
|
|
DWORD dwData2)
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
// Depending on the class of transaction, we return different data.
|
|
|
|
if(type & XCLASS_BOOL) {
|
|
|
|
// Must return (HDDEDATA)TRUE or (HDDEDATA)FALSE
|
|
|
|
switch(type) {
|
|
|
|
|
|
|
|
case XTYP_CONNECT: {
|
|
|
|
// We are the server.
|
|
|
|
// A client call the DdeConnect specifying a service and
|
|
|
|
// topic name which we support.
|
|
|
|
HSZ& hszTopic = hsz1;
|
|
|
|
HSZ& hszService = hsz2;
|
|
|
|
|
|
|
|
// Deny the connection if the service name is not the
|
|
|
|
// one we are taking connections for.
|
|
|
|
if(hszService !=
|
|
|
|
CDDECMDWrapper::m_hsz[CDDECMDWrapper::m_ServiceName]) {
|
|
|
|
return((HDDEDATA)FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now, the topic can be NULL, or it can be any one of our
|
|
|
|
// topic names to be accepted.
|
|
|
|
if(hszTopic == NULL) {
|
|
|
|
return((HDDEDATA)TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Go through all our topics, see if we match.
|
|
|
|
if(0 != CDDECMDWrapper::EnumTopic(hszTopic)) {
|
|
|
|
return((HDDEDATA)TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Topic not supported
|
|
|
|
return((HDDEDATA)FALSE);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
// unknown
|
|
|
|
return((HDDEDATA)FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Break handled here
|
|
|
|
return((HDDEDATA)FALSE);
|
|
|
|
}
|
|
|
|
else if(type & XCLASS_DATA) {
|
|
|
|
// Must return DDE data handle, CBR_BLOCK, or NULL
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
else if(type & XCLASS_FLAGS) {
|
|
|
|
// Must return DDE_FACK, DDE_BUSY, or DDE_FNOTPROCESSED
|
|
|
|
switch(type) {
|
|
|
|
case XTYP_ADVDATA: {
|
|
|
|
// We are the client.
|
|
|
|
// The server gave us a data handle.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XTYP_EXECUTE: {
|
|
|
|
// We are the server.
|
|
|
|
// A client said XTYP_EXECUTE in DdeClientTransaction
|
1998-06-18 01:47:30 +00:00
|
|
|
|
|
|
|
// If we are currently not fully initialized, we must ignore
|
|
|
|
// the request, but acknowledge it nonetheless.
|
|
|
|
if(theApp.m_bInInitInstance) {
|
|
|
|
return (HDDEDATA)DDE_FACK;
|
|
|
|
}
|
|
|
|
|
1998-03-28 02:44:41 +00:00
|
|
|
HDDEDATA& hDataExecute = hData;
|
|
|
|
char *pData = (char *)DdeAccessData(hDataExecute, NULL);
|
|
|
|
char szCmd[_MAX_PATH+12];
|
|
|
|
strcpy ( szCmd, "[cmdline(\"" );
|
|
|
|
strcat ( szCmd, pData );
|
|
|
|
strcat ( szCmd, "\")]" );
|
|
|
|
BOOL bRetval = theApp.OnDDECommand(szCmd);
|
|
|
|
|
|
|
|
DdeUnaccessData(hDataExecute);
|
|
|
|
return((HDDEDATA) bRetval);
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
// unknown
|
|
|
|
return(DDE_FNOTPROCESSED);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Break handled here
|
|
|
|
return(DDE_FNOTPROCESSED);
|
|
|
|
}
|
|
|
|
else if(type & XCLASS_NOTIFICATION) {
|
|
|
|
// Must return NULL, as the return value is ignored
|
|
|
|
switch(type) {
|
|
|
|
case XTYP_ADVSTOP: {
|
|
|
|
// We are the server
|
|
|
|
// A client said XTYP_ADVSTOP in DdeClientTransaction
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XTYP_CONNECT_CONFIRM: {
|
|
|
|
// We are the server.
|
|
|
|
// We returned 1 to a XTYP_CONNECT transaction.
|
|
|
|
|
|
|
|
// This callback is mainly to inform us of the conversation
|
|
|
|
// handle that now exists, but we will actually be
|
|
|
|
// creating an instance of an object to handle this
|
|
|
|
// conversation from now on.
|
|
|
|
HSZ& hszTopic = hsz1;
|
|
|
|
HSZ& hszService = hsz2;
|
|
|
|
|
|
|
|
// Create the object, correctly initialized so that
|
|
|
|
// it understands the service, topic, and conversation
|
|
|
|
// it is handling.
|
|
|
|
// It will add itself to the conversation list.
|
|
|
|
CDDECMDWrapper *pObject = new CDDECMDWrapper(hszService, hszTopic,
|
|
|
|
hconv);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XTYP_DISCONNECT: {
|
|
|
|
// We are either client/server
|
|
|
|
// The partner in the conversation called DdeDisconnect
|
|
|
|
// causing both client/server to receive this.
|
|
|
|
|
|
|
|
// Find out which conversation object we are dealing with.
|
|
|
|
CDDECMDWrapper *pWrapper = CDDECMDWrapper::GetConvObj(hconv);
|
|
|
|
|
|
|
|
// Simply delete it.
|
|
|
|
// The object takes care of removing itself from the list.
|
|
|
|
if(pWrapper != NULL) {
|
|
|
|
delete pWrapper;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XTYP_ERROR: {
|
|
|
|
// We are either client/server
|
|
|
|
// A serious error has occurred.
|
|
|
|
// DDEML doesn't have any resources left to guarantee
|
|
|
|
// good communication.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XTYP_REGISTER: {
|
|
|
|
// We are either client/server
|
|
|
|
// A server application used DdeNameService to register
|
|
|
|
// a new service name.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XTYP_UNREGISTER: {
|
|
|
|
// We are either client/server
|
|
|
|
// A server applciation used DdeNameService to unregister
|
|
|
|
// an old service name.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XTYP_XACT_COMPLETE: {
|
|
|
|
// We are the client
|
|
|
|
// An asynchronous tranaction, sent when the client specified
|
|
|
|
// the TIMEOUT_ASYNC flag in DdeClientTransaction has
|
|
|
|
// concluded.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
// unknown
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unknown class type
|
|
|
|
return(NULL);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|