Copyright(C) 1994-1998 T. Teranishi
All rights reserved. */
/* TERATERM.EXE, DDE routines */
#include "teraterm.h"
#include "tttypes.h"
#include <stdio.h>
#include <string.h>
#include <ddeml.h>
#include "ttwinman.h"
#include "ttftypes.h"
#include "filesys.h"
#include "clipboar.h"
#include "ttsetup.h"
#include "telnet.h"
#include "ttlib.h"
#include "ttdde.h"
#define ServiceName "TERATERM"
#define ItemName "DATA"
#define ItemName2 "PARAM"
char TopicName[21] = "";
HCONV ConvH = 0;
BOOL AdvFlag = FALSE;
BOOL CloseTT = FALSE;
static BOOL DdeCmnd = FALSE;
#ifndef TERATERM32
static FARPROC DdeCallbackPtr = NULL;
#endif
static DWORD Inst = 0;
static HSZ Service = 0;
static HSZ Topic = 0;
static HSZ Item = 0;
static HSZ Item2 = 0;
static HWND HWndDdeCli = NULL;
static StartupFlag = FALSE;
// for sync mode
static BOOL SyncMode = FALSE;
static BOOL SyncRecv;
static LONG SyncFreeSpace;
static char ParamFileName[256];
static WORD ParamBinaryFlag;
static WORD ParamAppendFlag;
static WORD ParamXmodemOpt;
#define CBBufSize 300
void GetClientHWnd(PCHAR HWndStr)
{
int i;
BYTE b;
LONG HCli;
HCli = 0;
i = 0;
b = HWndStr[0];
while (b > 0)
{
if (b <= 0x39)
HCli = (HCli << 4) + (b-0x30);
else
HCli = (HCli << 4) + (b-0x37);
i++;
b = HWndStr[i];
}
HWndDdeCli = (HWND)HCli;
}
void Byte2HexStr(BYTE b, LPSTR HexStr)
{
if (b<0xa0)
HexStr[0] = 0x30 + (b >> 4);
else
HexStr[0] = 0x37 + (b >> 4);
if ((b & 0x0f) < 0x0a)
HexStr[1] = 0x30 + (b & 0x0f);
else
HexStr[1] = 0x37 + (b & 0x0f);
HexStr[2] = 0;
}
void SetTopic()
{
#ifdef TERATERM32
WORD w;
w = HIWORD(HVTWin);
Byte2HexStr(HIBYTE(w),&(TopicName[0]));
Byte2HexStr(LOBYTE(w),&(TopicName[2]));
w = LOWORD(HVTWin);
Byte2HexStr(HIBYTE(w),&(TopicName[4]));
Byte2HexStr(LOBYTE(w),&(TopicName[6]));
#else
Byte2HexStr(HIBYTE(HVTWin),&(TopicName[0]));
Byte2HexStr(LOBYTE(HVTWin),&(TopicName[2]));
#endif
}
HDDEDATA WildConnect(HSZ ServiceHsz, HSZ TopicHsz, UINT ClipFmt)
{
HSZPAIR Pairs[2];
BOOL Ok;
Pairs[0].hszSvc = Service;
Pairs[0].hszTopic = Topic;
Pairs[1].hszSvc = NULL;
Pairs[1].hszTopic = NULL;
Ok = FALSE;
if ((ServiceHsz == 0) && (TopicHsz == 0))
Ok = TRUE;
else
if ((TopicHsz == 0) &&
(DdeCmpStringHandles(Service, ServiceHsz) == 0))
Ok = TRUE;
else
if ((DdeCmpStringHandles(Topic, TopicHsz) == 0) &&
(ServiceHsz == 0))
Ok = TRUE;
if (Ok)
return DdeCreateDataHandle(Inst, (LPBYTE)(&Pairs), sizeof(Pairs),
0, NULL, ClipFmt, 0);
else
return 0;
}
BOOL DDEGet1(LPBYTE b)
{
if (cv.DCount <= 0) return FALSE;
*b = ((LPSTR)cv.LogBuf)[cv.DStart];
cv.DStart++;
if (cv.DStart>=InBuffSize)
cv.DStart = cv.DStart-InBuffSize;
cv.DCount--;
return TRUE;
}
LONG DDEGetDataLen()
{
BYTE b;
LONG Len;
int Start, Count;
Len = cv.DCount;
Start = cv.DStart;
Count = cv.DCount;
while (Count>0)
{
b = ((LPSTR)cv.LogBuf)[Start];
if ((b==0x00) || (b==0x01)) Len++;
Start++;
if (Start>=InBuffSize) Start = Start-InBuffSize;
Count--;
}
return Len;
}
HDDEDATA AcceptRequest(HSZ ItemHSz)
{
BYTE b;
BOOL Unlock;
HDDEDATA DH;
LPSTR DP;
int i;
LONG Len;
if ((! DDELog) || (ConvH==0)) return 0;
if (DdeCmpStringHandles(ItemHSz, Item2) == 0) // item "PARAM"
DH = DdeCreateDataHandle(Inst,ParamFileName,sizeof(ParamFileName),0,
Item2,CF_OEMTEXT,0);
else if (DdeCmpStringHandles(ItemHSz, Item) == 0) // item "DATA"
{
if (cv.HLogBuf==0) return 0;
if (cv.LogBuf==NULL)
{
Unlock = TRUE;
cv.LogBuf = GlobalLock(cv.HLogBuf);
if (cv.LogBuf == NULL) return 0;
}
else Unlock = FALSE;
Len = DDEGetDataLen();
if ((SyncMode) &&
(SyncFreeSpace<Len))
Len = SyncFreeSpace;
DH = DdeCreateDataHandle(Inst,NULL,Len+2,0,
Item,CF_OEMTEXT,0);
DP = DdeAccessData(DH,NULL);
if (DP != NULL)
{
i = 0;
while (i < Len)
{
if (DDEGet1(&b)) {
if ((b==0x00) || (b==0x01))
{
DP[i] = 0x01;
DP[i+1] = b + 1;
i = i + 2;
}
else {
DP[i] = b;
i++;
}
}
else
Len = 0;
}
DP[i] = 0;
DdeUnaccessData(DH);
}
if (Unlock)
{
GlobalUnlock(cv.HLogBuf);
cv.LogBuf = NULL;
}
}
else
return 0;
return DH;
}
HDDEDATA AcceptPoke(HSZ ItemHSz, UINT ClipFmt,
HDDEDATA Data)
{
LPSTR DataPtr;
DWORD DataSize;
if ((TalkStatus != IdTalkKeyb) ||
(ConvH==0)) return DDE_FNOTPROCESSED;
if ((ClipFmt!=CF_TEXT) && (ClipFmt!=CF_OEMTEXT)) return DDE_FNOTPROCESSED;
if (DdeCmpStringHandles(ItemHSz, Item) != 0) return DDE_FNOTPROCESSED;
DataPtr = DdeAccessData(Data,&DataSize);
if (DataPtr==NULL) return DDE_FNOTPROCESSED;
CBStartPaste(NULL,FALSE,CBBufSize,DataPtr,DataSize);
DdeUnaccessData(Data);
if (TalkStatus==IdTalkCB)
return (HDDEDATA)DDE_FACK;
else
return DDE_FNOTPROCESSED;
}
WORD HexStr2Word(PCHAR Str)
{
int i;
BYTE b;
WORD w;
for (i=0; i<=3; i++)
{
b = Str[i];
if (b <= 0x39)
w = (w << 4) + (b-0x30);
else
w = (w << 4) + (b-0x37);
}
return w;
}
#define CmdSetHWnd ' '
#define CmdSetFile '!'
#define CmdSetBinary '"'
#define CmdSetAppend '#'
#define CmdSetXmodemOpt '$'
#define CmdSetSync '%'
#define CmdBPlusRecv '&'
#define CmdBPlusSend '\''
#define CmdChangeDir '('
#define CmdClearScreen ')'
#define CmdCloseWin '*'
#define CmdConnect '+'
#define CmdDisconnect ','
#define CmdEnableKeyb '-'
#define CmdGetTitle '.'
#define CmdInit '/'
#define CmdKmtFinish '0'
#define CmdKmtGet '1'
#define CmdKmtRecv '2'
#define CmdKmtSend '3'
#define CmdLoadKeyMap '4'
#define CmdLogClose '5'
#define CmdLogOpen '6'
#define CmdLogPause '7'
#define CmdLogStart '8'
#define CmdLogWrite '9'
#define CmdQVRecv ':'
#define CmdQVSend ';'
#define CmdRestoreSetup '<'
#define CmdSendBreak '='
#define CmdSendFile '>'
#define CmdSendKCode '?'
#define CmdSetEcho '@'
#define CmdSetTitle 'A'
#define CmdShowTT 'B'
#define CmdXmodemSend 'C'
#define CmdXmodemRecv 'D'
#define CmdZmodemSend 'E'
#define CmdZmodemRecv 'F'
HDDEDATA AcceptExecute(HSZ TopicHSz, HDDEDATA Data)
{
char Command[260];
char Temp[MAXPATHLEN];
int i;
WORD w, c;
if ((ConvH==0) ||
(DdeCmpStringHandles(TopicHSz, Topic) != 0) ||
(DdeGetData(Data,Command,sizeof(Command),0) == 0))
return DDE_FNOTPROCESSED;
switch (Command[0]) {
case CmdSetHWnd:
GetClientHWnd(&Command[1]);
if (cv.Ready)
SetDdeComReady(1);
break;
case CmdSetFile:
strcpy(ParamFileName,&(Command[1]));
break;
case CmdSetBinary:
ParamBinaryFlag = Command[1] & 1;
break;
case CmdSetAppend:
ParamAppendFlag = Command[1] & 1;
break;
case CmdSetXmodemOpt:
ParamXmodemOpt = Command[1] & 3;
if (ParamXmodemOpt==0) ParamXmodemOpt = 1;
break;
case CmdSetSync:
if (sscanf(&(Command[1]),"%u",&SyncFreeSpace)!=1)
SyncFreeSpace = 0;
SyncMode = (SyncFreeSpace>0);
SyncRecv = TRUE;
break;
case CmdBPlusRecv:
if ((FileVar==NULL) && NewFileVar(&FileVar))
{
FileVar->NoMsg = TRUE;
DdeCmnd = TRUE;
BPStart(IdBPReceive);
}
else
return DDE_FNOTPROCESSED;
break;
case CmdBPlusSend:
if ((FileVar==NULL) && NewFileVar(&FileVar))
{
FileVar->DirLen = 0;
strcpy(FileVar->FullName,ParamFileName);
FileVar->NumFname = 1;
FileVar->NoMsg = TRUE;
DdeCmnd = TRUE;
BPStart(IdBPSend);
}
else
return DDE_FNOTPROCESSED;
break;
case CmdChangeDir:
strcpy(ts.FileDir,ParamFileName);
break;
case CmdClearScreen:
switch (ParamFileName[0]) {
case '0':
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdEditCLS,0);
break;
case '1':
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdEditCLB,0);
break;
case '2':
PostMessage(HTEKWin,WM_USER_ACCELCOMMAND,IdCmdEditCLS,0);
break;
}
break;
case CmdCloseWin:
CloseTT = TRUE;
break;
case CmdConnect:
if (cv.Open) {
if (cv.Ready)
SetDdeComReady(1);
break;
}
strcpy(Temp,"a "); // dummy exe name
strcat(Temp,ParamFileName);
if (LoadTTSET())
(*ParseParam)(Temp, &ts, NULL);
FreeTTSET();
cv.NoMsg = 1; /* suppress error messages */
PostMessage(HVTWin,WM_USER_COMMSTART,0,0);
break;
case CmdDisconnect:
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdDisconnect,0);
break;
case CmdEnableKeyb:
KeybEnabled = (ParamBinaryFlag!=0);
break;
case CmdGetTitle:
// title is transfered later by XTYP_REQUEST
strcpy(ParamFileName,ts.Title);
break;
case CmdInit: // initialization signal from TTMACRO
if (StartupFlag) // in case of startup macro
{ // TTMACRO is waiting for connecting to the host
if ((ts.PortType==IdSerial) ||
(ts.HostName[0]!=0))
{
cv.NoMsg = 1;
// start connecting
PostMessage(HVTWin,WM_USER_COMMSTART,0,0);
}
else // notify TTMACRO that I can not connect
SetDdeComReady(0);
StartupFlag = FALSE;
}
break;
case CmdKmtFinish:
case CmdKmtRecv:
if ((FileVar==NULL) && NewFileVar(&FileVar))
{
FileVar->NoMsg = TRUE;
DdeCmnd = TRUE;
if (Command[0]==CmdKmtFinish)
i = IdKmtFinish;
else
i = IdKmtReceive;
KermitStart(i);
}
else
return DDE_FNOTPROCESSED;
break;
case CmdKmtGet:
case CmdKmtSend:
if ((FileVar==NULL) && NewFileVar(&FileVar))
{
FileVar->DirLen = 0;
strcpy(FileVar->FullName,ParamFileName);
FileVar->NumFname = 1;
FileVar->NoMsg = TRUE;
DdeCmnd = TRUE;
if (Command[0]==CmdKmtGet)
i = IdKmtGet;
else
i = IdKmtSend;
KermitStart(i);
}
else
return DDE_FNOTPROCESSED;
break;
case CmdLoadKeyMap:
strcpy(ts.KeyCnfFN,ParamFileName);
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdLoadKeyMap,0);
break;
case CmdLogClose:
if (LogVar != NULL) FileTransEnd(OpLog);
break;
case CmdLogOpen:
if ((LogVar==NULL) && NewFileVar(&LogVar))
{
LogVar->DirLen = 0;
LogVar->NoMsg = TRUE;
strcpy(LogVar->FullName,ParamFileName);
ts.TransBin = ParamBinaryFlag;
ts.Append = ParamAppendFlag;
LogStart();
}
else
return DDE_FNOTPROCESSED;
break;
case CmdLogPause:
FLogChangeButton(TRUE);
break;
case CmdLogStart:
FLogChangeButton(FALSE);
break;
case CmdLogWrite:
if (LogVar != NULL)
{
_lwrite(LogVar->FileHandle,
ParamFileName,strlen(ParamFileName));
LogVar->ByteCount =
LogVar->ByteCount + strlen(ParamFileName);
FLogRefreshNum();
}
break;
case CmdQVRecv:
if ((FileVar==NULL) && NewFileVar(&FileVar))
{
FileVar->NoMsg = TRUE;
DdeCmnd = TRUE;
QVStart(IdQVReceive);
}
else
return DDE_FNOTPROCESSED;
break;
case CmdQVSend:
if ((FileVar==NULL) && NewFileVar(&FileVar))
{
FileVar->DirLen = 0;
strcpy(FileVar->FullName,ParamFileName);
FileVar->NumFname = 1;
FileVar->NoMsg = TRUE;
DdeCmnd = TRUE;
QVStart(IdQVSend);
}
else
return DDE_FNOTPROCESSED;
break;
case CmdRestoreSetup:
strcpy(ts.SetupFName,ParamFileName);
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdRestoreSetup,0);
break;
case CmdSendBreak:
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdBreak,0);
break;
case CmdSendFile:
if ((SendVar==NULL) && NewFileVar(&SendVar))
{
SendVar->DirLen = 0;
strcpy(SendVar->FullName,ParamFileName);
ts.TransBin = ParamBinaryFlag;
SendVar->NoMsg = TRUE;
DdeCmnd = TRUE;
FileSendStart();
}
else
return DDE_FNOTPROCESSED;
break;
case CmdSendKCode:
w = HexStr2Word(ParamFileName);
c = HexStr2Word(&ParamFileName[4]);
PostMessage(HVTWin,WM_USER_KEYCODE,w,(LPARAM)c);
break;
case CmdSetEcho:
ts.LocalEcho = ParamBinaryFlag;
if (cv.Ready && cv.TelFlag && (ts.TelEcho>0))
TelChangeEcho();
break;
case CmdSetTitle:
strcpy(ts.Title,ParamFileName);
ChangeTitle();
break;
case CmdShowTT:
switch (ParamFileName[0]) {
case '-': ShowWindow(HVTWin,SW_HIDE); break;
case '0': ShowWindow(HVTWin,SW_MINIMIZE); break;
case '1': ShowWindow(HVTWin,SW_RESTORE); break;
case '2': ShowWindow(HTEKWin,SW_HIDE); break;
case '3': ShowWindow(HTEKWin,SW_MINIMIZE); break;
case '4':
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdCtrlOpenTEK,0);
break;
case '5':
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdCtrlCloseTEK,0);
break;
}
break;
case CmdXmodemRecv:
if ((FileVar==NULL) && NewFileVar(&FileVar))
{
FileVar->DirLen = 0;
strcpy(FileVar->FullName,ParamFileName);
ts.XmodemOpt = ParamXmodemOpt;
ts.XmodemBin = ParamBinaryFlag;
FileVar->NoMsg = TRUE;
DdeCmnd = TRUE;
XMODEMStart(IdXReceive);
}
else
return DDE_FNOTPROCESSED;
break;
case CmdXmodemSend:
if ((FileVar==NULL) && NewFileVar(&FileVar))
{
FileVar->DirLen = 0;
strcpy(FileVar->FullName,ParamFileName);
ts.XmodemOpt = ParamXmodemOpt;
FileVar->NoMsg = TRUE;
DdeCmnd = TRUE;
XMODEMStart(IdXSend);
}
else
return DDE_FNOTPROCESSED;
break;
case CmdZmodemRecv:
if ((FileVar==NULL) && NewFileVar(&FileVar))
{
FileVar->NoMsg = TRUE;
DdeCmnd = TRUE;
ZMODEMStart(IdZReceive);
}
else
return DDE_FNOTPROCESSED;
break;
case CmdZmodemSend:
if ((FileVar==NULL) && NewFileVar(&FileVar))
{
FileVar->DirLen = 0;
strcpy(FileVar->FullName,ParamFileName);
FileVar->NumFname = 1;
ts.XmodemBin = ParamBinaryFlag;
FileVar->NoMsg = TRUE;
DdeCmnd = TRUE;
ZMODEMStart(IdZSend);
}
else
return DDE_FNOTPROCESSED;
break;
default:
return DDE_FNOTPROCESSED;
}
return (HDDEDATA)DDE_FACK;
}
HDDEDATA CALLBACK DdeCallbackProc(UINT CallType, UINT Fmt, HCONV Conv,
HSZ HSz1, HSZ HSz2, HDDEDATA Data, DWORD Data1, DWORD Data2)
{
HDDEDATA Result;
if (Inst==0) return 0;
Result = 0;
switch (CallType) {
case XTYP_WILDCONNECT:
Result = WildConnect(HSz2, HSz1, Fmt);
break;
case XTYP_CONNECT:
if (Conv == 0)
{
if ((DdeCmpStringHandles(Topic, HSz1) == 0) &&
(DdeCmpStringHandles(Service, HSz2) == 0))
{
if (cv.Ready)
SetDdeComReady(1);
Result = (HDDEDATA)TRUE;
}
}
break;
case XTYP_CONNECT_CONFIRM:
ConvH = Conv;
break;
case XTYP_ADVREQ:
case XTYP_REQUEST:
Result = AcceptRequest(HSz2);
break;
case XTYP_POKE:
Result = AcceptPoke(HSz2, Fmt, Data);
case XTYP_ADVSTART:
if ((ConvH!=0) &&
(DdeCmpStringHandles(Topic, HSz1) == 0) &&
(DdeCmpStringHandles(Item, HSz2) == 0) &&
! AdvFlag)
{
AdvFlag = TRUE;
Result = (HDDEDATA)TRUE;
}
break;
case XTYP_ADVSTOP:
if ((ConvH!=0) &&
(DdeCmpStringHandles(Topic, HSz1) == 0) &&
(DdeCmpStringHandles(Item, HSz2) == 0) &&
AdvFlag)
{
AdvFlag = FALSE;
Result = (HDDEDATA)TRUE;
}
break;
case XTYP_DISCONNECT:
ConvH = 0;
PostMessage(HVTWin,WM_USER_DDEEND,0,0);
break;
case XTYP_EXECUTE:
Result = AcceptExecute(HSz1, Data);
} /* switch (CallType) */
return Result;
}
BOOL InitDDE()
{
BOOL Ok;
if (ConvH != 0) return FALSE;
Ok = TRUE;
#ifdef TERATERM32
if (DdeInitialize(&Inst,(PFNCALLBACK)DdeCallbackProc,0,0) == DMLERR_NO_ERROR)
#else
DdeCallbackPtr = (PFNCALLBACK)MakeProcInstance((FARPROC)DdeCallbackProc,
(HINSTANCE)GetWindowWord(HVTWin,GWW_HINSTANCE));
if ((DdeCallbackPtr!=NULL) &&
(DdeInitialize(&Inst,DdeCallbackPtr,0,0) == DMLERR_NO_ERROR))
#endif
{
Service= DdeCreateStringHandle(Inst, ServiceName, CP_WINANSI);
Topic = DdeCreateStringHandle(Inst, TopicName, CP_WINANSI);
Item = DdeCreateStringHandle(Inst, ItemName, CP_WINANSI);
Item2 = DdeCreateStringHandle(Inst, ItemName2, CP_WINANSI);
Ok = DdeNameService(Inst, Service, 0, DNS_REGISTER) != 0;
}
else
Ok = FALSE;
SyncMode = FALSE;
CloseTT = FALSE;
StartupFlag = FALSE;
DDELog = FALSE;
if (Ok)
{
Ok = CreateLogBuf();
if (Ok) DDELog = TRUE;
}
if (! Ok) EndDDE();
return Ok;
}
void SendDDEReady()
{
GetClientHWnd(TopicName);
PostMessage(HWndDdeCli,WM_USER_DDEREADY,0,0);
}
void EndDDE()
{
DWORD Temp;
if (ConvH != 0)
DdeDisconnect(ConvH);
ConvH = 0;
SyncMode = FALSE;
StartupFlag = FALSE;
Temp = Inst;
if (Inst != 0)
{
Inst = 0;
DdeNameService(Temp, Service, 0, DNS_UNREGISTER);
if (Service != 0)
DdeFreeStringHandle(Temp, Service);
Service = 0;
if (Topic != 0)
DdeFreeStringHandle(Temp, Topic);
Topic = 0;
if (Item != 0)
DdeFreeStringHandle(Temp, Item);
Item = 0;
if (Item2 != 0)
DdeFreeStringHandle(Temp, Item2);
Item2 = 0;
DdeUninitialize(Temp);
#ifndef TERATERM32
if (DdeCallbackPtr != NULL)
FreeProcInstance((FARPROC)DdeCallbackPtr);
DdeCallbackPtr = NULL;
#endif
}
TopicName[0] = 0;
if (HWndDdeCli!=NULL)
PostMessage(HWndDdeCli,WM_USER_DDECMNDEND,0,0);
HWndDdeCli = NULL;
AdvFlag = FALSE;
DDELog = FALSE;
FreeLogBuf();
cv.NoMsg = 0;
}
void DDEAdv()
{
if ((ConvH==0) ||
(! AdvFlag) ||
(cv.DCount==0))
return;
if ((! SyncMode) ||
SyncMode && SyncRecv)
{
if (SyncFreeSpace<10)
SyncFreeSpace=0;
else
SyncFreeSpace=SyncFreeSpace-10;
DdePostAdvise(Inst,Topic,Item);
SyncRecv = FALSE;
}
}
void EndDdeCmnd(int Result)
{
if ((ConvH==0) || (HWndDdeCli==NULL) || (! DdeCmnd)) return;
PostMessage(HWndDdeCli,WM_USER_DDECMNDEND,(WPARAM)Result,0);
DdeCmnd = FALSE;
}
void SetDdeComReady(WORD Ready)
{
if (HWndDdeCli==NULL) return;
PostMessage(HWndDdeCli,WM_USER_DDECOMREADY,Ready,0);
}
void RunMacro(PCHAR FName, BOOL Startup)
// FName: macro filename
// Startup: TRUE in case of startup macro execution.
// In this case, the connection to the host will
// made after the link to TT(P)MACRO is established.
{
int i;
char Cmnd[MAXPATHLEN+40];
SetTopic();
if (! InitDDE()) return;
#ifdef TERATERM32
strcpy(Cmnd,"TTPMACRO /D=");
#else
strcpy(Cmnd,"TTMACRO /D=");
#endif
strcat(Cmnd,TopicName);
if (FName!=NULL)
{
strcat(Cmnd," ");
i = strlen(Cmnd);
strcat(Cmnd,FName);
#ifdef TERATERM32
QuoteFName(&Cmnd[i]);
#endif
}
StartupFlag = Startup;
if (Startup)
strcat(Cmnd," /S"); // "startup" flag
if (WinExec(Cmnd,SW_MINIMIZE) < 32)
EndDDE();
}
/* Tera Term
Copyright(C) 1994-1998 T. Teranishi
All rights reserved. */
/* TERATERM.EXE, DDE routines */
#include <ddeml.h>
#ifdef __cplusplus
extern "C" {
#endif
void SetTopic();
BOOL InitDDE();
void SendDDEReady();
void EndDDE();
void DDEAdv();
void EndDdeCmnd(int Result);
void SetDdeComReady(WORD Ready);
void RunMacro(PCHAR FName, BOOL Startup);
extern char TopicName[21];
extern HCONV ConvH;
extern BOOL AdvFlag;
extern BOOL CloseTT;
#ifdef __cplusplus
}
#endif
DDE多线程阻塞和卡顿的问题我还没解决,卡顿30秒