home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: WPS_PM
/
WPS_PM.zip
/
xf083czs.zip
/
NETSC421
/
netscdde.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-11-22
|
25KB
|
688 lines
/*
* netscdde.c:
* this is the main (and only) C file for the
* Netscape DDE interface. This code is much more
* messy than XFolder's. It's a rather quick hack
* done in about two days with DDE code stolen from
* various places.
*
* Use the undocumented "-D" parameter on the command
* line to start NetscDDE in "debug" mode, which will
* display a frame window with a menu where you may
* debug the DDE messages. This window is invisible
* when "-D" is not used. (Ugly, huh.)
*
* Netscape's DDE topics are (horribly) documented
* for all Netscape versions at
* http://developer.netscape.com/library/documentation/communicator/DDE
*
* Copyright (C) 1997-98 Ulrich Möller.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, in version 2 as it comes in the COPYING
* file of the XFolder main distribution.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define INCL_WIN
#define INCL_DOS
#include <os2.h>
#include <stdio.h>
#include <string.h>
#include "netscdde.h"
#pragma linkage (main,optlink)
void ShowMessage(PSZ);
MRESULT EXPENTRY LocalWndProc(HWND, ULONG, MPARAM, MPARAM);
HAB hab;
HWND hwndDebug, hwndListbox,
hServerWnd = NULLHANDLE;
PFNWP SysWndProc;
CHAR szURL[400] = "";
ULONG idTimer = 0;
CONVCONTEXT context;
CHAR szDDENetscape[] = "NETSCAPE", // DDE server name
szNetscapeApp[CCHMAXPATH] = "NETSCAPE.EXE", // default program to start
// if not running
szNetscapeParams[CCHMAXPATH] = ""; // space for params
PSZ szOpenURLTopic = "WWW_OpenURL"; // open URL DDE topic
// (see Netscape docs)
// options flags, modified by command line interface
BOOL optNewWindow = FALSE,
optDebug = FALSE,
optExecute = TRUE,
optConfirmStart = TRUE,
optMinimized = FALSE,
optHidden = FALSE;
BOOL NetscapeFound = FALSE;
// status window handle
HWND hwndContacting = NULLHANDLE;
/*
* CenterWindow:
* centers a window within its parent window.
* The window should not be visible to avoid flickering.
*/
void CenterWindow(HWND hwnd)
{
RECTL rclParent;
RECTL rclWindow;
WinQueryWindowRect(hwnd, &rclWindow);
WinQueryWindowRect(WinQueryWindow(hwnd, QW_PARENT), &rclParent);
rclWindow.xLeft = (rclParent.xRight - rclWindow.xRight) / 2;
rclWindow.yBottom = (rclParent.yTop - rclWindow.yTop ) / 2;
WinSetWindowPos(hwnd, NULLHANDLE, rclWindow.xLeft, rclWindow.yBottom,
0, 0, SWP_MOVE | SWP_SHOW);
}
/*
* WinCenteredDlgBox:
* just like WinDlgBox, but the window is centered
*/
ULONG WinCenteredDlgBox(HWND hwndParent, HWND hwndOwner,
PFNWP pfnDlgProc, HMODULE hmod, ULONG idDlg, PVOID pCreateParams)
{
ULONG ulReply;
HWND hwndDlg = WinLoadDlg(hwndParent, hwndOwner, pfnDlgProc,
hmod, idDlg, pCreateParams);
CenterWindow(hwndDlg);
ulReply = WinProcessDlg(hwndDlg);
WinDestroyWindow(hwndDlg);
return (ulReply);
}
/*
* GenericDlgProc:
* this is the dlg procedure for dlg boxes;
* it really does nothing
*/
MRESULT EXPENTRY GenericDlgProc(HWND hwnd,
ULONG msg,
MPARAM mp1,
MPARAM mp2)
{
return (WinDefDlgProc(hwnd, msg, mp1, mp2));
}
/*
* ExplainParams:
* this displays the dlg box which explains
* NetscDDE's usage in brief; called when the
* parameters on the cmd line don't seem to
* be complete
*/
VOID ExplainParams(VOID)
{
WinCenteredDlgBox(HWND_DESKTOP, HWND_DESKTOP,
GenericDlgProc,
NULLHANDLE,
ID_NDD_EXPLAIN,
NULL);
}
/*
* main:
* Program entry point; accepts URLs on the command line.
*/
int main(int argc, char *argv[])
{
HMQ hmq;
FRAMECDATA fcd;
QMSG qmsg;
BOOL Proceed = TRUE;
if (!(hab = WinInitialize(0)))
return FALSE;
if (!(hmq = WinCreateMsgQueue(hab, 0)))
return FALSE;
// parse parameters on cmd line
if (argc > 1) {
SHORT i = 0;
while (i++ < argc-1) {
if (argv[i][0] == '-') {
SHORT i2;
for (i2 = 1; i2 < strlen(argv[i]); i2++) {
switch (argv[i][i2]) {
case 'n':
optNewWindow = TRUE;
break;
case 'x':
optExecute = FALSE;
break;
case 'm':
optMinimized = TRUE;
break;
case 'h':
optHidden = TRUE;
break;
case 'X':
optConfirmStart = FALSE;
break;
case 'p': // netscape path
if (i < argc) {
strcpy(szNetscapeApp, argv[i+1]);
i++;
i2 = 1000;
}
else
{
ExplainParams();
Proceed = FALSE;
}
break;
case 'P': // netscape parameters
if (i < argc) {
strcpy(szNetscapeParams, argv[i+1]);
i++;
i2 = 1000;
}
else
{
ExplainParams();
Proceed = FALSE;
}
break;
case 'D': // debug, show list box window w/ DDE msgs
optDebug = TRUE;
break;
default: // unknown parameter
ExplainParams();
Proceed = FALSE;
break;
}
}
}
else {
// no option ("-"): seems to be URL
if (strchr(argv[i], ' ')) {
// if the URL contains spaces, we enclose it in quotes
sprintf(szURL, "\"%s\"", argv[i]);
}
else
strcpy(szURL, argv[i]);
}
}
}
if (strlen(szURL) == 0) {
// no URL given: explain
ExplainParams();
Proceed = FALSE;
}
if (Proceed) {
// OK, parameters seemed to be correct:
// create the main window, which is only
// visible in Debug mode ("-D" param). But
// even if not in debug mode, this window is
// used for DDE message processing.
fcd.cb = sizeof(FRAMECDATA);
fcd.flCreateFlags = FCF_TITLEBAR |
FCF_SYSMENU |
FCF_MENU |
FCF_SIZEBORDER |
FCF_SHELLPOSITION |
FCF_MINMAX |
FCF_TASKLIST;
fcd.hmodResources = NULLHANDLE;
// set our resource key (so PM can find menus, icons, etc).
fcd.idResources = DDEC;
// create the frame
hwndDebug = WinCreateWindow(HWND_DESKTOP,
WC_FRAME,
"Netscape DDE",
0, 0, 0, 0, 0,
NULLHANDLE,
HWND_TOP,
DDEC,
&fcd,
NULL);
if (!hwndDebug)
return FALSE;
// set the NetscDDE icon for the frame window
WinSendMsg(hwndDebug,
WM_SETICON,
(MPARAM)WinLoadPointer(HWND_DESKTOP, NULLHANDLE,
ID_ICON),
NULL);
// create a list window child
hwndListbox = WinCreateWindow(hwndDebug,
WC_LISTBOX,
NULL,
LS_HORZSCROLL,
0, 0, 0, 0,
hwndDebug,
HWND_BOTTOM,
FID_CLIENT,
NULL,
NULL);
// we must intercept the frame window's messages;
// we save the return value (the current WndProc),
// so we can pass it all the other messages the frame gets.
SysWndProc = WinSubclassWindow(hwndDebug, (PFNWP)LocalWndProc);
// the window we just created is normally invisible; we
// will only display it if the (undocumented) "-D" option
// was given on the command line.
if (optDebug)
WinShowWindow(hwndDebug, TRUE);
// now show "Contacting Netscape"
hwndContacting = WinLoadDlg(HWND_DESKTOP, hwndDebug,
GenericDlgProc,
0, ID_NDD_CONTACTING,
0);
WinShowWindow(hwndContacting, TRUE);
// now post msg to main window to initiate DDE
WinPostMsg(hwndDebug, WM_COMMAND, MPFROM2SHORT(IDM_INITIATE, 0), 0);
// standard PM message loop
while (WinGetMsg(hab, &qmsg, NULLHANDLE, 0, 0))
{
WinDispatchMsg(hab, &qmsg);
}
} // end if (proceed)
// clean up on the way out
if (hwndContacting)
WinDestroyWindow(hwndContacting);
WinDestroyMsgQueue(hmq);
WinTerminate(hab);
return TRUE;
}
/*
* DDERequest:
* this routine tries to post a DDE request to Netscape
* and returns TRUE only if this was successful.
*/
BOOL DDERequest(HWND hwndClient, PSZ pszItemString)
{
ULONG mem;
PID pid;
TID tid;
PDDESTRUCT pddeStruct;
PSZ pszDDEItemName;
// get some sharable memory
DosAllocSharedMem((PVOID)&mem,
NULL,
sizeof(DDESTRUCT)+1000,
PAG_COMMIT |
PAG_READ |
PAG_WRITE |
OBJ_GIVEABLE);
// get the server's ID and give it access
// to the shared memory
WinQueryWindowProcess(hServerWnd, &pid, &tid);
DosGiveSharedMem(&mem, pid, PAG_READ | PAG_WRITE);
/* here is definition for DDESTRUCT, for further reference:
typedef struct _DDESTRUCT {
ULONG cbData;
This is the length of data that occurs after the offabData parameter. If no
data exists, this field should contain a zero (0).
USHORT fsStatus; / Status of the data exchange.
DDE_FACK
Positive acknowledgement
DDE_FBUSY
Application is busy
DDE_FNODATA
No data transfer for advise
DDE_FACKREQ
Acknowledgements are requested
DDE_FRESPONSE
Response to WM_DDE_REQUEST
DDE_NOTPROCESSED
DDE message not understood
DDE_FAPPSTATUS
A 1-byte field of bits that are reserved for application-specific returns.
USHORT usFormat; / Data format.
USHORT offszItemName; / Offset to item name.
This is the offset to the item name from the start of this structure. Item
name is a null (0x00) terminated string. If no item name exists, there must
be a single null (0x00) character in this position. (That is, ItemName is
ALWAYS a null terminated string.)
USHORT offabData; / Offset to beginning of data.
This is the offset to the data, from the start of this structure. This field
should be calculated regardless of the presence of data. If no data exists,
cbData must be zero (0).
For compatibility reasons, this data should not contain embedded pointers.
Offsets should be used instead.
-- CHAR szItemName[] / offset: offszItemName
-- BYTE abData[] / offset: offabData
} DDESTRUCT; */
// setup DDE data structures
pddeStruct = (PDDESTRUCT)mem;
pddeStruct->fsStatus = 0; // DDE_FACKREQ; // Status
pddeStruct->usFormat = DDEFMT_TEXT; // Text format
// go past end of data structure for the item name
pddeStruct->offszItemName = sizeof(DDESTRUCT);
pszDDEItemName = ((BYTE*)pddeStruct)+(pddeStruct->offszItemName);
strcpy(pszDDEItemName, pszItemString);
// go past end of data structure
// (plus past the name) for the data
pddeStruct->offabData = strlen(pszDDEItemName)+1;
// offset to BEGINNING of data
pddeStruct->cbData = 500;
// length of the data
// post our request to the server program
NetscapeFound = (WinDdePostMsg(hServerWnd,
hwndClient,
WM_DDE_REQUEST,
pddeStruct,
0));
return (NetscapeFound);
}
/*
* LocalWndProc:
* window procedure for the main NetscDDE window, which
* is only visible in Debug mode ("-D" option), mostly
* processing DDE messages. If we're in debug mode, this
* routine waits for certain menu selections, otherwise
* the corresponding messages will be posted automatically.
*/
MRESULT EXPENTRY LocalWndProc(HWND hwndFrame,ULONG msg,MPARAM mp1,MPARAM mp2)
{
PSZ szData;
PDDESTRUCT pddeStruct;
ULONG mem;
CHAR szBuffer[200];
switch(msg)
{
// all answers to the WinDDEInitate call arrive here
case WM_DDE_INITIATEACK: {
PDDEINIT pddeInit;
PSZ szInApp, szInTopic;
pddeInit = (PDDEINIT)mp2;
szInApp = pddeInit->pszAppName;
szInTopic = pddeInit->pszTopic;
ShowMessage("!! Netscape odpov╪d╪l.");
hServerWnd = (HWND)mp1;
break; }
// all answers to DDE requests arrive here
case WM_DDE_DATA: {
ShowMessage("!! P²ijata data od Netscape: ");
pddeStruct = (PDDESTRUCT)mp2;
DosGetSharedMem(pddeStruct, PAG_READ | PAG_WRITE);
szData = (BYTE *)(pddeStruct+(pddeStruct->offabData));
ShowMessage(szData);
break; }
// menu item processing (in debug mode, otherwise these
// WM_COMMAND msgs have been posted automatically)
case WM_COMMAND:
switch (SHORT1FROMMP(mp1))
{
// start DDE conversation: this was posted
// by "main" before the PM loop was entered
case IDM_INITIATE:
WinPostMsg(hwndListbox, LM_DELETEALL, 0, 0);
ShowMessage("--- Spouτtím DDE... Téma:");
ShowMessage(szOpenURLTopic);
context.cb = sizeof(CONVCONTEXT);
context.fsContext = 0;
WinDdeInitiate(hwndFrame, szDDENetscape,
szOpenURLTopic, &context);
if (!optDebug)
// if we're not in debug mode, post subsequent
// menu commands automatically
WinPostMsg(hwndFrame, WM_COMMAND, MPFROM2SHORT(IDM_CHAIN2, 0), 0);
break;
// "Open URL": request data from server
case IDM_OPENURL: {
ShowMessage("--- URL je:");
ShowMessage(szURL);
strcpy(szBuffer, szURL);
strcat(szBuffer, ",,0xFFFFFFFF,0x0");
ShowMessage("Odesílám poºadavek:");
ShowMessage(szBuffer);
if (DDERequest(hwndFrame, szBuffer))
ShowMessage("Zpráva DDE odeslána.");
else
ShowMessage("Chyba p²i odesílání zprávy DDE.");
break; }
// "Open URL in new window": request data from server,
// but with different parameters
case IDM_OPENURLNEW: {
ShowMessage("--- URL je:");
ShowMessage(szURL);
strcpy(szBuffer, szURL);
strcat(szBuffer, ",,0x0,0x0");
ShowMessage("Odesílám poºadavek:");
ShowMessage(szBuffer);
if (DDERequest(hwndFrame, szBuffer))
ShowMessage("Zpráva DDE odeslána.");
else
ShowMessage("Chyba p²i odesílání zprávy DDE.");
break; }
/*
* IDM_CHAIN2:
* this is posted after DDE_INITIATE was
* successful
*/
case IDM_CHAIN2:
{
if (optNewWindow)
WinPostMsg(hwndDebug, WM_COMMAND, MPFROM2SHORT(IDM_OPENURLNEW, 0), 0);
else
WinPostMsg(hwndDebug, WM_COMMAND, MPFROM2SHORT(IDM_OPENURL, 0), 0);
WinPostMsg(hwndDebug, WM_COMMAND, MPFROM2SHORT(IDM_CHAIN3, 0), 0);
}
break;
/*
* IDM_CHAIN3:
* this is posted to close the whole thing; we just need
* another msg before going for IDM_CLOSE, or some DDE
* msgs might get lost
*/
case IDM_CHAIN3:
WinPostMsg(hwndDebug, WM_COMMAND, MPFROM2SHORT(IDM_CLOSE, 0), 0);
break;
/*
* IDM_CLOSE:
* this is posted to close the whole thing
*/
case IDM_CLOSE:
WinDdePostMsg(hServerWnd,
hwndFrame,
WM_DDE_TERMINATE,
NULL,
DDEPM_RETRY);
ShowMessage("Komunikace DDE ukonƒena.");
if (!optDebug)
WinPostMsg(hwndFrame, WM_COMMAND, MPFROM2SHORT(IDM_DELAYEXIT, 0), 0);
break;
/*
* IDM_DELAYEXIT:
* this is posted after IDM_CLOSE; we will now
* check for whether the DDE conversation with
* Netscape was successful and, if not, start
* a new instance of Netscape according to the
* command line parameters
*/
case IDM_DELAYEXIT: {
if ((!NetscapeFound) && (optExecute)) {
// confirm start netscape
if ( (!optConfirmStart)
|| (WinCenteredDlgBox(
HWND_DESKTOP,
hwndDebug,
GenericDlgProc,
NULLHANDLE,
ID_NDD_QUERYSTART,
NULL)
== DID_OK)
)
{
STARTDATA SData = {0};
APIRET rc = 0;
PID pid = 0; // PID returned
ULONG ulSessID = 0; // session ID returned
UCHAR achObjBuf[256] = {0}; // Error data if DosStart fails
CHAR szArgs[CCHMAXPATH];
CHAR szMsg[100]; // message
HWND hwndNotify = HWND_DESKTOP;
PROGDETAILS Details;
HAPP happ;
// destroy "Contacting", create "Starting Netscape"
// window
if (hwndContacting)
WinDestroyWindow(hwndContacting);
hwndContacting = WinLoadDlg(HWND_DESKTOP, hwndDebug,
GenericDlgProc,
0, ID_NDD_STARTING,
0);
WinShowWindow(hwndContacting, TRUE);
// now start session
strcpy(szArgs, szNetscapeParams);
strcat(szArgs, " ");
strcat(szArgs, szURL);
SData.Length = sizeof(STARTDATA);
SData.Related = SSF_RELATED_INDEPENDENT;
SData.FgBg = SSF_FGBG_FORE;
SData.TraceOpt = SSF_TRACEOPT_NONE;
SData.PgmTitle = "Netscape";
SData.PgmName = szNetscapeApp;
SData.PgmInputs = szArgs;
SData.TermQ = 0;
SData.Environment = 0;
SData.InheritOpt = SSF_INHERTOPT_SHELL;
SData.SessionType = SSF_TYPE_DEFAULT;
SData.IconFile = 0;
SData.PgmHandle = 0;
SData.PgmControl = (optMinimized)
? (SSF_CONTROL_MINIMIZE |
((optHidden) ? SSF_CONTROL_INVISIBLE : SSF_CONTROL_VISIBLE)
)
: SSF_CONTROL_VISIBLE;
SData.InitXPos = 30;
SData.InitYPos = 40;
SData.InitXSize = 200;
SData.InitYSize = 140;
SData.Reserved = 0;
SData.ObjectBuffer = achObjBuf;
SData.ObjectBuffLen = (ULONG) sizeof(achObjBuf);
rc = DosStartSession(&SData, &ulSessID, &pid);
}
}
// keep "Contacting" / "Starting" window visible for two seconds
idTimer = WinStartTimer(hab, hwndFrame, 1, 2000);
break; }
// User closes the window
case IDM_EXIT:
WinPostMsg(hwndFrame, WM_CLOSE, 0, 0);
break;
}
break;
case WM_TIMER:
// after two seconds, close status window
WinStopTimer(hab, hwndFrame, idTimer);
WinPostMsg(hwndFrame, WM_CLOSE, 0, 0);
break;
// Send the message to the usual WC_FRAME WndProc
default:
return (*SysWndProc)(hwndFrame, msg, mp1, mp2);
}
return FALSE;
}
/*
* ShowMessage:
* add a string to the listbox.
*/
void ShowMessage(PSZ szText)
{
WinPostMsg(hwndListbox,
LM_INSERTITEM,
MPFROMSHORT(LIT_END),
szText);
}