Интеграция InTuch с приложением на C++

Вопросы, не попадающие в другие разделы.

Интеграция InTuch с приложением на C++

Сообщение Drimascus » Пн апр 16, 2012 2:22 pm

Добрый день, уважаемые господа. Я начинающий специалист и мне необходима Ваша помощь. В InTuch мной был создан тег (например level3). Как реализовать консольное приложение на с++, которое c помощью DDE выводило изменяющееся значение этого тега на экран? Заранее большое смпасибо.
Drimascus
 
Сообщения: 8
Зарегистрирован: Пн апр 16, 2012 2:12 pm

Re: Интеграция InTuch с приложением на C++

Сообщение LexSL » Пн апр 16, 2012 3:07 pm

Доброго дня!
На С++ Вам необходимо следующие функции из библитеки user32.dll использовать:
DdeInitialize, DdeUninitialize, DdeCreateStringHandle, DdeFreeStringHandle, DdeConnect, DdeDisconnect и прочее...
Поищите в инете описание этих функций с примерами, думаю будет все понятно, если в С++ не новичек...
а так, для C# написана очень полезная (для меня :D ) сборка http://ndde.codeplex.com/.

Код: Выделить всё
using Ndde.Client;
....
..
DDEClient client = new DDEClient("view","Tagname");
client.Connect();
string Tag1 = client.Request("Tag1",1000).TrimEnd('\0');
string Tag1Comment = client.Request("Tag1.Comment",1000).TrimEnd('\0');
string Tag1DateTime = client.Request("Tag1.DateString",1000).TrimEnd('\0') + " " + client.Request("Tag1.TimeString",1000).TrimEnd('\0');
//DDE обмен в нашем случае в формате CF_TEXT. InTouch возвращает все значения в виде строки с \0\0\0  в конце, поэтому обрезаем.
double Tag1Value = Convert.ToDouble(Tag1);
client.Disconnect();


Также в архиве со сборкой есть примеры, как получать значения по подписке (организация "горячего" канала)
LexSL
 
Сообщения: 80
Зарегистрирован: Вт дек 14, 2010 2:53 pm

Re: Интеграция InTuch с приложением на C++

Сообщение LexSL » Пн апр 16, 2012 3:25 pm

Drimascus писал(а):В InTuch ....

InTouch :D
LexSL
 
Сообщения: 80
Зарегистрирован: Вт дек 14, 2010 2:53 pm

Re: Интеграция InTuch с приложением на C++

Сообщение Drimascus » Пн апр 16, 2012 3:34 pm

Проблема в том, что используется древняя ОС WIndows NT 4.0 и можно писать только на VS 6.0 и я от этого в шоке. Последний раз использовал С++ лет 8 назад)) в институте.
Я использовал функции, которые Вы привели в своем ответе. Ниже идет пример кода, в котором я пытался вызвать эти функции. Но у меня так и не вышло ничего, вот и очень прошу Вас привести маленький примерчик передачи значения тега из Intuch в приложение на с++, с дальнейшм выводом его на экран

#include "stdafx.h"
#include "windows.h"
#include "ddeml.h"
#include "stdio.h

DWORD inst = 0, res;
char ItemData1[256] = "5", ItemData2[256] = "2";

HDDEDATA CALLBACK exitFunction(UINT uType,UINT uFmt,HCONV hconv,HSZ hsz1,HSZ hsz2,HDDEDATA hdata,DWORD dwData1,DWORD dwData2)
// Программа выхода для обработки запросов от клиентов DDE.
{char forTopic[256] = "", forItem[256] = "", forData[256] = "", forWho[256] = "";


switch (uType & XCLASS_MASK)
{case XCLASS_BOOL : // Подтверждения.
switch (uType)
{case XTYP_CONNECT : case XTYP_CONNECT+XTYPF_NOBLOCK : // Запрос на соединение.
DdeQueryString(inst,hsz1,forTopic,sizeof(forTopic),CP_WINANSI);
DdeQueryString(inst,hsz2,forItem,sizeof(forItem),CP_WINANSI);
printf("Connect %s:%s\n",forTopic,forItem);

return (HDDEDATA)TRUE;
case XTYP_ADVSTART : case XTYP_ADVSTART+XTYPF_NOBLOCK : // Запрос на обновление данных.
DdeQueryString(inst,hsz1,forTopic,sizeof(forTopic),CP_WINANSI);
DdeQueryString(inst,hsz2,forItem,sizeof(forItem),CP_WINANSI);
printf("Start advise %s:%s\n",forTopic,forItem);
printf(" %s=%s",forTopic,forItem);
printf("\n\r");

return (HDDEDATA)TRUE;
case XTYP_ADVSTOP : case XTYP_ADVSTOP+XTYPF_NOBLOCK : // Окончание запроса на обновление данных.
DdeQueryString(inst,hsz1,forTopic,sizeof(forTopic),CP_WINANSI);
DdeQueryString(inst,hsz2,forItem,sizeof(forItem),CP_WINANSI);
printf("Stop advise %s:%s\n",forTopic,forItem);
return (HDDEDATA)TRUE;
default : // Прочие запросы.
printf("bool %d\n",(uType & ~(XCLASS_MASK)));
return (HDDEDATA)TRUE;
}
case XCLASS_DATA : // Блоки данных.
switch (uType)
{case XTYP_REQUEST : // Запрос на чтение данных.
DdeQueryString(inst,hsz1,forTopic,sizeof(forTopic),CP_WINANSI);
DdeQueryString(inst,hsz2,forItem,sizeof(forItem),CP_WINANSI);

if (!strcmpi(forTopic,"TOPIC1") && ! strcmpi(forItem,"ITEM1"))
strcpy(forData,ItemData1);
else if (!strcmpi(forTopic,"TOPIC1") && ! strcmpi(forItem,"ITEM2"))
strcpy(forData,ItemData2);
else return NULL;

printf("request %s:%s = %s\n",forTopic,forItem,forData);
return DdeCreateDataHandle(inst,(unsigned char *)forData,strlen(forData),0,hsz2,CF_TEXT,0);
default :
printf("data %d\n",(uType & ~(XCLASS_MASK)));
return NULL;
}
case XCLASS_FLAGS : // Флаги.
switch (uType)
{case XTYP_POKE : // Запрос на обновление данных.
DdeQueryString(inst,hsz1,forTopic,sizeof(forTopic),CP_WINANSI);
DdeQueryString(inst,hsz2,forItem,sizeof(forItem),CP_WINANSI);
DdeGetData(hdata,(unsigned char *)forData,sizeof(forData),0);

if (!strcmpi(forTopic,"TOPIC1") && ! strcmpi(forItem,"ITEM1")) strcpy(ItemData1,forData);
else if (!strcmpi(forTopic,"TOPIC1") && ! strcmpi(forItem,"ITEM2")) strcpy(ItemData1,forData);
else return NULL;

printf("poke %s:%s = %s\n",forTopic,forItem,forData);
return (HDDEDATA)DDE_FACK;
default :
printf("flag %d %d\n",(uType & ~(XCLASS_MASK)),uType == XTYP_POKE);
return NULL;
}
case XCLASS_NOTIFICATION: // Извещения.
// printf("note %d\n",(uType & ~(XCLASS_MASK)));
return NULL;
default :
printf("undef %d\n",(uType & ~(XCLASS_MASK)));
return NULL;
}
}

int main(int argc, char* argv[])
{
DdeInitialize(&inst,exitFunction,MF_CALLBACKS|MF_CONV|MF_ERRORS|MF_HSZ_INFO|MF_LINKS|MF_POSTMSGS|MF_SENDMSGS,0);

HSZ Sservice = DdeCreateStringHandle(inst,"OUN",CP_WINANSI);
DdeNameService(inst,Sservice,0,DNS_REGISTER);
printf("reg=%d\n",DdeGetLastError(inst));
MessageBox (NULL, "Сервер DDE запущен. Нажмите OK для завершения работы","ВНИМАНИЕ!", 0);

DdeNameService(inst,Sservice,0,DNS_UNREGISTER);
DdeFreeStringHandle(inst,Sservice);

DdeUninitialize(inst);

return 0;
}
Drimascus
 
Сообщения: 8
Зарегистрирован: Пн апр 16, 2012 2:12 pm

Re: Интеграция InTuch с приложением на C++

Сообщение LexSL » Пн апр 16, 2012 4:29 pm

Перво-наперво: зачем вам создавать и регистрировать в системе DDE-сервер?
Drimascus писал(а):HSZ Sservice = DdeCreateStringHandle(inst,"OUN",CP_WINANSI);
DdeNameService(inst,Sservice,0,DNS_REGISTER);


Этого делать нет необходимости - InTouch сам является DDE-сервером!!! Имя сервиса = view, имя топика для доступа к тегам, созданным в InTouch = Tagname.

И рекомендую к прочтению и повторению вот эту статейку: http://frolov-lib.ru/books/bsp/v17/ch3_5.htm, тем более что у вас "древний" NT.
Там есть есть раздел, посвященный как раз созданию клиента.
LexSL
 
Сообщения: 80
Зарегистрирован: Вт дек 14, 2010 2:53 pm

Re: Интеграция InTuch с приложением на C++

Сообщение Drimascus » Пн апр 16, 2012 5:46 pm

Большое спасибо за полезные ссылки, сейчас этим буду заниматься, надеюсь, что получится. Но все же, мне бы хотелось увидеть такой пример, который я просил, т.к. в инете такого я и не нашел. Заранее спасибо...
Drimascus
 
Сообщения: 8
Зарегистрирован: Пн апр 16, 2012 2:12 pm

Re: Интеграция InTuch с приложением на C++

Сообщение LexSL » Пн апр 16, 2012 6:02 pm

Drimascus писал(а):Но все же, мне бы хотелось увидеть такой пример, который я просил, т.к. в инете такого я и не нашел.

Пожалуйста, почаще пользуйтесь поиском, это от "авторов" -- microsoft
http://support.microsoft.com/kb/279721/ru

из примера:

Код: Выделить всё
...
int main(int argc, char* argv[])
{
    char szApp[] = "EXCEL";
    char szTopic[] = "C:\\Test.xls";
    char szItem1[] = "R1C1";
...


Для вас же будет так:

Код: Выделить всё
...
int main(int argc, char* argv[])
{
    char szApp[] = "view";
    char szTopic[] = "Tagname";
    char szItem1[] = "level3";
...


До выполнения программы InTouch должен быть запущен, тег level3 создан
LexSL
 
Сообщения: 80
Зарегистрирован: Вт дек 14, 2010 2:53 pm

Re: Интеграция InTuch с приложением на C++

Сообщение LexSL » Пн апр 16, 2012 6:11 pm

Кстати, сам хотел спросить - на NT вроде же можно поставить Framework 1.1, не пробовали?
LexSL
 
Сообщения: 80
Зарегистрирован: Вт дек 14, 2010 2:53 pm

Re: Интеграция InTuch с приложением на C++

Сообщение Drimascus » Пн апр 16, 2012 7:16 pm

Большое спасибо)) результат тега был выведен на экран. По поводу Framework 1.1 - да его можно поставить, но приложения под NT можно писать только на VS 6.0 и более ранних версиях, увы это так...
Еще раз спасибо за оказанную помощь. Я с InTouch воюю только второй день. Вы очень помогли. Теперь буду разбираться, как постоянно отслеживать изменение результата, то есть реализовать с C++ такой вариант, как работа InTouch с Excel....
Drimascus
 
Сообщения: 8
Зарегистрирован: Пн апр 16, 2012 2:12 pm

Re: Интеграция InTuch с приложением на C++

Сообщение Drimascus » Пн апр 16, 2012 7:18 pm

Когда изменение тега отображается в Excel по команде =view|TagName|level3
Drimascus
 
Сообщения: 8
Зарегистрирован: Пн апр 16, 2012 2:12 pm

Re: Интеграция InTuch с приложением на C++

Сообщение LexSL » Пн апр 16, 2012 8:03 pm

LexSL писал(а):Теперь буду разбираться, как постоянно отслеживать изменение результата, то есть реализовать с C++ такой вариант, как работа InTouch с Excel....

Для начала, я думаю, будет достаточно таймера, в обработчик которого и нужно подсунуть выполнение запроса по DDE. Учтите только, что таймеру промежуток времени не надо ставить в миллисекунды, потому что может не успеть ответ от предыдущего запроса придти. Мне, например, хватало обновления каждые 5 сек.
Это уже вы сами решайте, в зависимости от "жесткости" требований по обновлению.

А отслеживать постоянно изменения - это организация "горячего" канала(подписка) - нужна callback функция.
LexSL
 
Сообщения: 80
Зарегистрирован: Вт дек 14, 2010 2:53 pm

Re: Интеграция InTuch с приложением на C++

Сообщение Drimascus » Вт апр 17, 2012 10:54 am

А примерчик не подскажете?
Drimascus
 
Сообщения: 8
Зарегистрирован: Пн апр 16, 2012 2:12 pm

Re: Интеграция InTuch с приложением на C++

Сообщение Drimascus » Вт апр 17, 2012 10:55 am

на основе текущего примера...
Drimascus
 
Сообщения: 8
Зарегистрирован: Пн апр 16, 2012 2:12 pm

Re: Интеграция InTuch с приложением на C++

Сообщение LexSL » Вт апр 17, 2012 12:12 pm

Попробуйте так, сам не проверял...
ключевые слова - SetTimer, KillTimer

Код: Выделить всё
#include <windows.h>
...
//объявляете функцию обратного вызова:
void CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{
 DDERequest(idInst, hConv, szItem1, szDesc1);
}

int main(....
{
MSG Msg;
int Counter=0;
...
iReturn = DdeInitialize(&idInst, (PFNCALLBACK)DdeCallback,
                            APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0 );
    if (iReturn!=DMLERR_NO_ERROR)
    {
        printf("DDE Initialization Failed: 0x%04x\n", iReturn);
        Sleep(1500);
        return 0;
    }
....
...
//устанавливаем таймер на 5 сек
UINT TimerId = SetTimer(NULL, 0, 5000, &TimerProc);

if (!TimerId)
{
printf("Error set timer");
return 0;
}

while (GetMessage(&Msg, NULL, 0, 0))
         {
   ++Counter;
   if (Msg.message == WM_TIMER)
        cout << "Counter: " << Counter << "; timer message\n";
   else
       cout << "Counter: " << Counter << "; message: " << Msg.message << '\n';
   DispatchMessage(&Msg);
   }

KillTimer(NULL, TimerId);
DdeDisconnect(hConv);
DdeUninitialize(idInst);
Sleep(3000);
return 1;

}
LexSL
 
Сообщения: 80
Зарегистрирован: Вт дек 14, 2010 2:53 pm

Re: Интеграция InTuch с приложением на C++

Сообщение LexSL » Вт апр 17, 2012 3:13 pm

по "горячему" обмену по DDE:
пишем DDE сервер для SCADA
с этого я сам начинал:
Организация "горячего" обмена по DDE между Microsoft Excel и приложением .NET. и переделывал под InTouch.
Также выше уже приводил ссылку на сборку NDde,

подробнее об обмене данными по DDE, естественно у первоисточника протокола :)
LexSL
 
Сообщения: 80
Зарегистрирован: Вт дек 14, 2010 2:53 pm

Re: Интеграция InTuch с приложением на C++

Сообщение Drimascus » Вт апр 17, 2012 3:37 pm

Большое спасибо, будем пробовать :)
Drimascus
 
Сообщения: 8
Зарегистрирован: Пн апр 16, 2012 2:12 pm

Re: Интеграция InTuch с приложением на C++

Сообщение LexSL » Вт апр 17, 2012 4:05 pm

LexSL писал(а):
Код: Выделить всё
KillTimer(NULL, TimerId);
DdeDisconnect(hConv);
DdeUninitialize(idInst);
Sleep(3000);
return 1;



Я конечно, дико извиняюсь :D , только после цикла while (GetMessage(...)) до строк, где таймер уничтожается и происходит дисконнект, дело не дойдет :)
чтобы корректно убрать таймер из системы и сделать дисконнект, надо еще обрабатывать сообщение WM_QUIT
LexSL
 
Сообщения: 80
Зарегистрирован: Вт дек 14, 2010 2:53 pm


Вернуться в Другое

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7