Использование функций внешней DLL

Разработка программ на пес его знает на чем
Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
Ответить
Гость

Сообщение Гость »

Здрствуйте!
Есть внешяя библиоткека с набором различных функций написанная на Delphi.
Подключить билиотеку к проекту получилось. Получается так же вызывать простые функции. Но есть функции, которые использовать не получается. Привожу описание функций из документации на библиотеку:

1)function cbAddTitleLine(Line: PChar): Integer;
Принимаемые параметры:
Line - указатель на нуль-терминированную строку, содержащую строку заголовка.
Возвращаемые значения:
1 - в случае успешного завершения;
0 - в случае возникновения ошибки.

2)function cbGetTitleLine(Index: Integer; var Line: PChar): Integer;
Принимаемые параметры:
Index - номер строки заголовка, которую необходимо получить;
Line - переменная, через которую возвращается указатель на нуль-терминированную строку, содержащую
текст запрошенной строки заголовка.
Возвращаемые значения:
1 - в случае успешного завершения;
0 - в случае возникновения ошибки.

Первая ф-ция добавляет строку в массив библиотеки, а 2-я считывает.

3) function cbAddSale(Name: PChar; Price, Qty: Double; Section: Integer): Integer;

4) function cbGetSale(Index: Integer; var Name: PChar; var Price, Qty: Double; var Section: Integer): Integer;

Аналогично для 3-й и 4-й. Одна добавляет,а другая считывает.
Как правильно описать прототипы этих функций и осуществлять их вызов?

Спасибо!
С увжением, Анатолий

(Добавление)

По идее так, хотя могу и ошибаться (не использовал никогда стыковку Clarion + Delphi):

1) cbAddTitleLine(*Cstring Line), Long, Raw
2) cbGetTitleLine(Long Index, *Cstring Line), Long, Raw
3) cbAddSale(*Cstring Name, Real Price, Real Qty, Long Section), Long, Raw
4) cbGetSale(Long Index, *Cstring Name, *Real Price, *Real Qty, *Long Section), Long, Raw

Best regards,
Andrew Listiev
Work mailto:andrewl@inbox.lv
Home mailto:gidravlic@mhm.lv
ICQ UID: 169357390
MS Messenger: werdna_werdna@hotmail.com

Спасибо!
У меня сработал вариант:
cbAddTitleLine(*Cstring Line), Long,Pascal,Raw
cbGetTitleLine(Long Index, *Cstring Line), Long, Pascal,Raw

Вернее обе функции возвращают код успеха. А вот как правильно объявить переменую из которой считывается и в которую заносится строка.
У меня проходит только CSTRING(18). Все другое приводит к аварийному закрытию приложения. Как вообще правильно сделать вызов функций?

Извиняюсь!
Забыл упомянуть, что хоть вариант CSTRIN(18) сраьатывает, но переменная при использовании второй функции остается пустой. Пожоже ничего на записывается и ничего не считывается!

"Анатолий" <gik7@list.ru>

А почему именно размер 18? может нжуно больший буфер дать? да и посмотреть что там возвращается побайтово в строке...

--
Best regards,
Vadym mailto:vadim@softcreator.com
ICQ: 82308757

В описании библиотеки есть пример использовании ф-ции на Delphi. С Delphi я не знаком, но по коду вроде видно, что объявлется переменная и стоит размер 18. Как только я установил CSTRING(18), так работать все стало, только информация пожоже не записывается и не считывается. Все другие варианты объявления переменной, вырубают приложение напрочь при вызове ф-ций.

Кстати, в библиотеки есть такая ф-ция:

function GetErrorMsg: PChar;
Принимаемые параметры:
PChar -Указатель на нуль-терминированную строку, содержащую сообщение об ошибке.
Возвращаемые значения:
1 - в случае успешного завершения;
0 - в случае возникновения ошибки.

Для нее я сделал прототип GetErrorMsg (),CSTRING,PASCAL,RAW и все работает. Проблема только с выше приведенными ф-циями.

"Анатолий" <gik7@list.ru>

(Добавление)

Как только я установил CSTRING(18), так работать все стало, только информация пожоже не записывается и не считывается.

А почему "похоже"? Еще раз - в этом буфере после вызова есть что-то или нет?

Все другие варианты объявления переменной, вырубают приложение
напрочь при вызове ф-ций.

А какие еще были варианты декларации?
Может стоит дать CSTRING(19)?
Или как минимум привести пример гарантированно корректного использования на делфях. Иначе все это похоже на гадание на кофейной гуще

--
Best regards,
Vadym

cbGetTitleLine

Описание:

function cbGetTitleLine(Index: Integer; var Line: PChar): Integer;
Принимаемые параметры:
Index - номер строки заголовка, которую необходимо получить;
Line - переменная, через которую возвращается указатель на нуль-терминированную строку, содержащую текст запрошенной строки заголовка.

Возвращаемые значения:
1 - в случае успешного завершения;
0 - в случае возникновения ошибки.

Функция позволяет получить текст строки заголовка чека, добавленной ранее во внутренний массив загруженного экземпляра библиотеки при помощи функции cbAddTitleLine.

Пример

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

procedure TDemoForm.ReadTitleButtonClick(Sender: TObject); //Читаем весь заголовок

var
  i, Count: Integer;
  ResultStr: String;
  TempLine: PChar;
  S: String[18];

begin
  Count:=cbGetTitleLinesCount; //Получаем число строк заголовка
  ResultStr:='';
  TempLine:=@S;
  for i:=1 to Count do
    begin
      if cbGetTitleLine(i, TempLine)<>1 then  //Читаем строку
        begin
          ShowMessage(GetErrorMsg);
          Exit;
        end;
      ResultStr:=ResultStr+String(TempLine)+#13+#10;
    end;
  ShowMessage(ResultStr);
end;
Если делаю CSTRING(19), то приложение вылетает.

Могу выслать проект с библиотекой и описанием самой библиотеки. Если кто знает как заставить это работать, буду очень признателен!

"Анатолий" <gik7@list.ru>

(Добавление)

Вот оно ключевое слово: "возвращается указатель" ! Т.е. переменную декларируешь не ты. Тебе говорят где лежит результат. Попробуй так:

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

pLine   &CString
pLocLineCopy    &CString

  If cbGetTitleLine(Index, pLine)
    LineCopyLen# = Len(pLine) + 1
    pLocLineCopy = New(CString(LineCopyLen#))
    Message(pLocLineCopy)
  else
    Message('O-o-ps ;-(')
  end
И не забыть
DISPOSE(pLocLineCopy)

Nick Tsigouro <nick@arsis.ru>

Хм, и что же мы, Николай, должны увидеть в Message(pLocLineCopy) ? ;)

Если функция возвращает указатель на некую созданную в самой DLL
0-терминированную строку, то надо, получив этот указатель:
1. определить длину строки (функция StrLen)
2. создать нужный CSTRING буфер для копии
3. скопировать строку в этот буфер (функция StrCpy)
4. Обработать полученную копию и освободить буфер.

И все это потому, что в Clarion-е нет указателей.

При этом, кстати, прототипы лучше такие использовать:

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

 MAP
    cbGetTitleLine (SIGNED nIndex, ULONG pcLine),SIGNED,PASCAL

    MODULE('Clarion RTL')
      StrCpy (ULONG pcDestStr, ULONG
pcSourceStr),CSTRING,PROC,RAW,NAME('_strcpy')
      StrLen (ULONG pcStr),UNSIGNED,PROC,NAME('_strlen')
    END
 END
Можно попробовать другой вариант, по идее должно сработать. Эмулировать
указатель в Clarion-e.

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

nIndex                  SIGNED
ResLineGrp          GROUP
cLine                      &CSTRING
                           END
ResLinePointer     ULONG,OVER(ResLineGrp)
 CODE
 ...
 IF cbGetTitleLine(nIndex, ResLinePointer)
     ! Здесь работаем с полученным указателем, как с ResLineGrp.cLine
 END
Удачи!
__________________________________
Владимир Якимченко (ICQ: 16993194)

Если делаю CSTRING(19), то приложение вылетает.
Перед вызовом сделай
TmpLine = ALL('<0>',SIZE(TmpLine))

С уважением, Андрей Истомин

(Добавление)

Привет, Всем!

Пардон, с прототипами ошибся. Так правильнее (если вообще правильно :)) :

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

 MAP
   MODULE('MyDelphi.dll')
     cbGetTitleLine (SIGNED nIndex, *ULONG pcLine),SIGNED,PASCAL
   END

   MODULE('Clarion RTL')
     StrCpy (ULONG pcDestStr, ULONG
pcSourceStr),CSTRING,PROC,RAW,NAME('_strcpy')
     StrLen (ULONG pcStr),UNSIGNED,PROC,NAME('_strlen')
   END
 END
Удачи!
__________________________________
Владимир Якимченко (ICQ: 16993194)
Написал: ClaList(2)
Гость

Сообщение Гость »

1. определить длину строки (функция StrLen)
А почему не катит кларионовская LEN() ?
3. скопировать строку в этот буфер (функция StrCpy)
Каюсь, забыл:
pLocLineCopy = pLine

BTW, StrCpy не самый удобный способ. Имхо лучше WINAPI-шная lStrCpyN:

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

LPTSTR lstrcpyn(
    LPTSTR lpString1,   // address of target buffer
    LPCTSTR lpString2,  // address of source string
    int iMaxLength      // number of bytes or characters to copy
   );
Message(pLocLineCopy)
И про DISPOSE я написал.
И все это потому, что в Clarion-е нет указателей.
Не уловил, в чем проблема?
При этом, кстати, прототипы лучше такие использовать:

MAP
cbGetTitleLine (SIGNED nIndex, ULONG pcLine),SIGNED,PASCAL
Тогда нужно
pLine &CString
оборачивать в группу и оверрайтить лонгом. Бывают случаи когда иначе нельзя (возвращают адрес структуры или интерфейса), но с простыми строками это имхо избыточно.
Можно попробовать другой вариант, по идее должно сработать. Эмулировать указатель в Clarion-e.
Так тоже можно, но это немного другое. Ты работаешь с чужим буфером, а не со своей копией. Я хотел показать, как на кларионе сделать тот пример, что в доке к б-ке. Только там фиксированная локальная строка STRING(18), что не здорово.

WBR, Nick Tsigouro

(Добавление)
А почему не катит кларионовская LEN() ?
В хелпе о CString прочитай.

--
Best regards,
Maxim Yemelyanov,
Enigma Soft Company
phone: +380 572 177977
WEB: http://enigmasoft.com.ua
e-mail: clalist@enigmasoft.com.ua
ICQ: 12253836
Каюсь, забыл:
pLocLineCopy = pLine
Проблема не только в этом. Я сильно сомневаюсь, что таким образом мы получим полноценную pLine, если в доке сказано, что возвращается указатель на некую 0-term строку, инициированную самой DLL.

Именно, поэтому я и говорил, что в Clarion не хватает указателей (а это как раз случай, когда нужен указатель), эмулировать их функции впрочем можно, но через разные трюки с группами.

Удачи!
__________________________________
Владимир Якимченко (ICQ: 16993194)
Написал: ClaList(2)
Гость

Сообщение Гость »

Не получим, но _в_данном_случае_ (скопировать строку), вроде-бы, "не очень-то и хотелось", а копия будет совершенно полноценной.

WBR, Nick Tsigouro

Ну, во-первых и скопировать строку "не очень-то и хотелось", продемонстрированный пример на Delphi показывает нам работу именно с указателем, без промежуточных буферов. А, во-вторых, Николай, чой-то не узнаю тебя, а где же твои железобетонные принципы? Если получаем неполноценный &CSTRING, то нефиг его использовать вообще, ни на чтение, ни на запись, а то изменится что-нить в следующей версии ... и ... :)

Удачи!
__________________________________
Владимир Якимченко (ICQ: 16993194)

Положим это
ResultStr:=ResultStr+String(TempLine)+#13+#10;
отличается от моего копирования только сборкой всех строк в одну.
А, во-вторых, Николай, чой-то не узнаю тебя, а где же твои железобетонные принципы? Если получаем неполноценный &CSTRING, то нефиг его использовать вообще, ни на чтение, ни ...
Так я его пользую _только_ в трех строчках и только для создания полноценной локальной переменной.
... на запись, ...
На запись нельзя. Андрей только что об этом писал. На запись либо либа сама должна записывать и не допускать посторонних к телу и либо, на худой конец, вызывать Callback и давать размер своего буфкра.
... а то изменится что-нить в следующей версии ... и ... :)
Во-первых, это документировано: PG (C5/5.5), AT&RG (C6)

"Clarion STRING variables are normally passed as two parameters: first, a UNSIGNED which contains the length of the data buffer; second, the address of the data.
CSTRINGs and PSTRINGs are passed the same as STRINGs (as two parameters). The RAW attribute can be used in the Clarion prototype to pass only the address of the string data to external 3GL
functions (Clarion language procedures do not need, or support, RAW)."

А во-вторых, у тебя есть лучшее предложение? Твой cLine такой же неполноценный ;)

WBR, Nick Tsigouro

(Добавление)
Я еще про LEN прочитал:
А я не прочитал.
The LEN procedure returns the length of a string. [...] If the string parameter is the label of a CSTRING or PSTRING variable, the procedure will return the length of the contents of the variable.
Блин.
А я всю жизнь писал Len(Clip(S))... даже для CString-ов.
Пора отписываться от листа, все равно на кларе почти не пишу.
Зачем для LEN размер переменной мне не очень понятно. Это же не SIZE().
?

--
Best regards,
Maxim Yemelyanov,
Enigma Soft Company
phone: +380 572 177977
WEB: http://enigmasoft.com.ua
e-mail: clalist@enigmasoft.com.ua
ICQ: 12253836

LEN(PString) должна вернуть первый байт.
LEN(СString) должна поискать первый <0>.
Размер переменной пока, вроде бы, не при чем.
LEN(String) должна найти последний не ' '. Т.е. поиск с конца. Вот тут нужен
полноценный реферал.
Runtime-овый SIZE() должен вернуть второй лонг реферала.

WBR, Nick Tsigouro

(Добавление)

Этот да :), но его то я предлагал просто проверить и для демонстрации варианта, когда нужен указатель на область памяти. А нормальный вариант как раз я описывал выше, по пунктам, в общем аналог твоего, но железобетонный, без некорректностей, связанных с недостаточной инициализацией &CSTRING в дельфийской процедуре. Но он грешит тем же, дополнительным копированием в буфер, патамучта нет указателей :).

И на самом деле эти решения (которые я выше описывал), конечно находятся несколько в отрыве, от оригинальной задачи. Вообще, если автор делает аналог той процедуры, которую он продемонстрировал на Delphi, то никакой дополнительный буфер делать не надо и мы можем вполне обойтись адресом полученной 0-term строки и функцией strcpy (strncpy не подходит, потому, что мы не знаем длину строки), просто в качестве первого аргумента strcpy нужно ставить вычисленный адрес (это LEN(ResString)) для копируемого блока в пределах общей результирующей строки, вот правда результирующую строку надо делать изначально достаточного размера.

И это самый быстрый вариант решения :)

Удачи!
__________________________________
Владимир Якимченко (ICQ: 16993194)
Написал: ClaList(2)
Гость

Сообщение Гость »

В хелпе о CString прочитай.
Прочитал. Не понял. Поясни.

Я еще про LEN прочитал:

The LEN procedure returns the length of a string. [...] If the string parameter is the label of a CSTRING or PSTRING variable, the procedure will return the length of the contents of the variable.

Зачем для LEN размер переменной мне не очень понятно. Это же не SIZE().

WBR, Nick Tsigouro

(Добавление)

Добрый день,Vladimir Yakimchenko!

В примере на Дельфи память под буфер выделяется строкой:
S: String[18];
а дальше в процедуру передается адрес этой строки:
TempLine:=@S;

С уважением, Андрей Истомин
Написал: ClaList(2)
Ответить