На форуме обязательно:
  1. Заполнить свой профиль НА РУССКОМ ЯЗЫКЕ КИРИЛЛИЦЕЙ. См. Правила, п.2.d.
  2. Не писать свой вопрос в первую попавшуюся тему, а вместо этого создать свою. См. Правила, п.3.a.

Рекламу мы не размещаем ни на каких условиях.

Использование DMGetValue

Ответить

Автор темы
ignatS
здесь недавно
здесь недавно
Сообщения: 10
Зарегистрирован: 22 сен 2014, 17:30
Имя: Иванов Игнат Петрович
Благодарил (а): 2 раза

Использование DMGetValue

Сообщение ignatS » 09 окт 2018, 15:29

Добрый день! Использую функцию DMGetValue (DMCLIENT.dll),точнее пытаюсь:) И возник вопрос как вытянуть значение тэга из переменной dmValue структуры DM_VAR_UPDATE_STRUCT. Тип у нее VARIANT, как с ним работать? Вопрос больше по знанию Си,чем о WinCC, но буду рад и примеру с рабочим кодом.

Заранее Спасибо!


LexSL
здесь недавно
здесь недавно
Сообщения: 94
Зарегистрирован: 16 дек 2011, 14:13
Имя: Михайлов Алексей
Поблагодарили: 13 раз

Использование DMGetValue

Сообщение LexSL » 11 окт 2018, 11:48

Примеры есть в ODK, как и описание структур и методов.
Но если коротко, то :

Код: Выделить всё

BOOL DMGetValue (
        LPDM_VARKEY               lpdmVarKey,
        DWORD                     dwItems,
        LPDM_VAR_UPDATE_STRUCT    lpdmvus,
        LPCMN_ERROR               lpdmError);
Параметры:
lpdmVarKey - указатель на массив (на первый элемент массива) структур DM_VARKEY
dwItems - кол-во элементов в массиве
lpdmvus - указатель на массив структур DM_VAR_UPDATE_STRUCT. В этот массив WinCC (Data Manager) запишет данные.
lpdmError - указатель на структуру CMN_ERROR. В нее WinCC запишет, если при выполнении функции произошла ошибка.
А дальше просто (взято из примера ODK):

Код: Выделить всё

CMN_ERROR Error; //для возврата ошибки
BOOL ret = FALSE; //для возврата результата вызова функции
const short int nNum = 11; // tagcount - число тегов
	//объявление имен тегов
    TCHAR TagNames[nNum][nTextMax]=
    {
        "VAR_1_BOOL",     // boolVal;   // VT_BOOL.
        "VAR_2_BYTE",     // bVal;              // VT_UI1
        "VAR_3_SBYTE",    // iVal;              // VT_I2
        "VAR_4_WORD",     // lVal       // VT_I4
        "VAR_5_SWORD",    // iVal       // VT_I2
        "VAR_6_DWORD",    // dblVal     // VT_R8
        "VAR_7_SDWORD",   // lVal       // VT_I4
        "VAR_8_FLOAT",    // fltVal     // VT_R4
        "VAR_9_DOUBLE",   // dblVal     // VT_R8
        "VAR_A_TEXT8",    // bstrVal    // VT_BSTR
        "VAR_B_TEXT16"    // bstrVal    // VT_BSTR
    };
	
	DM_VARKEY VarKey[nNum]; //объявляем массив тегов, значения которых будем запрашивать
    DM_VAR_UPDATE_STRUCT VarUp[nNum]; //объявляем массив для получения данных

	//выделяем память под массивы и стуктуры
    memset(&VarUp, 0, sizeof(DM_VAR_UPDATE_STRUCT) * nNum); 
    memset(&VarKey,0, sizeof(DM_VARKEY) * nNum);
    memset(&Error,0,sizeof(Error));

	//заполняем массив VarKey
	for(int iRead = 0; iRead < nNum; iRead++)
	{
		VarKey[iRead].dwKeyType = DM_VARKEY_NAME; //указание на то, чтобы WinCC брал имя тега (есть еще DM_VARKEY_ID - по идентификатору тега в базе данных WinCC)
		VarKey[iRead].dwID = 0; //0 потому что запрашиваем по имени
		strcpy( VarKey[iRead].szName, &TagNames[iRead][0]); //копируем имя тега
		VarKey[iRead].lpvUserData = (VOID *) iRead; //в UserData можно вносить все что угодно, в данном случае вносится порядковый номер тега в массиве.
	}
	
	ret = DMGetValue(VarKey, nNum, VarUp, &Error); // запрашиваем данные
	
	//дальше разбор данных в зависимости от типа данных
	if(ret != FALSE)
	{
		for(int iOut=0; iOut < nNum; iOut++)
		{
			switch(VarUp[iOut].dmTypeRef.dwType) //dwType указывает на тип тега
			{
				case DM_VARTYPE_BIT: //vt = 3    VT_I4  = 3
				{
					sprintf(szText, "Index=%d Name=%s ID=%d Value=%d",
						iOut, VarUp[iOut].dmVarKey.szName, VarUp[iOut].dmVarKey.dwID,
						VarUp[iOut].dmValue.boolVal); 	//dmValue содержит значение bool
					break;
				}
				case DM_VARTYPE_BYTE:  //vt = 17  VT_UI1 = 17
				{
					sprintf(szText, "Index=%d Name=%s ID=%d Value=%d",
						iOut, VarUp[iOut].dmVarKey.szName, VarUp[iOut].dmVarKey.dwID,
						VarUp[iOut].dmValue.bVal); //dmValue содержит значение byte
					break;
				}
				case DM_VARTYPE_SBYTE:  //vt = 2   VT_I2        = 2
				{
					sprintf(szText, "Index=%d Name=%s ID=%d Value=%d",
						iOut, VarUp[iOut].dmVarKey.szName, VarUp[iOut].dmVarKey.dwID,
						VarUp[iOut].dmValue.iVal); //dmValue содержит значение знаковый byte (signed)
					break;
				}
				case DM_VARTYPE_WORD:  //vt = 3     VT_I4       = 3
				{
					sprintf(szText, "Index=%d Name=%s ID=%d Value=%d",
						iOut, VarUp[iOut].dmVarKey.szName, VarUp[iOut].dmVarKey.dwID,
						VarUp[iOut].dmValue.lVal); //dmValue содержит значение беззнаковое целое (unsigned)
					break;
				}
				case DM_VARTYPE_SWORD:  //vt = 2        VT_I2   = 2
				{ 
					sprintf(szText, "Index=%d Name=%s ID=%d Value=%d",
						iOut, VarUp[iOut].dmVarKey.szName, VarUp[iOut].dmVarKey.dwID,
						VarUp[iOut].dmValue.iVal); //dmValue содержит значение знаковое целое (signed)
					break;
				}
				case DM_VARTYPE_DWORD:  //vt = 5        VT_R8   = 5
				{
					sprintf(szText, "Index=%d Name=%s ID=%d Value=%d",
						iOut, VarUp[iOut].dmVarKey.szName, VarUp[iOut].dmVarKey.dwID,
						VarUp[iOut].dmValue.dblVal); //dmValue содержит значение двойное целое (здесь dblVal - 4 байта в памяти равно DWORD)
					break;
				}
				case DM_VARTYPE_SDWORD: //vt = 3        VT_I4   = 3
				{
					sprintf(szText, "Index=%d Name=%s ID=%d Value=%d",
						iOut, VarUp[iOut].dmVarKey.szName, VarUp[iOut].dmVarKey.dwID,
						VarUp[iOut].dmValue.lVal);//dmValue содержит значение двойное целое (здесь dblVal - 4 байта в памяти равно DWORD)
					break;
				}
				case DM_VARTYPE_FLOAT:   //vt = 4   VT_R4       = 4
				{
					sprintf(szText, "Index=%d Name=%s ID=%d Value=%f",
						iOut, VarUp[iOut].dmVarKey.szName, VarUp[iOut].dmVarKey.dwID,
						VarUp[iOut].dmValue.fltVal);//dmValue содержит значение float IEEE-754
					break;
				}
				case DM_VARTYPE_DOUBLE:  //vt = 5   VT_R8       = 5
				{
					sprintf(szText, "Index=%d Name=%s ID=%d Value=%f",
						iOut, VarUp[iOut].dmVarKey.szName, VarUp[iOut].dmVarKey.dwID,
						VarUp[iOut].dmValue.dblVal);//dmValue содержит значение double 4 байта
					break;
				}
				case DM_VARTYPE_TEXT_8:   //vt = 8      VT_BSTR = 8
				{
					ret = WideCharToMultiByte( CP_ACP,(DWORD)0,VarUp[iOut].dmValue.bstrVal, ////dmValue содержит значение строки BSTR
											-1,(LPSTR)&BstrValue[0],128,NULL,NULL);
					sprintf(szText, "Index=%d Name=%s ID=%d StrValue=%s",
						iOut, VarUp[iOut].dmVarKey.szName, VarUp[iOut].dmVarKey.dwID,BstrValue);
					break;
				}
				case DM_VARTYPE_TEXT_16:  // vt = 8   VT_BSTR   = 8
				{
					ret = WideCharToMultiByte( CP_ACP,(DWORD)0,VarUp[iOut].dmValue.bstrVal,////dmValue содержит значение строки Unicode
											-1,(LPSTR)&BstrValue[0],128,NULL,NULL);
					sprintf(szText, "Index=%d Name=%s ID=%d StrValue=%s",
							iOut, VarUp[iOut].dmVarKey.szName, VarUp[iOut].dmVarKey.dwID,BstrValue);
					break;
				}
				default:
					break;
			}// end switch case
			ODKTrace(szText);
			//printf("%s\r\n",szText);
			VariantClear( &VarUp[iOut].dmValue );
		}//end for
	}
Дополнительно хочу отметить, что перед получением данных необходимо установить соединение с DataManager функцией DMConnect, а по завершению DMDisconnect.


Автор темы
ignatS
здесь недавно
здесь недавно
Сообщения: 10
Зарегистрирован: 22 сен 2014, 17:30
Имя: Иванов Игнат Петрович
Благодарил (а): 2 раза

Использование DMGetValue

Сообщение ignatS » 12 окт 2018, 13:21

Спасибо,буду разбираться. В хелпе ODK видимо плохо искал.


Автор темы
ignatS
здесь недавно
здесь недавно
Сообщения: 10
Зарегистрирован: 22 сен 2014, 17:30
Имя: Иванов Игнат Петрович
Благодарил (а): 2 раза

Использование DMGetValue

Сообщение ignatS » 15 окт 2018, 14:57

Вот попробовал..При попытке указать тип переменой для dmValue выдает ошибку. Я так понимаю надо корректно указать header?
unknow struct/union member
.

Код: Выделить всё

#include "apdefap.h"

void Get()
{
  BOOL b;
  char Buf[1000];
  CMN_ERROR scError;
  DM_VARKEY Tag;
  DM_VAR_UPDATE_STRUCT VarUpStruct;

  memset(&VarUpStruct,0,sizeof(DM_VAR_UPDATE_STRUCT))
  memset(&Tag,0,sizeof(DM_VARKEY))
  memset(&scError,0,sizeof(CMN_ERROR))


          Tag.dwKeyType = DM_VARKEY_NAME; 
          Tag.dwID = 0; 
          Tag.lpvUserData = NULL;
          strcpy(Tag,"TAG");
          
	  b = DMConnect(NULL, NULL, NULL, &scError);
	  printf( szErrorText: %s\r\n", scError.szErrorText);
	  //чтение 
	  b = DMGetValue(&Tag.szName,1,&VarUpStruct,&scError);
	  

	  printf( "Тип переменной: %d\r\n", VarUpStruct.dmTypeRef.dwType);
	  printf( "Размер переменной: %d\r\n", VarUpStruct.dmTypeRef.dwSize);
	  printf( "Значение переменной: %f\r\n", VarUpStruct.dmValue.fltVal);
	  
  VariantClear(&VarUpStruct.dmValue)
}

:ges_help:


LexSL
здесь недавно
здесь недавно
Сообщения: 94
Зарегистрирован: 16 дек 2011, 14:13
Имя: Михайлов Алексей
Поблагодарили: 13 раз

Использование DMGetValue

Сообщение LexSL » 15 окт 2018, 16:22

Код: Выделить всё

b = DMGetValue(&Tag.szName,1,&VarUpStruct,&scError);
По моему ошибка здесь. Вы передали адрес не структуры DM_VARKEY, а адрес строки szName.
Что если так?

Код: Выделить всё

b = DMGetValue(Tag,1,VarUpStruct,&scError);


Автор темы
ignatS
здесь недавно
здесь недавно
Сообщения: 10
Зарегистрирован: 22 сен 2014, 17:30
Имя: Иванов Игнат Петрович
Благодарил (а): 2 раза

Использование DMGetValue

Сообщение ignatS » 15 окт 2018, 16:30

Извиняюсь, с ошибкой написал.

Код: Выделить всё

b = DMGetValue(&Tag,1,&VarUpStruct,&scError);
так и использую.
Проблема именно при указании типа переменной в dmValue, при этом тип (VarUpStruct.dmTypeRef.dwType) и размер тега (VarUpStruct.dmTypeRef.dwSize) определяется верно.


LexSL
здесь недавно
здесь недавно
Сообщения: 94
Зарегистрирован: 16 дек 2011, 14:13
Имя: Михайлов Алексей
Поблагодарили: 13 раз

Использование DMGetValue

Сообщение LexSL » 15 окт 2018, 17:36

Что возвращает DMConnect? Должен 1(true). Как и DMGetValue.
Сейчас попробовал Ваш пример.
У меня все считалось (см. рис)
tmpFlt.png
У вас нет необходимых прав для просмотра вложений в этом сообщении.


Автор темы
ignatS
здесь недавно
здесь недавно
Сообщения: 10
Зарегистрирован: 22 сен 2014, 17:30
Имя: Иванов Игнат Петрович
Благодарил (а): 2 раза

Использование DMGetValue

Сообщение ignatS » 15 окт 2018, 17:51

Хм..DMConnect возвращает 0 и текст сообщения "Connection to Data Manadger already established". У меня было предположение, что WinCC при инициализации RT подключается сам к DM. А DMGetValue возвращает 1.
Наверное попробую переустановить ODK.


LexSL
здесь недавно
здесь недавно
Сообщения: 94
Зарегистрирован: 16 дек 2011, 14:13
Имя: Михайлов Алексей
Поблагодарили: 13 раз

Использование DMGetValue

Сообщение LexSL » 16 окт 2018, 08:41

Спрошу: Вы Runtime запустили? и pdl с, например IO Field, привязанным к тегу создали. Потому что есть нюанс - WinCC не опрашивает теги, которые не участвуют в отображении, не используются в AlarmLogging, TagLogging.
А еще, если делать вызов так:

Код: Выделить всё

b = DMConnect(NULL, NULL, NULL, &scError);
то в scError будет ошибка и возвращается false
А если передать какую либо строку (типа - наименование приложения) вот так:

Код: Выделить всё

TCHAR szAppName[255];
wcscpy(szAppName, L"AppName");
b = DMConnect(szAppName, NULL, NULL, &scError);
то подключение происходит нормально


Автор темы
ignatS
здесь недавно
здесь недавно
Сообщения: 10
Зарегистрирован: 22 сен 2014, 17:30
Имя: Иванов Игнат Петрович
Благодарил (а): 2 раза

Использование DMGetValue

Сообщение ignatS » 16 окт 2018, 14:19

На текущий момент я пробую из скриптов WinCC и ошибка выскакивает в момент компиляции. Попробую сделать чтение из внешнего приложения.
Спасибо за помощь!


LexSL
здесь недавно
здесь недавно
Сообщения: 94
Зарегистрирован: 16 дек 2011, 14:13
Имя: Михайлов Алексей
Поблагодарили: 13 раз

Использование DMGetValue

Сообщение LexSL » 16 окт 2018, 16:18

ignatS писал(а):
16 окт 2018, 14:19
На текущий момент я пробую из скриптов WinCC
Может я чего-то не понимаю, но ...зачем?))) из скриптов WinCC получать значения тегов, используя ODK?


Автор темы
ignatS
здесь недавно
здесь недавно
Сообщения: 10
Зарегистрирован: 22 сен 2014, 17:30
Имя: Иванов Игнат Петрович
Благодарил (а): 2 раза

Использование DMGetValue

Сообщение ignatS » 16 окт 2018, 16:41

Пока что для "попробовать", а так естественно для внешнего приложения это всё.

Ответить

Вернуться в «WinCC»