// -----------------------------------------------------
// Функции для работы с библиотекой 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 "ddemlsr.hpp"

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

// Идентификатор приложения, полученный после регистрации в
// библиотеке DDEML
DWORD idInst = 0L;

FARPROC lpDdeProc;
HSZ hszService = NULL;
HSZ hszTopic   = NULL;
HSZ hszItem    = NULL;

// Идентификатор канала
HCONV hConvApp = NULL;

// Буфер для приема данных
char szDDEData[200];

// Версия сервера. Эта текстовая строка
// передается клиенту по его запросу
char szDDEServerVersion[] =
  "DDEML Server v.1.0, (C) Frolov A.V.";

//-----------------------------------------------------
// Функция DDEServerOpen
// Инициализация библиотеки DDEML
//-----------------------------------------------------
BOOL DDEServerOpen(HINSTANCE hInst,
  LPSTR szService, LPSTR szTopic, LPSTR szItem)
{
  int rc;

  // Создаем переходник для функции обратного вызова
  lpDdeProc =
    MakeProcInstance((FARPROC)DDEServerCallback, hInst);

  // Выполняем инициализацию
  if(DdeInitialize((LPDWORD)&idInst, (PFNCALLBACK)lpDdeProc,
       APPCLASS_STANDARD, 0L))
  {
    return FALSE;
  }

  // После успешной инициализации получаем идентификаторы
  // строк для сервиса, раздела и элемента данных
  else
  {
    hszService =
      DdeCreateStringHandle(idInst, szService, CP_WINANSI);
    hszTopic   =
      DdeCreateStringHandle(idInst, szTopic, CP_WINANSI);
    hszItem    =
      DdeCreateStringHandle(idInst, szItem, CP_WINANSI);

    // Регистрируем сервис
    DdeNameService(idInst, hszService, (HSZ)NULL, DNS_REGISTER);
    return TRUE;
  }
}

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

  // Сервис больше не доступен
  DdeNameService(idInst, hszService, (HSZ)NULL,
    DNS_UNREGISTER);

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

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

//-----------------------------------------------------
// Функция DDEServerCallback
// Функция обратного вызова для сервера DDEML
//-----------------------------------------------------
#pragma argsused
HDDEDATA EXPENTRY _export
DDEServerCallback(WORD wType,
  WORD wFmt, HCONV hConv, HSZ hsz1, HSZ hsz2,
  HDDEDATA hData, DWORD dwData1, DWORD dwData2)
{
   switch(wType)
   {
      // Создание канала передачи данных
      case XTYP_CONNECT:
      {
        // Если сервис поддерживается, возвращаем
        // признак успешного создания канала
        if((HSZ)hsz2==(HSZ)hszService)
           return((HDDEDATA)TRUE);
        else
          return((HDDEDATA)FALSE);
      }

      // Запрос данных от сервера
      case XTYP_REQUEST:
      {
        // Создаем идентификатор данных
        hData = DdeCreateDataHandle(idInst,
          szDDEServerVersion, lstrlen(szDDEServerVersion) + 1,
          0L, hszItem, CF_TEXT, 0);

        // В случае успеха возвращаем созданный идентификатор
        if(hData != NULL)
          return(hData);
        else
          return(NULL);
      }

      // Запрос на выполнение команды, отрабатывается вхолостую
      case XTYP_EXECUTE:
         break;

      // Передача данных серверу
      case XTYP_POKE:
      {
        // Проверяем элемент данных
        if(hsz1 == hszTopic)
        {
          // Получаем данные
          DdeGetData(hData, (LPBYTE) szDDEData, 200L, 0L);

          // Отображаем принятые данные на экране
          if(szDDEData != NULL)
          {
            MessageBox(NULL, szDDEData,
              "DDEML Server",
              MB_OK | MB_SYSTEMMODAL | MB_ICONINFORMATION);

            // Признак успешного завершения транзакции
            return((HDDEDATA)DDE_FACK);
          }
        }
        else
          return((HDDEDATA)NULL);
        break;
      }

      // Подтверждение создания канала
      case XTYP_CONNECT_CONFIRM:
      {
        // Сохраняем идентификатор канала 
        hConvApp = hConv;
        break;
      }

      // Завершение работы канала
      case XTYP_DISCONNECT:
      {
        hConvApp = NULL;
        break;
      }

      // Ошибка
      case XTYP_ERROR:
      {
        break;
      }
   }
   return((HDDEDATA)NULL);
}
