// -----------------------------------------------------
// Функции для работы с библиотекой DDEML
// Клиент DDEML
// -----------------------------------------------------
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <ddeml.h>
#include <dde.h>
#include <mem.h>
#include <string.h>
#pragma hdrstop

#include "ddemlcl.hpp"

HDDEDATA EXPENTRY _export
DDEClientCallback(WORD wType, WORD wFmt, HCONV hConv,
  HSZ hsz1, HSZ hsz2, HDDEDATA hData,
  DWORD dwData1, DWORD dwData2);

// Идентификатор приложения для DDEML
DWORD   idInst;

// Функция обратного вызова для DDE
FARPROC lpDdeProc;

HSZ hszService;
HSZ hszTopic;
HSZ hszItem;

HDDEDATA hData;
DWORD    dwResult;
WORD     wFmt = CF_TEXT;

//-----------------------------------------------------
// Функция DDEClientOpen
// Инициализация DDEML, создание идентификаторов строк
//-----------------------------------------------------
HCONV DDEClientOpen(HINSTANCE hInst,
  LPSTR szService, LPSTR szTopic, LPSTR szItem)
{
  HCONV hConv = NULL;
  
  // Создаем переходник для функции обратного вызова
  lpDdeProc =
    MakeProcInstance((FARPROC)DDEClientCallback, hInst);

  // Инициализируем DDEML
  if(DdeInitialize((LPDWORD)&idInst, (PFNCALLBACK)lpDdeProc,
       APPCMD_CLIENTONLY, 0L))
  {
    return NULL;
  }
  else
  {
    // При успешной инициализации создаем
    // идентификаторы строк для сервиса, раздела
    // и элемента данных
    hszService =
      DdeCreateStringHandle(idInst, szService, CP_WINANSI);
    hszTopic   =
      DdeCreateStringHandle(idInst, szTopic, CP_WINANSI);
    hszItem    =
      DdeCreateStringHandle(idInst, szItem, CP_WINANSI);

    // Устанавливаем канал связи
    hConv =
      DdeConnect(idInst, hszService, hszTopic, (PCONVCONTEXT)NULL);

    // Возвращаем идентификатор созданного канала связи
    return hConv;
  }
}

//-----------------------------------------------------
// Функция DDEClientClose
// Завершение работы с библиотекой DDEML
//-----------------------------------------------------
void DDEClientClose(HCONV hConv)
{
  // Закрываем канал связи
  if(hConv != NULL)
  {
    DdeDisconnect(hConv);
    hConv = NULL;
  }

  // Освобождаем идентификаторы строк
  DdeFreeStringHandle(idInst, hszService);
  DdeFreeStringHandle(idInst, hszTopic);
  DdeFreeStringHandle(idInst, hszItem );

  // Удаляем переходник для функции обратного вызова 
  FreeProcInstance(lpDdeProc);
}

//-----------------------------------------------------
// Функция DDESend
// Передача серверу текстовой строки
//-----------------------------------------------------
BOOL DDESend(HCONV hConv, LPSTR szString)
{
  if(hConv != NULL)
  {
    // Создаем идентификатор данных
    hData = DdeCreateDataHandle (idInst, szString,
       lstrlen(szString) + 1, 0L, hszItem, CF_TEXT, 0);

    // Запускаем транзакцию записи данных
    if(hData != NULL)
      hData = DdeClientTransaction((LPBYTE)hData, -1, hConv,
        hszItem, CF_TEXT, XTYP_POKE, 1000, &dwResult);
      if(hData != NULL)
        return TRUE;
      else
        return FALSE;
  }
  else
    return FALSE;
}

//-----------------------------------------------------
// Функция DDEReceive
// Получение от сервера текстовой строки
//-----------------------------------------------------
BOOL DDEReceive(HCONV hConv, LPSTR szBuf, int nBufSize)
{
  // Запускаем транзакцию чтения данных
  if(hConv != NULL)
  {
    hData = DdeClientTransaction(NULL, 0, hConv,
       hszItem, CF_TEXT, XTYP_REQUEST, 1000, &dwResult);

    // Получаем строку от сервера 
    if(hData != NULL)
    {
      DdeGetData(hData, szBuf, nBufSize, 0L);
      return TRUE;
    }
    else
      return FALSE;
  }
  else
    return FALSE;
}

//-----------------------------------------------------
// Функция DDEClientCallback
// Функция обратного вызова для клиента DDEML
//-----------------------------------------------------
#pragma argsused
HDDEDATA EXPENTRY
DDEClientCallback(WORD wType, WORD wFmt, HCONV hConvX, HSZ hsz1,
    HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2)
{
  switch(wType)
  {
    case XTYP_DISCONNECT:
      return((HDDEDATA) NULL);

    case XTYP_ERROR:
      break;

    case XTYP_XACT_COMPLETE:
      break;
  }
  return((HDDEDATA)NULL);
}

