C语言实现的一个DDE

时间:2022-12-24 23:58:40
/* Tera Term
 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秒