Call library function node

Простейшие вопросы в области инженерной разработки
Ответить
Boris_K
developer
developer
Сообщения: 281
Зарегистрирован: 28 янв 2015, 14:25
Версия LabVIEW: 2012 Pro

Call library function node

Сообщение Boris_K »

Вызываю функцию из сторонней dll. В принципе всё работает, но есть неясности, как. Перерыл весь хелп на тему. Вот на конкретном примере:

Функция (конвенция __stdcall) возвращает указатель на строку, а принимает 1 параметр, это указатель на unsigned long int (то есть в адрес по этому указателю она также выводит некоторое значение). В меню Configure всё настроил соотв. образом, "String format" - C string pointer, а для передаваемого параметра "Pass" - Pointer to value. Готовый вид узла на скрине. Вот собсно вопросы.

1) С выходного терминала узла уже передаётся сама строка, а не указатель, то есть, как я понял, :labview: автоматически считывает строку по адресу, который выдала функция? А если я хочу далее манипулировать именно с самим указателем? И где найти функции для работы с указателями (pointers), то есть получение указателя, чтение данных из указателя? Не нашёл в хелпе.

2) Теперь про параметр. По идее, я вначале должен получить указатель на какую-то 4-байтовую переменную, а затем этот указатель подключить к левому терминалу (и далее считывать с правого напротив), но всё работает, если ничего не подключать. Это корректный способ? Что тогда делает :labview: , просто создаёт где-то в памяти область нужного размера (4 байт в данном случае), и использует её при этой операции?

3) Чем отличаются настройки Run in UI thread / Run in any thread? Из названия понятно, что "работает либо в потоке польз. интерфейса, либо в любом потоке", но в чём её смысл? По идее должно работать в том потоке, из которого я вызвал сабж. В хелпе как-то мутно написано. Если не трудно, объясните по-человечески.
Вложения
Безымянный.png
Безымянный.png (2.11 КБ) 7887 просмотров
Race conditions - опасный и скользкий баг!
Аватара пользователя
dadreamer

Activity Professionalism Автор
professor
professor
Сообщения: 3926
Зарегистрирован: 17 фев 2013, 16:33
Награды: 4
Версия LabVIEW: 2.5 — 2022
Благодарил (а): 11 раз
Поблагодарили: 127 раз
Контактная информация:

Re: Call library function node

Сообщение dadreamer »

:labview: автоматически считывает строку по адресу, который выдала функция?
Да, и автоматически конвертирует во внутренний тип LStr, потому что C String и LabVIEW String - это разные вещи.
А если я хочу далее манипулировать именно с самим указателем? И где найти функции для работы с указателями (pointers), то есть получение указателя, чтение данных из указателя?
Плохо представляю, зачем это нужно, кроме узкоспециализированных манипуляций. Но если все-таки нужно, то делаете возвращаемое значение как Unsigned Pointer-Sized Integer. Считать из указателя / записать по нему можно с помощью функции MoveBlock: https://decibel.ni.com/content/docs/DOC-9091 Работа с памятью в :labview: выполняется с помощью функций менеджера памяти (DSNewPtr и т.д.): http://zone.ni.com/reference/en-XX/help ... functions/ (это есть и во встроенной справке :labview: ). Обычно эти функции используются во внешнем коде, однако можно и вызывать их из самого :labview: .
Это корректный способ? Что тогда делает :labview: , просто создаёт где-то в памяти область нужного размера (4 байт в данном случае), и использует её при этой операции?
Да, хотя я предпочитаю засылать туда 0, так при отключении правого провода, левый терминал остается определенным, а не пустым (void). LabVIEW делает так, как вы написали.
Чем отличаются настройки Run in UI thread / Run in any thread?
UI поток в :labview: один, в нём работают все графические элементы панели (кнопки, контролы, индикаторы и т.д.). Если у вас вызов библиотеки будет в UI потоке и по какой либо причине затянется/зависнет, то это подвесит всю программу, т.к. поток UI будет заблокирован. Это событие на самом деле редкое, т.к. его стараются избежать при разработке DLL, делая её функции реентерантными. Опцию работы в UI потоке в узле CLFN оправдано ставить только тогда, когда не предполагается параллельная работа одних и тех же функций из библиотеки. В противном случае нужно ставить Run in any thread для параллельного вызова, но вы должны точно знать, что разработчик DLL сделал эти функции реентерантными.
Boris_K
developer
developer
Сообщения: 281
Зарегистрирован: 28 янв 2015, 14:25
Версия LabVIEW: 2012 Pro

Re: Call library function node

Сообщение Boris_K »

Опцию работы в UI потоке в узле CLFN оправдано ставить только тогда, когда не предполагается параллельная работа одних и тех же функций из библиотеки.
Параллельная в рамках данного приложения, или учитывая, что эта биб-ка может использоваться другими приложениями? В моём приложении предполагается только последовательный вызов, и из одного потока. Но есть другая программа, которая тоже запущена и юзает эту биб-ку...
Race conditions - опасный и скользкий баг!
Аватара пользователя
dadreamer

Activity Professionalism Автор
professor
professor
Сообщения: 3926
Зарегистрирован: 17 фев 2013, 16:33
Награды: 4
Версия LabVIEW: 2.5 — 2022
Благодарил (а): 11 раз
Поблагодарили: 127 раз
Контактная информация:

Re: Call library function node

Сообщение dadreamer »

В рамках одного процесса, в конкретном случае - вашей программы. Если используется одновременно в другой программе, то это косвенно говорит о том, что функции потокобезопасны. В вашем случае, получается, по барабану, что ставить - UI или Any Thread.
Boris_K
developer
developer
Сообщения: 281
Зарегистрирован: 28 янв 2015, 14:25
Версия LabVIEW: 2012 Pro

Re: Call library function node

Сообщение Boris_K »

Да, хотя я предпочитаю засылать туда 0, так при отключении правого провода, левый терминал остается определенным, а не пустым (void).
А как в данном случае интерпретируется нулевой адрес?
Race conditions - опасный и скользкий баг!
Аватара пользователя
dadreamer

Activity Professionalism Автор
professor
professor
Сообщения: 3926
Зарегистрирован: 17 фев 2013, 16:33
Награды: 4
Версия LabVIEW: 2.5 — 2022
Благодарил (а): 11 раз
Поблагодарили: 127 раз
Контактная информация:

Re: Call library function node

Сообщение dadreamer »

Boris_K, это не NULL, это начальное состояние переменной при передаче её в функцию. В большинстве случаев без разницы, что туда посылать, можно любое число прописать. Так как в CLFN стоит Pass - Pointer To Value, то :labview: всё равно перезапишет эту область памяти значением, полученным при вызове функции. Нюанс есть тогда, когда функция работает сразу с начальным состоянием переменной. Например,

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

void MyFunc(int32 *a, int32 *b, int32 *sum)
{
*sum = *a + *b;
}
В данном случае состояние переменных *a и *b важно, так как они являются слагаемыми. А вот результат суммирования *sum перезаписывается.
danya
junior
junior
Сообщения: 52
Зарегистрирован: 23 мар 2015, 18:29
Версия LabVIEW: 2010
Контактная информация:

Re: Call library function node

Сообщение danya »

Здравствуйте, а у меня возник следующий вопрос при использовании этого vi: в параметрах функции есть тип enum, а также есть структура - как их указать в параметрах labview, какой применить тип?
Аватара пользователя
dadreamer

Activity Professionalism Автор
professor
professor
Сообщения: 3926
Зарегистрирован: 17 фев 2013, 16:33
Награды: 4
Версия LabVIEW: 2.5 — 2022
Благодарил (а): 11 раз
Поблагодарили: 127 раз
Контактная информация:

Re: Call library function node

Сообщение dadreamer »

danya писал(а):Здравствуйте, а у меня возник следующий вопрос при использовании этого vi: в параметрах функции есть тип enum, а также есть структура - как их указать в параметрах labview, какой применить тип?
1. enum зависит от параметров компилятора, как правило это обычный int (I32), если не указано иное. Сопоставлять конкретный enum и число следует по заголовочному (*.h) файлу, где дано определение этого enum'а;
2. структура (struct) может передаваться в функцию в виде кластера; в таком случае нужно выставить в CLFN опцию Adapt To Type - Handles By Value, в результате кластер будет передан по ссылке (т.е., передаётся не сам кластер со всеми "потрохами", а указатель на него). Если структура сильно сложная и не может быть выражена на БД в виде кластера, то можно передавать блок памяти или массив U8. Иногда функция требует инициализации входных параметров, тогда в этот блок данных следует прописать начальные значения. После вызова функции придётся преобразовать блок данных в удобный для LV вид.
Аватара пользователя
Favorit
interested
interested
Сообщения: 4
Зарегистрирован: 09 дек 2016, 19:22
Версия LabVIEW: 8-15
Контактная информация:

Re: Call library function node

Сообщение Favorit »

Приветствую всех, возник вопрос по Call library function node.

Есть библиотека с соглашением о вызове cdecl в заголовочном файле есть функция, принимает параметр типом указателя на функцию:

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

MOTO_DLL_2_API int _cdecl AddParamToStream(int inv,char *name,READ_CALLBACK onPoint);
имя типа данных объявлена так:

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

typedef void (__stdcall *READ_CALLBACK)(int, int, double, void *, int);
Сделал так
структура (struct) может передаваться в функцию в виде кластера; в таком случае нужно выставить в CLFN опцию Adapt To Type - Handles By Value
но при передаче пустого кластера LabView выдаёт ошибку, может кто подскажет....
Аватара пользователя
dadreamer

Activity Professionalism Автор
professor
professor
Сообщения: 3926
Зарегистрирован: 17 фев 2013, 16:33
Награды: 4
Версия LabVIEW: 2.5 — 2022
Благодарил (а): 11 раз
Поблагодарили: 127 раз
Контактная информация:

Re: Call library function node

Сообщение dadreamer »

Favorit, не используйте пока [ code ], на форуме проблемы с его отображением.
[q=="Favorit"]Приветствую всех, возник вопрос по Call library function node.

Есть библиотека с соглашением о вызове cdecl в заголовочном файле есть функция, принимает параметр типом указателя на функцию:
MOTO_DLL_2_API int _cdecl AddParamToStream(int inv,char *name,READ_CALLBACK onPoint);

имя типа данных объявлена так:
typedef void (__stdcall *READ_CALLBACK)(int, int, double, void *, int);

Сделал так
[q=="dadreamer"]структура (struct) может передаваться в функцию в виде кластера; в таком случае нужно выставить в CLFN опцию Adapt To Type - Handles By Value[/q]
но при передаче пустого кластера LabView выдаёт ошибку, может кто подскажет....[/q]

Вам нужно передать указатель на функцию, почему вы решили передать структуру? :shok: Где у вас находится этот колбэк? Он должен быть написан, чтобы передать его адрес. Обычно подобные вещи нужно писать программисту в традиционной среде программирования в виде DLL. Хотя, возможно, разработчик предоставил какие-то стандартные функции для этого?..
Аватара пользователя
Favorit
interested
interested
Сообщения: 4
Зарегистрирован: 09 дек 2016, 19:22
Версия LabVIEW: 8-15
Контактная информация:

Re: Call library function node

Сообщение Favorit »

[quote=="dadreamer"]
Вам нужно передать указатель на функцию, почему вы решили передать структуру? :shok: Где у вас находится этот колбэк? Он должен быть написан, чтобы передать его адрес. Обычно подобные вещи нужно писать программисту в традиционной среде программирования в виде DLL. Хотя, возможно, разработчик предоставил какие-то стандартные функции для этого?..[/quote]

dll библиотека иметься, для этой библиотеки имеется *.h с описанием функций, библиотеку импортировал с помощью инструмента Import->Shared Library (dll)...
Почти все функции импортировались нормально кроме одной AddParamToStream, в качестве праметра предаётся переманная onPoint типом READ_CALLBACK тип является указателем на функцию.
Shared Library (dll)... автоматически принял настройки Adapt To Type - Handles By Value по праметру onPoint, Call library function node принимает на этот вход пустой кластер, и выдаёт ошибку на эту связь

это фрагмент *.h
typedef void (__stdcall *READ_CALLBACK)(int, int, double, void *, int);

MOTO_DLL_2_API int _cdecl AddParamToStream(int inv,char *name,READ_CALLBACK onPoint);
Аватара пользователя
dadreamer

Activity Professionalism Автор
professor
professor
Сообщения: 3926
Зарегистрирован: 17 фев 2013, 16:33
Награды: 4
Версия LabVIEW: 2.5 — 2022
Благодарил (а): 11 раз
Поблагодарили: 127 раз
Контактная информация:

Re: Call library function node

Сообщение dadreamer »

Import Shared Library Wizard не достаточно интеллектуален, чтобы различать некоторые сложные типы данных, кроме того он не поддерживает многие фичи C++, например указатель на this и классы. Если не планируете пользоваться этой функцией, то попробуйте исключить её из импорта - снимите галку на её имени. Если же очень сильно нужна эта функция, то вам придётся подкорректировать настройки CLFN вручную. Этот последний параметр должен быть в виде Numeric -> Unsigned Pointer-Sized Integer. А чтобы вызвать AddParamToStream, нужно иметь кастомную (самописную) функцию-колбэк в некоторой DLL. Далее парой функций LoadLibrary/GetModuleHandle + GetProcAddress получаете адрес вашего колбэка и передаёте в AddParamToStream. Естественно, внутри callback должна находиться какая-то простенькая логика, например, передача значений в :labview: через PostLVUserEvent.
Аватара пользователя
Favorit
interested
interested
Сообщения: 4
Зарегистрирован: 09 дек 2016, 19:22
Версия LabVIEW: 8-15
Контактная информация:

Re: Call library function node

Сообщение Favorit »

[quote=="dadreamer"]Подкорректировать настройки CLFN вручную. Этот последний параметр должен быть в виде Numeric -> Unsigned Pointer-Sized Integer. А чтобы вызвать AddParamToStream, нужно иметь кастомную (самописную) функцию-колбэк в некоторой DLL. Далее парой функций LoadLibrary/GetModuleHandle + GetProcAddress получаете адрес вашего колбэка и передаёте в AddParamToStream. Естественно, внутри callback должна находиться какая-то простенькая логика, например, передача значений в :labview: через PostLVUserEvent.[/quote]

Пока ещё не сталкивался LoadLibrary/GetModuleHandle + GetProcAddress

Решил проблему передаче кластера типа Variant... Если понадобиться функция попробую ваш вариант, спасибо !
Ответить
  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Для чайников»