Calling conversion

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Ответить
Аватара пользователя
FedeX
постоялец
Сообщения: 422
Зарегистрирован: 27.03.2006 09:25:34
Откуда: украина, житомир

Calling conversion

Сообщение FedeX »

Пытаюсь перевести на Паскаль заголовки libgles_cm.dll библиотечки под Win32 (емуляция OpenGL ES под Win32), но столкнулся с тем, что часть функций имеет толи какой-то нестандартный Calling conversion, то ли вообще как-то не так описаны. Для этой же библиотеки только WinCE версии я уже вроде бы перевёл заголовки - там все функции cdecl. Всё вроде работает. В сишных заголовках под Win32 стоят такие макросы:

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

#if defined(AEE_SIMULATOR)

#define __GL_EXPORTS

#endif



#ifdef _WIN32

#   ifdef __GL_EXPORTS

#       define GL_API __declspec(dllexport)

#   else

#       define GL_API __declspec(dllimport)

#   endif

#else

#   ifdef __GL_EXPORTS

#       define GL_API

#   else

#       define GL_API extern

#   endif

#endif



#define GL_APIENTRY



#ifndef GLAPI

#   define GLAPI GL_API

#endif

, а функции обьявлены например как:
#ifdef __cplusplus

extern "C" {

#endif
GLAPI EGLint APIENTRY eglGetError();
#ifdef __cplusplus

}

#endif
но когда я обьявляю функции как
function eglGetError:EGLint;stdcall;external egl_lib name 'eglGetError';
при запуске приложения пишет, что точка входа в процедуру не найдена. Причём не все процедуры не находяться, а только те что начинаються на eglххх. Я попробовал открыть длл в написанной на Делфи утилитке, что используя модуль imagehlp отображает экспортируемые функции. В ней я увидел интересную вещь - функции, точка входа которых не найдена отображаються как напр. _eglGetError@0 , тоесть почему-то со знаком "_" в начале и с указанием общего размера передаваемых параметров после символа "@". Что это может быть? Какие-то с++-ные методы чтоли? Как их обьявить на Паскале?
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Это обычный stdcall (если я не путаю. Если путаю, то cdecl), только библиотека немного по-больному слинкована.
Объявить, наверное, можно, указав это кривое имя после name.
Аватара пользователя
FedeX
постоялец
Сообщения: 422
Зарегистрирован: 27.03.2006 09:25:34
Откуда: украина, житомир

Сообщение FedeX »

Да - действительно, если после name указать это странное имя, то точка входа находиться. Ещё всё не перевёл, но наверно дольше проблем не будет. Спасибо.
Аватара пользователя
VAshot
постоялец
Сообщения: 128
Зарегистрирован: 01.11.2007 11:31:21
Откуда: Пермь

Сообщение VAshot »

Есть библиотека аписанная на С, dll и lib файл.
Вот так вызов идет из программы на С:

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

#pragma once

#include <iostream>
#include <stdio.h>
#include <tchar.h>

_declspec(dllimport) long GetHeaderSecondArg(TCHAR* fileName);

#include "HeadReader_demo.h"

int _tmain(int argc, _TCHAR* argv[])
{
   TCHAR* fileName;
   fileName = L"N5_18062008_17 22 12.bn1";

   GetHeaderSecondArg(fileName);

   return 0;
}


А вот так пытаюсь вызвать я:

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

interface

uses
  function GetHeaderSecondArg(filename: PWideString): Integer; cdecl; external 'BINFileReader_demo.dll' name 'GetHeaderSecondArg';           


При запуске ошибка: "Не могу найти точку входа".
Это я делаю что-то не то или в библиотеке С надо переделать? Исходника, пока, библиотеки нет.
Аватара пользователя
FedeX
постоялец
Сообщения: 422
Зарегистрирован: 27.03.2006 09:25:34
Откуда: украина, житомир

Сообщение FedeX »

Да, скорее всего это тоже что и у меня было..
Надо перекомпилировать саму длл-ку, и везде в экспортируемых функциях прописать extern C (или что-то вроде этого)..
Если исходников либы нет, то возможно поможет какая-нибудь прога вроде ADLLExport.. Посмотреть, какие там (в длл) имена функций через прогу и так их и описать в паскалевских хедерах.. А ещё проще обращаться к функциям по индексам..
Аватара пользователя
VAshot
постоялец
Сообщения: 128
Зарегистрирован: 01.11.2007 11:31:21
Откуда: Пермь

Сообщение VAshot »

Вроде получилось, когда результат передается в Result.
А как подключить и вызвать такую функцию?

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

bool GetHeaderFirstArg(TCHAR* fileName, char* retVal);

Функция принимает два аргумента: указатель строку типа TCHAR* (в данной сборке этот тип означает указатель на "широкие" строки) и указатель на строку типа char* (указатель на обычную строку).
fileName - имя файла, откуда необходимо получить данные,
retVal - указатель на строку в памяти, куда необходимо записать данные
Функция записывает в retVal первую строку заголовка файла и возвращает true в случае успеха.


Перебрад несколько способов, что-то делаю не так. Не направите на путь истинный?
GrayEddy
постоялец
Сообщения: 375
Зарегистрирован: 06.05.2005 09:37:56

Сообщение GrayEddy »

Скорее так:

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

function GetHeaderFirstArg(fileName: WideString; retVal: PChar): Boolean
Аватара пользователя
FedeX
постоялец
Сообщения: 422
Зарегистрирован: 27.03.2006 09:25:34
Откуда: украина, житомир

Сообщение FedeX »

Помойму так:
function GetHeaderFirstArg(fileName: PWideChar; retVal: PAnsiChar): Boolean;cdecl; external 'BINFileReader_demo.dll' index ...;

..хех.. хотя возможно и так:
function GetHeaderFirstArg(fileName: PWideChar; var retVal: PAnsiChar): Boolean;cdecl; exter...

Вообще к либе должны быть как минимум какие-то доки. И в них должны описываться такие подробности... Просто если учесть что во второй параметр функция будет возвращать значение, то логично что буфер для строки либо должен быть уже выделен либо он должен быть выделен функцией .. Во втором случае логичен "var", в первом - нет..
Аватара пользователя
VAshot
постоялец
Сообщения: 128
Зарегистрирован: 01.11.2007 11:31:21
Откуда: Пермь

Сообщение VAshot »

Работает (что и логично и правильно) так: "fileName: PWideString".

Вот так работает, только я не знаю, корректно это или нет. Впервые использую указатели самостоятельно.

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

  function GetNumOfStrings(fileName: PWideString): Integer; cdecl; external ...
  function GetHeaderFirstArg(fileName: PWideString; retVal: PAnsiChar): Boolean; cdecl; external ...
//---------------------------------------------
var
  WS : WideString;
  PS : PAnsiChar;

  Count: Integer;
begin
  WS:='E:\folder\N5_18062008_17 22 12.bn1';
//-----
  Count := GetNumOfStrings(PWideString(WS));
  ShowMessage( IntToStr(Count) );
//-----
  GetMem(PS, SizeOf(AnsiChar));
  GetHeaderFirstArg(PWideString(WS), PS);
  ShowMessage( PS^ );
  Freemem(PS);
//-----
end;
Аватара пользователя
FedeX
постоялец
Сообщения: 422
Зарегистрирован: 27.03.2006 09:25:34
Откуда: украина, житомир

Сообщение FedeX »

Вообще-то не должно работать... :?
GetMem(PS, SizeOf(AnsiChar));
Это должно всегда создавать буфер величиной в один байт (один символ)...
Если функция и должна считывать из файла только один символ, то правитьно, если должна считывать больше - то не правильно..
Что показывает ShowMessage( PS^ ); ? Один символ? А так в остальном правильно..
Аватара пользователя
VAshot
постоялец
Сообщения: 128
Зарегистрирован: 01.11.2007 11:31:21
Откуда: Пермь

Сообщение VAshot »

Да, пожалуй надо домножить на число символов
GrayEddy
постоялец
Сообщения: 375
Зарегистрирован: 06.05.2005 09:37:56

Сообщение GrayEddy »

Тут несколько вариантов, тоже подключал в свое время сишную либу от кассового аппарата, поднял исходники, тогда по аналогии

Вариант 1:

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

var
  s: string;
...
GetHeaderFirstArg(PWideString(WS), PChar(s));
...


Вариант 2 (более правильный, что ли):

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

var
  s: PChar;
...
s := StrAlloc(1024); // Занимаем память
s := StrCopy(s, 'COM1');
GetHeaderFirstArg(PWideString(WS), PChar(s));
StrDispose(s); // Отдаем память
...
Ответить