Thread overview
Creating DLL
Jun 16, 2022
Sergeant
Jun 16, 2022
Adam D Ruppe
Jun 16, 2022
Sergeant
Jun 16, 2022
Adam D Ruppe
Jun 16, 2022
Sergeant
Jun 16, 2022
Ali Çehreli
Jun 16, 2022
Adam D Ruppe
Jun 16, 2022
Ali Çehreli
Jun 16, 2022
Adam D Ruppe
Jun 16, 2022
Sergeant
June 16, 2022

Hi,
I wonder if anyone knowledgeable can point me in the right direction here.
I created DLL in Visual D, but when I try to use it by my application (AHK script), DLL itself is loaded ok, but error is set to "specified function could not be found inside the DLL". (Same DLL that I made in C++ works, but this doesn't somehow)

Sample code looks like this:

module my_dll;

import core.sys.windows.windows;
import core.sys.windows.dll;

export int my(int a, int b)
{
  // ... my code ...
  // return output;
}

mixin SimpleDllMain;

I set "-shared" switch in VS. Is there anything I'm missing here?
Thanks!

June 16, 2022
On Thursday, 16 June 2022 at 13:57:48 UTC, Sergeant wrote:
>     export int my(int a, int b)

the name here is going to be mangled, so like "_D5mydll2myiiZi" or something like that.

You might want to add `extern(C)` to it so it keeps the simple name "my", that might help.
June 16, 2022

Adam thank you, it works now!

May I ask one more question: why a code like this would work in D-application but not in D-DLL? (also I notice some other D functions don't work in DLL):

import std.string;

export extern(C) string my(string input)
{
string output = "";
auto lines = input.lineSplitter();
foreach (line; lines){
	output ~= line;
}
return output
}
June 16, 2022
On Thursday, 16 June 2022 at 16:07:41 UTC, Sergeant wrote:
> May I ask one more question: why a code like this would work in D-application but not in D-DLL? (also I notice some other D functions don't work in DLL):

Probably because the runtime not initialized properly. Export an Initialize() and Terminate() functions and call them from your application loading the dll.

Inside those functions:


export extern(C) void Initialize() {
   import core.runtime;
   Runtime.initialize();
}


export extern(C) void Terminate() {
   import core.runtime;
   Runtime.terminate();
}



If you call those the other functions should start working.

(this is a fairly common thing libraries need to do, but it might be tricky if you are loading the dll into an uncooperative application, there's other hacks for that, but having your functions like this and the app calling them are the right way to do it)
June 16, 2022
On 6/16/22 09:07, Sergeant wrote:

> May I ask one more question: why a code like this would work in
> D-application but not in D-DLL?

D programs generated by D compilers automatically initialize the D runtime. You can do the same with rt_init:

pragma (crt_constructor)
extern(C) int initialize() { // Can have any name
  return rt_init();
}

And to deinitialize;

pragma (crt_destructor)
extern(C) int terminate() { // Can have any name
  return rt_term();
}

Although, I haven't tested it with a DLL but with .so libraries on Linux... :/

This answer may be relevant:

  https://forum.dlang.org/post/t8diks$2l79$1@digitalmars.com

Ali

June 16, 2022
On Thursday, 16 June 2022 at 16:19:22 UTC, Ali Çehreli wrote:
> pragma (crt_constructor)

You have to be pretty careful about this since it might not run in the order you expect. If there's two things in the program with a equal-priority crt constructor, they are run in arbitrary order. In a shared lib, there's also the possibility that loader locks are in place, and if it runs rt_init specifically, that can run D module constructors... which might load other libraries.

Similar concerns apply to doing rt_init in DllMain.

This is why an explicit initialization call is the preferred method - there, the time it is called is well-defined by the user after initial loading is complete.
June 16, 2022
On 6/16/22 09:32, Adam D Ruppe wrote:

> This is why an explicit initialization call is the preferred method -
> there, the time it is called is well-defined by the user after initial
> loading is complete.

Agreed but that excludes using the D runtime in 'static this' (and shared) blocks, right? If my explicit call to Initialize is in a 'shared static this', then I can have only one such block, right?

Ali

June 16, 2022
On Thursday, 16 June 2022 at 16:37:34 UTC, Ali Çehreli wrote:
> Agreed but that excludes using the D runtime in 'static this' (and shared) blocks, right?

It is runtime.initialize that calls those `static this` blocks.

> If my explicit call to Initialize is in a 'shared static this'

This is backward - the explicit call to Initalize is in the exe. It'd look like:

// this code is in the exe! pretend it is C++ or whatever

HANDLE lib = LoadLibrary("my_d_lib.dll");
if(lib !is null) {
     auto fn = cast(typeof(init_func)) GetProcAddress("Initialize");
     if(fn !is null) {
           fn(); // this now calls runtime.initialize which calls the static this blocks etc
          // you're now good to call any D functions
     }
}

June 16, 2022
Adam, thank you again!

Adding Initialize()/Terminate() to code and calling from my application as you suggested didn't help, unfortunately. Maybe the problem is in the scripting language I'm using (AHK) which is not designed to handle situations like these.

In any case, appreciate your help!
June 16, 2022
On Thursday, 16 June 2022 at 16:19:22 UTC, Ali Çehreli wrote:
> On 6/16/22 09:07, Sergeant wrote:
>
> This answer may be relevant:
>
>   https://forum.dlang.org/post/t8diks$2l79$1@digitalmars.com


Ali, thank you, I'll take a look.