Win32Api Dll Load

Hi
I have now produced a dll file, and that dll file is win32api in ruby.I’m trying to get a function of the dll file. However, when Ruby tries to load that dll file, an error message appears.

C:/Ruby25-x64/lib/ruby/2.5.0/fiddle.rb:in ‘initialize’: Exec format error (LoadError)
from C:/from Ruby25-x64/lib/ruby/2.5.0/fiddle.rb:47:in ‘new’
from C:/Ruby25-x64/lib/ruby/2.5.0/fiddle.rb:47:in ‘dlopen’
from C:/Ruby25-x64/lib/ruby/2.5.0/Win32API.rb:28:in ‘rescue initialize’
from C:/Ruby25-x64/lib/ruby/2.5.0/Win32API.rb:24:in ‘initialize’

I also tried AppData\Roaming\SketchUp\SketchUp 2019\SketchUp\Plugins\dll.
I don’t know why such an error comes out. I want you to let me.
I will attach the ruby code and the dll code below.

ruby code

require "Win32API"

dll_path = File.join("C:/Program Files/SketchUp/SketchUp 2019", "bcdf")

aa = Win32API.new(dll_path, 'Message', 'I')


<dll code>

#include "stdio.h"
#include "Header.h"

extern "C"
{
	DLL_TEST_API int Example(int a, int b)
	{
		return a + b;
	}
}


<header>

#pragma once

#ifdef BCDF_EXPORTS
#define DLL_TEST_API __declspec(dllexport)
#else
#define DLL_TEST_API __declspec(dllimport)
#endif

1. Do not put your code files in SketchUp’s program path. They do not belong there.
All user files, plugins and extensions go in the %AppData% path since version 2014.

2. Use the ".dll" extension for the path as Win32API.rb will try to add it anyway, and you’ll do better to help it along.

3. The Win32API class is deprecated (for a long time) and no longer even appears in the current Ruby documentation for the versions used by SketchUp. The old compiled "Win32API.so" file was (a long time since) replaced with a "Win32API.rb" file that just made converted calls into other libraries. First into DL which was later removed. It then was rewritten to make converted calls using the Fiddle library.
So you might as well learn to use Fiddle directly.

Yes, the proper place for your code is in an extension specific subfolder of the "Plugins" folder.
These extension specific subfolders are traditionally prefixed with you author or company namespace identifier, followed by an underscore and the name of the extension.

You cannot just use … "AppData\Roaming\SketchUp\SketchUp 2019\SketchUp\Plugins\dll"
In Ruby you’d need to do …

plugins = "SketchUp/SketchUp 2019/SketchUp/Plugins"
dll_path = File.join( ENV["APPDATA"], plugins, 'ljs_dll_test', 'bcdf.dll')

… OR (even easier) …

plugins = Sketchup.find_support_file('Plugins')
dll_path = File.join( plugins, 'ljs_dll_test', 'bcdf.dll')

Your error indicates that the file was found and an attempt to load it was made but …
Exec format error (LoadError)
Fiddle could open it or more likely could not find the export function named "Message".
Ie, …

I looked at the C part of your code and I do NOT see an exported function by the name "Message".

I do see one by the name "Example".

Also when you post code, please post different languages delimited separately so they can be lexed properly. See

Also … If you will be writing Ruby extension using compiled C … then you can just use Ruby’s global require method if you properly name the entry point function.

The name of the file must be the same as the entry point function without the "Init_" prefix.
The file’s extension can be .so, .dll, etc.

See

from

:bulb:


Also there is a book specific to writing Ruby extensions in C.

Extending Ruby 1.9: Writing Extensions in C
by Dave Thomas …

1 Like

Did you compile the DLL as 64bit?

Are you able to load the DLL into a sample console app?

My first guess would be that the compiled dll is compiled for 32 bit, where SketchUp 2019 is 64 bit.

EDIT: as @tt_su already pointed out I see.

Also,

I would not use WIN32API for this, since that is Windows only. I would suggest using ruby Fiddle to wrap your native library: Module: Fiddle (Ruby 2.5.0)
this would give you the opportunity to compile and use your native code on OSX as well.

OR, make a Ruby C++ extension.

1 Like

Very good point. Fiddle is the way to interact with libraries from Ruby.

The drawback with Ruby C Extensions are that you need to compile a version for each Ruby version it needs to run on (excluding patch versions). So if you don’t need to invoke Ruby, but maybe just do some algorithms etc then a generic dynamic library saves you from the need to recompile per Ruby versions.

2 Likes

Hmmm… there’s a double echo in here… in Here … in here. :wink:

1 Like

Lol, I see. It seems you already had it al pointed out. You should include a TLDR in your long posts :sweat_smile:

Me? I thought that acronym was used by those that actually didn’t read because they felt the content was too long ? (ie, a disclaimer of sorts in case what they post doesn’t fit the conversation as it has developed.)


ThomThom, the above is for implicit linking at load time.

I believe FIddle uses explicit linking. Ie, it’s Fiddle::dlopen() and Fiddle::Importer.dlload() methods uses LoadLibrary and GetProcAddress to access foreign functions through the FFI.

Microsoft Docs : Link an executable to a DLL : Determine which linking method to use,
says in section “How to link explicitly to a DLL”:

Because applications call the DLL functions through a pointer, the compiler doesn’t generate external references, so there’s no need to link with an import library. However, you must have a typedef or using statement that defines the call signature of the exported functions that you call.

I think Fiddle takes care of calling the low level FFI interface calls so all the hard part is done by Fiddle.


So is it even needed to export functions if your DLL will only be explicitly linked (ie, such as using Fiddle or Ruby-FFI etc.,) ?

Well, I should’ve noticed you pointed out Fiddle already. Have never used it myself though.

TLDR was a joke. :slightly_smiling_face:

1 Like

It is 64 bits, so it works normally.
Thank you.

Yes. You need to export functions you want to use externally.

Processes explicitly linking to a DLL call GetProcAddress to obtain the address of an exported function in the DLL.

1 Like

EDIT: So an EXPORTS section of a .def file is needed

A module-definition or DEF file (*.def) is a text file containing one or more module statements that describe various attributes of a DLL. If you are not using the __declspec(dllexport) keyword to export the DLL’s functions, the DLL requires a DEF file.

I’d imagine that the module .def is more portable ?

Depends what you mean by portable. Def files are not cross platform.

Yes I was thinking “cross platform” as the docs stated that __declspec(dllexport) keyword was a Microsoft invention.