- Обязательно представиться на русском языке кириллицей (заполнить поле "Имя").
- Фиктивные имена мы не приветствуем. Ивановых и Пупкиных здесь уже достаточно.
- Не писать свой вопрос в первую попавшуюся тему - вместо этого создать новую тему.
- За поиск, предложение и обсуждение пиратского ПО и средств взлома - бан без предупреждения.
- Рекламу и частные объявления "куплю/продам/есть халтура" мы не размещаем ни на каких условиях.
- Перед тем как что-то написать - читать здесь и здесь, а студентам - обязательно здесь.
- Не надо писать в ЛС администраторам свои технические вопросы. Администраторы форума отлично знают как работает форум, а не все-все контроллеры, о которых тут пишут.
Использование DMGetValue
-
- здесь недавно
- Сообщения: 10
- Зарегистрирован: 22 сен 2014, 18:30
- Имя: Иванов Игнат Петрович
- Страна: Беларусь
- город/регион: Минск
- Благодарил (а): 2 раза
Использование DMGetValue
Добрый день! Использую функцию DMGetValue (DMCLIENT.dll),точнее пытаюсь:) И возник вопрос как вытянуть значение тэга из переменной dmValue структуры DM_VAR_UPDATE_STRUCT. Тип у нее VARIANT, как с ним работать? Вопрос больше по знанию Си,чем о WinCC, но буду рад и примеру с рабочим кодом.
Заранее Спасибо!
Заранее Спасибо!
-
- осмотрелся
- Сообщения: 192
- Зарегистрирован: 16 дек 2011, 15:13
- Имя: Алексей
- Страна: Россия
- Благодарил (а): 65 раз
- Поблагодарили: 46 раз
Использование DMGetValue
Примеры есть в ODK, как и описание структур и методов.
Но если коротко, то :
Параметры:
lpdmVarKey - указатель на массив (на первый элемент массива) структур DM_VARKEY
dwItems - кол-во элементов в массиве
lpdmvus - указатель на массив структур DM_VAR_UPDATE_STRUCT. В этот массив WinCC (Data Manager) запишет данные.
lpdmError - указатель на структуру CMN_ERROR. В нее WinCC запишет, если при выполнении функции произошла ошибка.
А дальше просто (взято из примера ODK):
Дополнительно хочу отметить, что перед получением данных необходимо установить соединение с DataManager функцией DMConnect, а по завершению DMDisconnect.
Но если коротко, то :
Код: Выделить всё
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
}
-
- здесь недавно
- Сообщения: 10
- Зарегистрирован: 22 сен 2014, 18:30
- Имя: Иванов Игнат Петрович
- Страна: Беларусь
- город/регион: Минск
- Благодарил (а): 2 раза
Использование DMGetValue
Вот попробовал..При попытке указать тип переменой для 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)
}
-
- осмотрелся
- Сообщения: 192
- Зарегистрирован: 16 дек 2011, 15:13
- Имя: Алексей
- Страна: Россия
- Благодарил (а): 65 раз
- Поблагодарили: 46 раз
Использование DMGetValue
Код: Выделить всё
b = DMGetValue(&Tag.szName,1,&VarUpStruct,&scError);
Что если так?
Код: Выделить всё
b = DMGetValue(Tag,1,VarUpStruct,&scError);
-
- здесь недавно
- Сообщения: 10
- Зарегистрирован: 22 сен 2014, 18:30
- Имя: Иванов Игнат Петрович
- Страна: Беларусь
- город/регион: Минск
- Благодарил (а): 2 раза
Использование DMGetValue
Извиняюсь, с ошибкой написал. так и использую.
Проблема именно при указании типа переменной в dmValue, при этом тип (VarUpStruct.dmTypeRef.dwType) и размер тега (VarUpStruct.dmTypeRef.dwSize) определяется верно.
Код: Выделить всё
b = DMGetValue(&Tag,1,&VarUpStruct,&scError);
Проблема именно при указании типа переменной в dmValue, при этом тип (VarUpStruct.dmTypeRef.dwType) и размер тега (VarUpStruct.dmTypeRef.dwSize) определяется верно.
-
- осмотрелся
- Сообщения: 192
- Зарегистрирован: 16 дек 2011, 15:13
- Имя: Алексей
- Страна: Россия
- Благодарил (а): 65 раз
- Поблагодарили: 46 раз
Использование DMGetValue
Что возвращает DMConnect? Должен 1(true). Как и DMGetValue.
Сейчас попробовал Ваш пример.
У меня все считалось (см. рис)
Сейчас попробовал Ваш пример.
У меня все считалось (см. рис)
У вас нет необходимых прав для просмотра вложений в этом сообщении.
-
- здесь недавно
- Сообщения: 10
- Зарегистрирован: 22 сен 2014, 18:30
- Имя: Иванов Игнат Петрович
- Страна: Беларусь
- город/регион: Минск
- Благодарил (а): 2 раза
Использование DMGetValue
Хм..DMConnect возвращает 0 и текст сообщения "Connection to Data Manadger already established". У меня было предположение, что WinCC при инициализации RT подключается сам к DM. А DMGetValue возвращает 1.
Наверное попробую переустановить ODK.
Наверное попробую переустановить ODK.
-
- осмотрелся
- Сообщения: 192
- Зарегистрирован: 16 дек 2011, 15:13
- Имя: Алексей
- Страна: Россия
- Благодарил (а): 65 раз
- Поблагодарили: 46 раз
Использование DMGetValue
Спрошу: Вы Runtime запустили? и pdl с, например IO Field, привязанным к тегу создали. Потому что есть нюанс - WinCC не опрашивает теги, которые не участвуют в отображении, не используются в AlarmLogging, TagLogging.
А еще, если делать вызов так: то в scError будет ошибка и возвращается false
А если передать какую либо строку (типа - наименование приложения) вот так:
то подключение происходит нормально
А еще, если делать вызов так:
Код: Выделить всё
b = DMConnect(NULL, NULL, NULL, &scError);
А если передать какую либо строку (типа - наименование приложения) вот так:
Код: Выделить всё
TCHAR szAppName[255];
wcscpy(szAppName, L"AppName");
b = DMConnect(szAppName, NULL, NULL, &scError);
-
- здесь недавно
- Сообщения: 10
- Зарегистрирован: 22 сен 2014, 18:30
- Имя: Иванов Игнат Петрович
- Страна: Беларусь
- город/регион: Минск
- Благодарил (а): 2 раза
Использование DMGetValue
На текущий момент я пробую из скриптов WinCC и ошибка выскакивает в момент компиляции. Попробую сделать чтение из внешнего приложения.
Спасибо за помощь!
Спасибо за помощь!
-
- осмотрелся
- Сообщения: 192
- Зарегистрирован: 16 дек 2011, 15:13
- Имя: Алексей
- Страна: Россия
- Благодарил (а): 65 раз
- Поблагодарили: 46 раз
Использование DMGetValue
Может я чего-то не понимаю, но ...зачем?))) из скриптов WinCC получать значения тегов, используя ODK?
-
- здесь недавно
- Сообщения: 10
- Зарегистрирован: 22 сен 2014, 18:30
- Имя: Иванов Игнат Петрович
- Страна: Беларусь
- город/регион: Минск
- Благодарил (а): 2 раза
Использование DMGetValue
Пока что для "попробовать", а так естественно для внешнего приложения это всё.