Форум » xBase языки » Адаптация кода C++ в КаВо » Ответить

Адаптация кода C++ в КаВо

loop007 : Добрый день! Найдётся ли специалист, который сможет мне помочь адаптировать код C++ в CA-Visual Objects? Общие представления у меня есть, но некоторые вещи у меня не получаются. Заранее благодарен.

Ответов - 25, стр: 1 2 All

Сыроежка: Тут возникает несколько вопросов. Является ли интерфейс подключения объектных модулей на С/С++ в CAVO таким же, как в Clipper? Или же в CAVO свои интерфейсные функции для передачи аргументов и возвращаемых значений? Насколько мне известно семейство типов данных в CAVO было существенно расширено по сравнению с Clipper, а значит должны быть новые интерфейсные функции. Нужно ли включать код на С++ или же на С? Дело в том, что в С++ создаются длинные имена функций, зависящие от компилятора. Я не имел дело с CAVO, поэтому ничего не могу сказать. В Google имеются форумы по CAVO. Например, [url=https://groups.google.com/forum/?hl=ru&fromgroups#!forum/comp.lang.clipper.visual-objects]здесь[/url]

Сыроежка: Там же, в Google есть и второй подобный [url=https://groups.google.com/forum/?fromgroups#!forum/comp.lang.clipper]форум[/url]

loop007: Добрый вечер! Спасибо за наводки на форумы. Скажу сразу: интерфейсные функции не нужны. Это не нужно. Суть такова: есть DLL, а в КаВо есть возможность использовать DLL-ки, сделанные в среде С/С++ Пример: есть Win32 API-функция CopyFileA, а я её хочу использовать, но под именем CopyFile. Чтобы её использовать, мне достаточно написать следующее: _DLL FUNC CopyFile(lpExistingFileName AS PSZ, lpNewFileName AS PSZ, bFailIfExists AS LOGIC); AS LOGIC PASCAL:KERNEL32.CopyFileA#48 После этого, я её спокойно использую. Как бы суть понятна... У меня есть DLL-ка RFIDAPI32PC.dll и пример работы с ней, написанный на C++. В этом примере применяются функции из этой .dll-ки. Никакого вывод на экран (вывод я сделаю потом, как будет надо). И всё хорошо, но у меня есть некоторое недопонимание и ошибки... В частности, например, там (насколько я понял) используется Unicode, а в КаВо стандартно он не используется... Поэтому и хотелось бы разобрать код с человеком, который имеет опыт перевода (адаптации) кода из Си в КаВо. На этом форуме я увидел несколько человек, которые ранее работали с КаВо. Возможно они имеют некоторый опыт. Поэтому и написал это сообщение сюда.


Sergey Spirin: Приведи здесь примеры вызовов этих функций из RFIDAPI32PC.dll с одной стороны. И с другой стороны опиши возможные в Каво типы данных и т.д. которые можно употреблять в _DLL FUNC и вообще синтаксис приведи. В принципе, ситуация в любом случае не патовая, даже если средствами Каво нужные типы невыразимы. В таких случаях пишется прокладочная dll на том же С или Delphi, которая принимает типы "удодные" и переводит их в нужные.

Avseev: lopp007 Посмотрите ftp.cavo.com удаленный каталог /pubcavo/resources пароль anonymous для доступа использую TOTALCOM там есть примеры работы c Unicode

loop007 : 2 Avseev: каталог такой знаю, может носом тыкнёте в примеры? Буду премного благодарен. 2 Sergey Spirin: я об этом вчера уже думал. К сожалению, я не пишу на C++ и знакомого, чтобы помог проверить тоже нет... Кроме того, обнаружились ошибки в описании функций - чуток продвинулся дальше... Сможете мне помочь проверить пару функций? У меня есть пример (должен быть рабочим), исходники. Мне нужно узнать, что видно у вас (в С++) и сравнить с тем, что видно у меня (в КаВо). Может, там есть ещё одна ошибка и проблема не в unicode... Ну, а если в unicode, то тогда бы я попросил момочь мне сделать прокладку по двум функциям. Этот же вопрос я адресую и Сыроежке.

Сыроежка: loop007 пишет: У меня есть пример (должен быть рабочим), исходники. Мне нужно узнать, что видно у вас (в С++) и сравнить с тем, что видно у меня (в КаВо). Может, там есть ещё одна ошибка и проблема не в unicode... Ну, а если в unicode, то тогда бы я попросил момочь мне сделать прокладку по двум функциям. Вы можете самостоятельно проверить эти функции, установив у себя на машине любой компилятор С/С++. Сейчас много есть свободно распространяемых компиляторов. Например, можно установить Microsoft Visual C++ 2010 Express Edition, либо любой другой. В любом случае полезно иметь под рукой С/С++ компилятор, так как Clipper-производные пакеты всегда предполагают интерфейс с С. Если у вас будут возникать ошибки компиляции, то вы можете вынести их сюда, на форум, на обсуждение. Либо если вам не понятен какой-то фрагмент кода, вы также можете его вынести на обсуждение на форуме.

Sergey Spirin : loop007 пишет: то тогда бы я попросил момочь мне сделать прокладку по двум функциям. Индивидуально вряд ли кто помогать будет. А коллективно, может и подскажем/наведем. Поэтому выкладывай здесь описание функции в dll, пример ее вызова в С++, и как пытаешься вызвать в каво, с комментариями об специфичных типах каво. Посмотрим...

loop007 : Давайте попробуем... [pre2]Function Prototype const TCHAR * WINAPI RFID_GetCommandStatusText(int stat); Parameters stat Status code returned by an RFID API function call. Return Values Returns a human readable string representing the RFID API’s integer error code. [/pre2] Вот, что на самом деле (взял из рабочего примера на Visual Studio 2005: => RFID_GetCommandStatusText(hReader, dwStatus) (Т.е., я уже узнал, что там не один, а два параметра :)) Перенёс в КаВо вот так: [pre2] _DLL FUNC RFID_GetCommandStatusText( hReader AS PTR, dwStatus AS DWORD ) ; AS PSZ PASCAL:RFIDAPI32PC.RFID_GetCommandStatusText#148 [/pre2] Но возвращает она мне только первую букву сообщения… То ли это функция глючная, то ли я глючу :)) Идём дальше: [pre2]bool ConfigureTCPIP(HANDLE hReader, TCHAR *ptszIPAddress, WORD wPort) { bool bSuccess = FALSE; DWORD dwItems = 1; DWORD dwStatus = RFID_SUCCESS; dwStatus = RFID_SetCapCurrValue(hReader, RFID_DEVCAP_IP_PORT, &dwItems, sizeof(wPort), &wPort); IF(dwStatus == RFID_SUCCESS) { dwItems = (DWORD)wcslen(ptszIPAddress) + 1;// + 1 for null dwStatus = RFID_SetCapCurrValue(hReader, RFID_DEVCAP_IP_NAME, &dwItems,; dwItems * sizeof(ptszIPAddress[0]), ptszIPAddress); Function Prototype RFID_SetCapCurrValue(HANDLE hReader, DWORD dwCapId, DWORD *pdwNumItems, DWORD dwValueBufSize, LPVOID pvValueBuf); Parameters hReader Handle to open RFIDAPI. dwCapId Id of capability being referenced. pdwNumItems Number of items that can fit into pvValueBuf. dwValueBufSize Size of pvValueBuf in BYTES. pvValueBuf Buffer that receives default value. Return Values If the function succeeds, the return value is RFID_SUCCESS. If the function fails, an "RFID_XXXX" error code is returned. Comments The API assumes that pvValueBuf points to 1 or more items. Each item can be a BYTE, WORD, or DWORD (8, 16, or 32bit value). The API calculates an item's size as follows: ItemSize = *pdwNumItems / dwValueBufSize; The API correctly converts a smaller item into a larger item, but not vice-versa. That is, if the caller supplies an array of DWORDs to the API, and the Capability is an array of bytes, each byte is properly placed into the supplied DWORD array as DWORDs. The API cannot put a DWORD into a WORD or BYTE since these items are not large enough to hold DWORDs. [/pre2] Понятно, что в КаВо эта функция будет выглядеть типа так: [pre2] _DLL FUNC RFID_SetCapCurrValue( hReader AS PTR, dwCapId AS DWORD, pdwNumItems AS DWORD PTR, dwValueBufSize AS DWORD, pvValueBuf AS PSZ) AS DWORD PASCAL:RFIDAPI32PC.RFID_SetCapCurrValue [/pre2] И как будет выглядеть следующий код в КаВо? [pre2]bool ConfigureTCPIP(HANDLE hReader, TCHAR *ptszIPAddress, WORD wPort) { bool bSuccess = FALSE; DWORD dwItems = 1; DWORD dwStatus = RFID_SUCCESS; dwStatus = RFID_SetCapCurrValue(hReader, RFID_DEVCAP_IP_PORT, &dwItems, sizeof(wPort), &wPort); IF(dwStatus == RFID_SUCCESS) { dwItems = (DWORD)wcslen(ptszIPAddress) + 1;// + 1 for null dwStatus = RFID_SetCapCurrValue(hReader, RFID_DEVCAP_IP_NAME, &dwItems,; dwItems * sizeof(ptszIPAddress[0]), ptszIPAddress); FUNCTION ConfigureTCPIP( hReader AS PTR, ptszIPAddress AS PSZ, wPort AS WORD ) AS LOGIC PASCAL LOCAL bSuccess := FALSE AS LOGIC LOCAL dwItems := 1 AS DWORD LOCAL dwStatus := RFID_SUCCESS AS DWORD dwStatus := RFID_SetCapCurrValue( hReader, RFID_DEVCAP_IP_PORT, @dwItems, sizeof(wPort), @wPort); IF(dwStatus == RFID_SUCCESS) // dwItems = (DWORD)wcslen(ptszIPAddress) + 1;// + 1 for null // dwStatus = RFID_SetCapCurrValue(hReader, RFID_DEVCAP_IP_NAME, &dwItems,; // dwItems * sizeof(ptszIPAddress[0]), ptszIPAddress); [/pre2] Как переделать последние три строки – я не знаю… Для справки: соответствие цифровых типов Си и КаВо почти полное (нет LONG LONG и ещё некоторых) Указателей в КаВо два: PSZ и PTR PSZ - это указатель на строку с нулём в конце (строка с обязательным 0x00 в конце) а PTR - просто указатель на область памяти

PSP : loop007 , не в тему, по оформлению: текст кода можно выделить и отметить как "Моноширинный шрифт" (кнопочка с цифрами "123"). Тогда намного лучше читается, можно отступы сделать.

loop007 : Т.е., проблема с пониманием (DWORD)wcslen(ptszIPAddress) и sizeof(ptszIPAddress[0]) ptszIPAddress - это строка в UNICODE (IP-адрес) но в ANSI (у меня только ANSI) 256.256.256.256 - длина 15 (+1) sizeof в КаВо будет или _SizeOf или просто SizeOf ptszIPAddress[0] - откуда [0]? Это связано с Unicode? Как это написать для ANSI?

loop007 : Спасибо, текст сделал моноширинным. Что-то ещё поправить? Объём не великоват?

Sergey Spirin : loop007 пишет: Function Prototype const TCHAR * WINAPI RFID_GetCommandStatusText(int stat); Parameters stat Status code returned by an RFID API function call. Return Values Returns a human readable string representing the RFID API’s integer error code. Вот, что на самом деле (взял из рабочего примера на Visual Studio 2005: => RFID_GetCommandStatusText(hReader, dwStatus) (Т.е., я уже узнал, что там не один, а два параметра :)) Перенёс в КаВо вот так: _DLL FUNC RFID_GetCommandStatusText( hReader AS PTR, dwStatus AS DWORD ) ; AS PSZ PASCAL:RFIDAPI32PC.RFID_GetCommandStatusText#148 Но возвращает она мне только первую букву сообщения… То ли это функция глючная, то ли я глючу :)) TCHAR может быть UTF-16, что скорее всего и функция возвращает. Попробуй конвертировать возврат WinAPi-функцией, например WideCharToMultiByte().

loop007: А что про (DWORD)wcslen(ptszIPAddress) и sizeof(ptszIPAddress[0]) скажете? что, почему и для чего делается? С WideCharToMultiByte пока не получается, т.к. длина возвращаемого значения - 1 Что-то где-то не там читаю...

Sergey Spirin: Длину попробуй определить с помощью lstrlenW(), она в kernel32. Остальное может вечером гляну, сейчас не могу.

Sergey Spirin: loop007 пишет: А что про (DWORD)wcslen(ptszIPAddress) и sizeof(ptszIPAddress[0]) скажете? Что именно здесь непонятно? (DWORD)wcslen(ptszIPAddress) - приведет к типу DWORD длину юникодной строки ptszIPAddress. sizeof(ptszIPAddress[0]) будет 2, если ptszIPAddress юникодная строка.

loop007 : Sergey Spirin пишет: (DWORD)wcslen(ptszIPAddress) - приведет к типу DWORD длину юникодной строки ptszIPAddress. sizeof(ptszIPAddress[0]) будет 2, если ptszIPAddress юникодная строка. Именно это я и хотел услышать. А при ANSI sizeof(ptszIPAddress[0]) будет 1 Спасибо. Sergey Spirin пишет: Длину попробуй определить с помощью lstrlenW(), она в kernel32. Буковка W в конце названия функции обозначает, что это Unicode-функция, а значит, для КаВо это не подходит ... Всё равно, спасибо! Данную ситуация я как-то обойду. Последний вопрос по синтаксису: вот идёт получение handle hReader = OpenReader(TEXT("157.235.88.44"), 3000); а вот сама функция: /// Opens and establishs connection to a reader /// @param[in] tszNewIPAddressThe IP address of the reader /// @param[in] wPortThe TCP port of the reader HANDLE OpenReader(TCHAR tszNewIPAddress[32], WORD wPort) { Что значит TCHAR tszNewIPAddress[32], почему нельзя написать просто TCHAR tszNewIPAddress ? Что означают цифры 32? Я так подозреваю, что это длина в Unicode, а в ANSI это, наверное, будет 16... А без указания длины можно? Простите за дилетанские вопросы. Большая вам благодарность за долготерпение!

Sergey Spirin : loop007 пишет: Буковка W в конце названия функции обозначает, что это Unicode-функция, а значит, для КаВо это не подходит ... Что значит "не подходит"? У нее один параметр указатель, который у тебя есть. Вернет число. От того, что каво не содержит юникодные типы данных, это не означает, что ты не можешь вызвать функцию. loop007 пишет: Что значит TCHAR tszNewIPAddress[32], почему нельзя написать просто TCHAR tszNewIPAddress ? Здесь параметр определен как массив символов, а не как указатель на символ. Символов одинаково будет и в Ansi и в Unicode, а вот байтов такие массивы займут разное количество. P.S. Вообще, использование TCHAR и таких конструкций как TEXT(""), наводит на мысль, что должна быть ANSI-версия этой библиотеки. Ты уверен, что скачал нужное? Тип TCHAR обычно используется в случаях когда один код нужно компилировать в двух вариантах - Ansi и Unocode.

loop007 : По первому ответу - принято. Уазатель он и есть указатель. Погорячился. Sergey Spirin пишет: Здесь параметр определен как массив символов, а не как указатель на символ. Символов одинаково будет и в Ansi и в Unicode, а вот байтов такие массивы займут разное количество. P.S. Вообще, использование TCHAR и таких конструкций как TEXT(""), наводит на мысль, что должна быть ANSI-версия этой библиотеки. Ты уверен, что скачал нужное? Тип TCHAR обычно используется в случаях когда один код нужно компилировать в двух вариантах - Ansi и Unocode. Вероятно, такая библиотека (ANSI) была ранее, но сейчас ничего не нашёл... Кроме того, старые библиотеки не поддерживают новые устройства (Motorola)... По поводу твоего объяснения что это не указатель, а массив... несколько в затруднении. Выходит, что TEXT() вернёт строку, которую передаём в функцию, но там её принимаем, как массив символов этой строки... Я правильно понял? Просто смотрю текст (примера): (Main) hReader = OpenReader(TEXT("157.235.88.44"), 3000); // Это строка но, в функции - это массив HANDLE OpenReader(TCHAR tszNewIPAddress[32], WORD wPort) при этом, в функции OpenReader тут же передаётся (без изменений) в функцию ConfigureTCPIP: IF(ConfigureTCPIP(hReader, tszNewIPAddress, wPort)) где, это вроде как указатель на строку: bool ConfigureTCPIP(HANDLE hReader, TCHAR *ptszIPAddress, WORD wPort) Это особенности синтаксиса Си, или я чего-то не понимаю?

Sergey Spirin : loop007 пишет: Это особенности синтаксиса Си, или я чего-то не понимаю? Да я бы не сказал, что только Си, в Дельфи где-то также. Строка это и есть массив символов А указатель на строку это указатель на первый элемент массива - указатель на символ. В терминах Клиппера - "по ссылке и по значению".

Сыроежка: loop007 пишет: HANDLE OpenReader(TCHAR tszNewIPAddress[32], WORD wPort) { Что значит TCHAR tszNewIPAddress[32], почему нельзя написать просто TCHAR tszNewIPAddress ? Что означают цифры 32? Я так подозреваю, что это длина в Unicode, а в ANSI это, наверное, будет 16... А без указания длины можно? TCHAR tszNewIPAddress[32] - это объявление массива в качестве параметра функции из элементов TCHAR длиной 32 элемента. В С/С++ при передаче имени массива в качестве аргумента он преобразуется в указатель на свой первый элемент. Поэтому данное объявление функции эквивалентно следующему: HANDLE OpenReader(TCHAR *tszNewIPAddress, WORD wPort); Почему был выбран первый вид объявления параметра функции в виде массива, а не указателя? Это было сделано для самодокументирования функции, чтобы пользователь знал, какой тип массива, то есть сколько элементов у этого массива должно быть, когда его имя передается в функцию в качестве аргумента. То есть для читающего это объявление функции предоставляется дополнительная информация о том, какой размер должен иметь массив, передаваемый в функцию. Сам размер массива в байтах определяется как 32 * sizeof( TCHAR ). Если вы имете дело с ASCII кодировкой, то TCHAR будет занимать один байт, если с UNICODE, то два байта.

Сыроежка: loop007 пишет: Просто смотрю текст (примера): (Main) hReader = OpenReader(TEXT("157.235.88.44"), 3000); // Это строка но, в функции - это массив HANDLE OpenReader(TCHAR tszNewIPAddress[32], WORD wPort) при этом, в функции OpenReader тут же передаётся (без изменений) в функцию ConfigureTCPIP: IF(ConfigureTCPIP(hReader, tszNewIPAddress, wPort)) где, это вроде как указатель на строку: bool ConfigureTCPIP(HANDLE hReader, TCHAR *ptszIPAddress, WORD wPort) Это особенности синтаксиса Си, или я чего-то не понимаю? TEXT("157.235.88.44") - это строковый литерал. В С/С++ они хранятся в памяти как массивы символов, содержащих завершающий нулевой символ. Как я уже написал выше, при передаче имени массива в качестве аргумента, он преобразуется в указатель на свой первый элемент. Поэтому объявления параметров, которые вызывают у вас вопросы, эквивалентны. То есть объявление параметра в виде TCHAR tszNewIPAddress[32] эквивалентно объявлению его в виде TCHAR *ptszIPAddress. Просто первое объявление более информативно, так как подсказывает пользователю функции, что передаваемый массив по крайней мере должен быть не меньше указанной размерности.

loop007: Всем большое спасибо!!! Извините, что долго не отвечал - писал программку и тестировал. Sergey Spirin навёл меня на правильную мысль фразой "по ссылке и по значению" И я начал писать программу... Как я и догадывался, RFID_GetCommandStatusText возвращала Unicode и я воспользовался наводкой на WideCharToMultiByte() (Только в лоб её использовать не получилось, пришлось подстелить :)) А когда вернулся, оказалось, что Сыроежка - просто разжевал для идиотов. Ребята, большое Вам спасибо !!!! Поставил Вам плюсы :)) Удачи всем!!!

Сыроежка: loop007 пишет: Просто смотрю текст (примера): (Main) hReader = OpenReader(TEXT("157.235.88.44"), 3000); // Это строка но, в функции - это массив HANDLE OpenReader(TCHAR tszNewIPAddress[32], WORD wPort) при этом, в функции OpenReader тут же передаётся (без изменений) в функцию ConfigureTCPIP: IF(ConfigureTCPIP(hReader, tszNewIPAddress, wPort)) где, это вроде как указатель на строку: bool ConfigureTCPIP(HANDLE hReader, TCHAR *ptszIPAddress, WORD wPort) Это особенности синтаксиса Си, или я чего-то не понимаю? Я сразу же не обратил внимание, но использование функции OpenReader из примера не согласуется с ее объявлением. Что я имею в виду? В вашем примере функция используется как hReader = OpenReader(TEXT("157.235.88.44"), 3000); То есть в качестве первого параметра передается строковый литерал. Согласно стандарту языков С/С++ строковые литералы изменять нельзя. Поэтому их нельзя передавать в качестве аргумента тем функциям, которые принимают неконстантный указатель или массив. Функция OpenReader объявлена таким образом, что ее первый параметр не является константным HANDLE OpenReader(TCHAR tszNewIPAddress[32], WORD wPort); Это означает, что функция вправе изменить значения массива, которые передаются по указателю (как уже упоминалось ранее, при передаче массива в качестве аргумента, он преобразуется в указатель на его первый элемент). А это может привести к аварийному завершению программы. То есть можно было бы передавать строковый литерал, если бы объявление функции имело вид: HANDLE OpenReader(const TCHAR tszNewIPAddress[32], WORD wPort); то есть если бы первый параметр имел квалификатор const. Это было бы соглашением между функцией и ее пользователем, что значения массива менятся не будут. Но такого квалификатора нет у исходного объявления функции, а потому напрямую передавать ей строковый литерал в качестве значения первого параметра будет некорректным. Нужно будет в коде пользователя сначала объявить массив, инициализировав его строковым литералом, а уж затем этот массив передавать данной функции в качестве аргумента. Так будет корректнее.

loop007: Сыроежка пишет: HANDLE OpenReader(const TCHAR tszNewIPAddress[32], WORD wPort); то есть если бы первый параметр имел квалификатор const. Это было бы соглашением между функцией и ее пользователем, что значения массива менятся не будут. Но такого квалификатора нет у исходного объявления функции, а потому напрямую передавать ей строковый литерал в качестве значения первого параметра будет некорректным. Нужно будет в коде пользователя сначала объявить массив, инициализировав его строковым литералом, а уж затем этот массив передавать данной функции в качестве аргумента. Так будет корректнее. Именно так я и сделал. И код у меня не проходил именно по той причине, что Вы указали. И хотя я это сделал ещё вчера - Ваше сегодняшнее дополнение очень важно для тех, кто захочет ознакомиться с этой темой! Большое Вам спасибо! Думаю, когда всё получиться, сделать маленькую запись об этом в своём блоге. К сожалению, Сыроежка, в Вашем профиле нет Ваших ФИО, поэтому дам ссылку только на НИК. У меня в профиле тоже нет данных - не даёт изменить... Видимо глюк движка. P.S.: Глюк разрешился: движок не совсем корректно работает с IE8 Сейчас зашёл под Mozilla Firefox - и сразу удалось скорректировать данные в профиле. В общем, если что - мои данные в профиле.



полная версия страницы