Recent

Author Topic: how to use a class from a DLL  (Read 6845 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 19249
  • Glad to be alive.
Re: how to use a class from a DLL
« Reply #15 on: December 20, 2022, 12:25:51 pm »
The default distribution is still 32 bit, unless you installed through fpcupdeluxe.
objects are fine constructs. You can even initialize them with constructors.

Rik

  • Jr. Member
  • **
  • Posts: 84
Re: how to use a class from a DLL
« Reply #16 on: December 20, 2022, 01:38:53 pm »
Quote
The default distribution is still 32 bit, unless you installed through fpcupdeluxe.
I just checked the exe:
Quote
PE  d†
so it should be 64 bit?

Meanwhile I will have a look at https://blogs.embarcadero.com/how-to-use-a-c-dll-in-any-delphi-program/ (proxy dll).
Complicated stuff (at least for me) ...
« Last Edit: December 20, 2022, 01:43:07 pm by Rik »

balazsszekely

  • Guest
Re: how to use a class from a DLL
« Reply #17 on: December 20, 2022, 01:44:25 pm »
@Rik

Quote
so it should be 64 bit?
Lazarus menu->Help->About. What do you see? i386 or x86_64?

Thaddy

  • Hero Member
  • *****
  • Posts: 19249
  • Glad to be alive.
Re: how to use a class from a DLL
« Reply #18 on: December 20, 2022, 01:50:13 pm »
a c dll is a never a problem. a c++ dll is...
objects are fine constructs. You can even initialize them with constructors.

Rik

  • Jr. Member
  • **
  • Posts: 84
Re: how to use a class from a DLL
« Reply #19 on: December 20, 2022, 01:52:32 pm »
Quote
Quote
so it should be 64 bit?
Lazarus menu->Help->About. What do you see? i386 or x86_64?
It says x86_64-win64-win32/win64 (see attached image)

Thaddy

  • Hero Member
  • *****
  • Posts: 19249
  • Glad to be alive.
Re: how to use a class from a DLL
« Reply #20 on: December 20, 2022, 01:55:07 pm »
that means you have a 32 bit version that can cross compile to 64 bit. so 32 bit. not sure.
I use dedicated compilers and IDE's per platform.
« Last Edit: December 20, 2022, 01:57:42 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

Warfley

  • Hero Member
  • *****
  • Posts: 2066
Re: how to use a class from a DLL
« Reply #21 on: December 20, 2022, 01:57:18 pm »
Strange that the StdC++ libraries for MSVC, GCC and LLVM are all compiled as dynamic libraries then when you say that it's not intended to be possible. Might be like the myth that bumblebees are not supposed to be able to fly, but nobody told them. :P

That is something that the compilers do that is outside of the standards and can only be guaranteed to work within their ecosystem. But as this is not standardized there is no guarantee that this will work across these ecosystems. For example there is no guarantee that the current LLVM stdc++ lib works with code generated by an old LLVM 2, or that an GCC executable will be able to use the MSVC++ library. It can be done on this low level because, but it is not generally applicable.
This is unlike external functions as defined in the C standard, when I write a function as external in C, any compiler that supports the standardized C calling convention (like FPC) will be able to call that function, no matter if it is compiled with a 40 year old Fortran compiler or a modern day C++ compiler.

Everything that is not defined in the C++ standard can be considered not valid C++. Implementation specific things might work for a specific C++ compiler and ecosystem (such as MSVC++) but can not be generalized to work with anything outside that ecosystem

Rik

  • Jr. Member
  • **
  • Posts: 84
Re: how to use a class from a DLL
« Reply #22 on: December 20, 2022, 02:03:40 pm »
Quote
a c dll is a never a problem. a c++ dll is...
They (Newport/Oriel) provide a "C# .NET" DLL, cornerstone.dll (attached).
But unfortunately it is undocumented (asked Newport, but the response was :  "Unfortunately there is not a lot in terms of documentation").
And DLL Export Viewer gives no result on it.

So I am still tapping in the dark with a c++ DLL that I cannot get working (so far) and a c# DLL that should be easier to use, but is undocumented.
« Last Edit: December 20, 2022, 02:09:40 pm by Rik »

balazsszekely

  • Guest
Re: how to use a class from a DLL
« Reply #23 on: December 20, 2022, 02:03:58 pm »
@Rik
Quote
It says x86_64-win64-win32/win64 (see attached image)
It's 64 bit. PascalDragon's example does work at my side, but make sure you copy the 64 bit dll in your project folder, the one from x64 folder. I tested with FPC/Lazarus trunk.

Quote
Meanwhile I will have a look at https://blogs.embarcadero.com/how-to-use-a-c-dll-in-any-delphi-program/ (proxy dll).
It's not that hard, you have to follow a few steps described in the article. You do need Delphi c++ builder though.

Rik

  • Jr. Member
  • **
  • Posts: 84
Re: how to use a class from a DLL
« Reply #24 on: December 20, 2022, 02:25:29 pm »
Quote
Posted by: GetMem
but make sure you copy the 64 bit dll in your project folder, the one from x64 folder
Sorry ... I had the 32 bit DLL, with the 64 bit version it seems to work. A bit embarrassing.

Next is to check if I can communicate with the monochromator (ie if the other commands beside GetLibraryVersion work too), fingers crossed.

I will also give it a try to create the proxy dll.

Many thanks for helping me out (also to Thaddy and the others).

Rik

  • Jr. Member
  • **
  • Posts: 84
Re: how to use a class from a DLL
« Reply #25 on: December 20, 2022, 04:20:12 pm »
A shot update

Using the functions
Code: Pascal  [Select][+][-]
  1. procedure COriel_USB_Ctor(This: Pointer); cdecl; external LibName name '??0COriel_USB@@QEAA@XZ';
  2. procedure COriel_USB_Dtor(This: Pointer); cdecl; external LibName name '??1COriel_USB@@QEAA@XZ';
  3. function COriel_USB_GetLibraryVersion(This: Pointer): PChar; cdecl; external LibName name '?GetLibraryVersion@COriel_USB@@QEAAPEADXZ';
  4. function COriel_USB_Send(This: Pointer; strCommand: PChar; bStaticDelay: LongBool): LongBool; cdecl; external LibName name '?Send@COriel_USB@@QEAAHPEBDH@Z';
  5. function COriel_USB_Read(This: Pointer; strReturn: PChar): LongBool; cdecl; external LibName name '?Read@COriel_USB@@QEAAHPEAD@Z';
  6. function COriel_USB_Query(This: Pointer; strCommand: PChar; strReturn: PChar; bStaticDelay: LongBool = false): LongBool; cdecl; external LibName name '?Query@COriel_USB@@QEAAHPEBDPEADH@Z';
  7. function COriel_USB_getCommandDelay(This: Pointer; command: PChar): LongInt; cdecl; external LibName name '?getCommandDelay@COriel_USB@@QEAAHPEBD@Z';
  8.  
The functions COriel_USB_GetLibraryVersion, COriel_USB_getCommandDelayand COriel_USB_Send do work.
Using COriel_USB_Send I can "talk" to the monochromator (eg. change the wavelength).
But trying to "read" from the monochromator using COriel_USB_Query or COriel_USB_Read causes a "External: ACCESS VIOLATION" error (see attached).
I tried to declare strReturn as var (because it hold a return variable), but that doesn't help.
I also found out that "external LibName name ..." can be replaced by "external LibName index ..." (where the index of the function is retrieved using DLL Export Viewer), but that doen't solve the problem either.

balazsszekely

  • Guest
Re: how to use a class from a DLL
« Reply #26 on: December 20, 2022, 04:54:21 pm »
@Rik

Looking at the exported function list, there is Initialize function too. Maybe you have to call it before trying to communicate with the device.

Thaddy

  • Hero Member
  • *****
  • Posts: 19249
  • Glad to be alive.
Re: how to use a class from a DLL
« Reply #27 on: December 20, 2022, 07:07:14 pm »
The Pchars need to be pre-allocated in your main program, I guess. (with getmem/allocmem and freemem/dispose)
objects are fine constructs. You can even initialize them with constructors.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6396
  • Compiler Developer
Re: how to use a class from a DLL
« Reply #28 on: December 20, 2022, 09:44:25 pm »
Strange that the StdC++ libraries for MSVC, GCC and LLVM are all compiled as dynamic libraries then when you say that it's not intended to be possible. Might be like the myth that bumblebees are not supposed to be able to fly, but nobody told them. :P

That is something that the compilers do that is outside of the standards and can only be guaranteed to work within their ecosystem. But as this is not standardized there is no guarantee that this will work across these ecosystems. For example there is no guarantee that the current LLVM stdc++ lib works with code generated by an old LLVM 2, or that an GCC executable will be able to use the MSVC++ library. It can be done on this low level because, but it is not generally applicable.
This is unlike external functions as defined in the C standard, when I write a function as external in C, any compiler that supports the standardized C calling convention (like FPC) will be able to call that function, no matter if it is compiled with a 40 year old Fortran compiler or a modern day C++ compiler.

Everything that is not defined in the C++ standard can be considered not valid C++. Implementation specific things might work for a specific C++ compiler and ecosystem (such as MSVC++) but can not be generalized to work with anything outside that ecosystem

The reality however is that C++ code across module boundaries is used a lot. The whole of Qt is build around that. Also LLVM supports linking against MSVC C++ code on Windows and GCC C++ code on *nix.

Looking at the exported function list, there is Initialize function too. Maybe you have to call it before trying to communicate with the device.

When you undecorate the function names (using MSVC's undname utility) you'll get the following list:

Code: [Select]
public: __cdecl COriel_USB::COriel_USB(void) __ptr64
public: __cdecl COriel_USB::~COriel_USB(void) __ptr64
private: int __cdecl COriel_USB::Connect(void) __ptr64
private: int __cdecl COriel_USB::Disconnect(void) __ptr64
public: char * __ptr64 __cdecl COriel_USB::GetLibraryVersion(void) __ptr64
private: int __cdecl COriel_USB::Initialize(void) __ptr64
public: int __cdecl COriel_USB::Query(char const * __ptr64,char * __ptr64,int) __ptr64
private: int __cdecl COriel_USB::QueryString(char const * __ptr64,char * __ptr64,int) __ptr64
public: int __cdecl COriel_USB::Read(char * __ptr64) __ptr64
public: int __cdecl COriel_USB::Send(char const * __ptr64,int) __ptr64
private: int __cdecl COriel_USB::SendString(char const * __ptr64) __ptr64
public: void __cdecl COriel_USB::__autoclassinit2(unsigned __int64) __ptr64
public: int __cdecl COriel_USB::getCommandDelay(char const * __ptr64) __ptr64
private: void __cdecl COriel_USB::stringToUpper(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > & __ptr64) __ptr64

That means that Initialize is not public and thus shouldn't be used manually.

The functions COriel_USB_GetLibraryVersion, COriel_USB_getCommandDelayand COriel_USB_Send do work.
Using COriel_USB_Send I can "talk" to the monochromator (eg. change the wavelength).
But trying to "read" from the monochromator using COriel_USB_Query or COriel_USB_Read causes a "External: ACCESS VIOLATION" error (see attached).
I tried to declare strReturn as var (because it hold a return variable), but that doesn't help.
I also found out that "external LibName name ..." can be replaced by "external LibName index ..." (where the index of the function is retrieved using DLL Export Viewer), but that doen't solve the problem either.

Would you please show what exactly you tried.

Rik

  • Jr. Member
  • **
  • Posts: 84
Re: how to use a class from a DLL
« Reply #29 on: December 20, 2022, 10:22:30 pm »
Quote
When you undecorate the function names (using MSVC's undname utility) you'll get the following list:
That seems identical to what I could retrieve with DLL Export Viewer.

Quote
Would you please show what exactly you tried.
I will be at the office tomorrow afternoon for a short time and will try to post the full code then.
After that it will be until January 3rd before I return to the office and can give it another try to get things working.

Best wishes for the Holidays and a happy New Year!
« Last Edit: December 20, 2022, 10:28:05 pm by Rik »

 

TinyPortal © 2005-2018