How to create dll using gcc compiler/Mingw for visual basic? - dll

How to create dll using gcc compiler/Mingw for visual basic?

The following is how I was able to get MinGW to build a DLL to be used in Excel 2003 VBA.
fooBar.cpp
int __stdcall Foo(int x)
{
return x * x;
}
double __stdcall Bar(double x)
{
return x * x;
}
1) Start MinGW shell and create a directory called fooBar .
Close the Excel Workbook (if open).
mkdir -p fooBar
cd fooBar
rm *.a *.dll *.def
2) Compile and generate a .def file - Note: this dll will not work because it has mangled symbols.
gcc -shared -o fooBar.dll fooBar.cpp -Wl,--output-def,fooBar.def,--out-implib,libfooBardll.a
The generated fooBar.def will look something like:
EXPORTS
_Z3Bard#8 #1
_Z3Fooi#4 #2
3) Modify the generated fooBar.def file by adding clean symbol aliases for the generated symbols. fooBar.def should now look something like:
EXPORTS
_Z3Bard#8 #1
_Z3Fooi#4 #2
Bar = _Z3Bard#8
Foo = _Z3Fooi#4
4) Cleaup again (except for the modified fooBar.def)
rm *.a *.dll
5) Compile with .def file with clean symbol aliases for the generated symbols.
gcc -shared -o fooBar.dll fooBar.cpp fooBar.def -Wl,--out-implib,libfooBar_dll.a
6) Open Excel and add the following VBA code (make sure to use the proper path, doubt it will have mmorris in it):
Private Declare Function Foo Lib _
"C:\MinGW\msys\1.0\home\mmorris\fooBar\fooBar.dll" _
(ByVal x As Long) As Long
Private Declare Function Bar Lib _
"C:\MinGW\msys\1.0\home\mmorris\fooBar\fooBar.dll" _
(ByVal x As Double) As Double
7) If you want to call the functions from an Excel Workbook, in a cell type =Foo(5) or =Bar(5)

First some DLL-iquette:
All exported function should have C linkage.
All C++-exceptions thrown inside the DLL should be catched inside the dll.
Why? Because there is no standard C++ ABI on Windows.
Also use __declspec(dllexport) on functions that should be exported
Now how to make the DLL without needing any DEF file
fooBar.cpp
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) int __stdcall square_int(int x) //I prefer manual mangling in this case to support static polymorphism
{
return x * x;
}
__declspec(dllexport) double __stdcall square_double(double x)
{
return x * x;
}
#ifdef __cplusplus
}
#endif
compile using
gcc fooBar.cpp -shared -Wl,--kill-at -o fooBar.dll
Now you should be able to call square_xxx as in mmorris answer. His solution probably works though.

This: http://www.mingw.org/wiki/DLL might be useful to you.

VB (all versions) prefers the pascal calling convention.
Declare your external functions with WINAPI and export them in your .def file.

Related

PyQt5 set qt_ntfs_permission_lookup

I want to use isWritable() from QFileInfo. According to the docs, you have to somehow set qt_ntfs_permission_lookup to 1 to get a meaningful result on Windows. The C++ code for this is
extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
qt_ntfs_permission_lookup++; // turn checking on
qt_ntfs_permission_lookup--; // turn it off again
How do I "translate" the extern statement into Python?
One possible solution is to create functions that change the state of that variable in C++ and export it to python. To export a C++ function to python there are options like pybind11, SWIG, sip, shiboken2, etc.
In this case, implement a small library using pybind11
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;
#ifdef Q_OS_WIN
QT_BEGIN_NAMESPACE
extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
QT_END_NAMESPACE
#endif
PYBIND11_MODULE(qt_ntfs_permission, m) {
m.def("enable", [](){
#ifdef Q_OS_WIN
qt_ntfs_permission_lookup = 1;
#endif
});
m.def("disable", [](){
#ifdef Q_OS_WIN
qt_ntfs_permission_lookup = 0;
#endif
});
#ifdef VERSION_INFO
m.attr("__version__") = VERSION_INFO;
#else
m.attr("__version__") = "dev";
#endif
}
and you can install it by following these steps:
Requirements:
Qt5
Visual Studio
cmake
git clone https://github.com/eyllanesc/qt_ntfs_permission_lookup.git
python setup.py install
Also with the help of github actions I have created the wheels for some versions of Qt and python so download it from here, extract the .whl and run:
python -m pip install qt_ntfs_permission-0.1.0-cp38-cp38-win_amd64.whl
Then you run it as:
from PyQt5.QtCore import QFileInfo
import qt_ntfs_permission
qt_ntfs_permission.enable()
qt_ntfs_permission.disable()

Error when compiling a program that uses Assimp with MinGW in CLion

I'm trying to compile a program in CLion that uses the Assimp library using the MinGW compiler. When building the project it gets up to 77% and gives the following error on the file "SMDLoader.cpp.obj":
C:\Dev\AssimpTest\cmake-build-debug\_deps\assimp-src\code\SMDLoader.cpp: In member function 'void Assimp::SMDImporter::GetAnimationFileList(const string&, Assimp::IOSystem*, std::vector<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&)':
C:\Dev\AssimpTest\cmake-build-debug\_deps\assimp-src\code\SMDLoader.cpp:579:47: error: 'strtok_s' was not declared in this scope
tok1 = strtok_s(&buf[0], "\r\n", &context1);
^
_deps\assimp-build\code\CMakeFiles\assimp.dir\build.make:2246: recipe for target '_deps/assimp-build/code/CMakeFiles/assimp.dir/SMDLoader.cpp.obj' failed
This is the CMakeLists.txt file i'm using:
cmake_minimum_required(VERSION 3.13)
project(AssimpTest)
set(CMAKE_CXX_STANDARD 11)
find_package(assimp 4.1.0 QUIET)
if (NOT assimp_FOUND)
include(FetchContent)
FetchContent_Declare(
assimp
URL https://github.com/assimp/assimp/archive/master.tar.gz
)
FetchContent_GetProperties(raylib)
if (NOT assimp_POPULATED)
set(FETCHCONTENT_QUIET NO)
FetchContent_Populate(assimp)
set(CMAKE_BUILD_TYPE release CACHE STRING "" FORCE)
set(ASSIMP_BUILD_TESTS OFF CACHE BOOL "" FORCE)
add_subdirectory(${assimp_SOURCE_DIR} ${assimp_BINARY_DIR})
endif()
endif()
add_executable(AssimpTest main.cpp)
target_link_libraries(${PROJECT_NAME} assimp)
Here's the main file i'm trying to compile, just in case:
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
int main() {
Assimp::Importer importer;
const char* pFile = R"(C:\Dev\raycast\models\teapot.fbx)";
const aiScene* scene = importer.ReadFile( pFile,
aiProcess_CalcTangentSpace |
aiProcess_Triangulate |
aiProcess_JoinIdenticalVertices |
aiProcess_SortByPType);
if( !scene)
{
printf(importer.GetErrorString());
return -1;
}
printf("Num meshes: %i", scene->mNumMeshes);
return 0;
}
The main reason i'm trying to use Assimp is to import .fbx models into my program, so if there is any way to optimize all of this setup just for that, that would be really helpful!
The information i found about the usage of this library with MinGW on the internet was really scarce.
Anyway thanks for help in advance.
If you don't need the SMD loader, you can simply disable it. Go to File -> Settings -> Build, Execution, Deployment -> CMake and insert "-DASSIMP_BUILD_SMD_LOADER=NO" (without " ") into CMake options
GCC does not implement the _s functions. The solution is to change the #indef condition at the top of the SMDloader.cpp to check agains _MSC_VER instead of _WIN32:
#ifndef _MSC_VER
#define strtok_s strtok_r
#endif
Which mingw- and assimp-version do you use? Mingw is part of the CI-buildchain we are using to test the assimp-code and this issue shall not occur anymore. So if this issue is on our current master we need to fix it.
And which kind of information do you miss when using mingw? I will try to optimize this.
Thanks!

make mosquitto-auth-plug on windows

I am currently trying to build the mosquitto-auth-plugin on windows but I am unsure which make process to use. The doc says to edit the config.mk file which I have done, then to 'make' the auth-plug -- this is were I am struck I have tried to make using GnWin & MinGW but neither has worked is there a way to build-make the library on windows or can I make it in Linux and copy the auth-plug.o to my windows machine?
I'm not aware of anybody having attempted to build mosquitto-auth-plug on Windows, and I'd be very surprised if that worked at all; as the author of the plugin, I paid no attention to portability outside Un*x, and so as to not raise hopes, I will not. :-)
That said, you cannot run (load) shared objects built on Linux on Windows. What may be possible, but it's been years since I did anything similar, is to cross compile with an appropriate toolchain.
I build it for Windows, using the HTTP and JWT backends only.
Had to fix:
Put __declspec(dllexport) to the mosquitto_auth_Xyz... functions in auth-plug.c.
Added alternative code for fnmatch(a,b) and strsep() in auth-plug.c, see below.
In log.c I fell back to use log=__log instead of log=mosquitto_log_printf as I failed importing the function from libmosquitto.
Compiled using Visual Studio 2017 Express with preprocessor definitions _CRT_NONSTDC_NO_DEPRECATE and _CRT_SECURE_NO_WARNINGS put into place.
The code works fine!
For fnmatch(a,b) and strsep() in auth-plug.c change the #include to:
#ifdef _WIN32
#include <windows.h>
#include <shlwapi.h>
#define fnmatch(a, b, c) PathMatchSpecA(a, b)
extern char* strsep(char** stringp, const char* delim)
{
char* start = *stringp;
char* p;
p = (start != NULL) ? strpbrk(start, delim) : NULL;
if (p == NULL)
{
*stringp = NULL;
}
else
{
*p = '\0';
*stringp = p + 1;
}
return start;
}
#else
#include <fnmatch.h>
#endif

CMake adds -Dlibname_EXPORTS compile definition

CMake adds the following compile definition to all source code files automatically when simply compiling a target:
-Dlibname_EXPORTS
Why is this done and how can I disable it?
cmake add <libname>_EXPORTS macros only for shared libraries. It's useful when exporting API's in Windows DLL.
#if defined(_WINDOWS) && defined(testlib_EXPORTS)
# define API_DLL extern "C" __declspec(dllexport)
#else
# define API_DLL
#endif
API_DLL void foo();
It could be disabled by setting the DEFINE_SYMBOL property of target to empty.
# disable the <libname>_EXPORTS
set_target_properties(sharedlib
PROPERTIES
DEFINE_SYMBOL ""
)
Reference
http://www.cmake.org/cmake/help/v3.0/prop_tgt/DEFINE_SYMBOL.html

Calling a dll from fortran

I am aiming at calling a dll file from a fortran compiler. I am doing all this in windows using the mingw compiler.
The dll was created using a g++ compiler
The code for which I am trying to create a dll
// example_dll.cpp
#include <stdio.h>
#include "example_dll.h"
__stdcall void hello()
{
printf("Hello");
}
command entered in the command prompt
g++ -c -DBUILDING_EXAMPLE_DLL example_dll.cpp
g++ -shared -o example_dll.dll example_dll.o -Wl,--out-implib,libexample_dll.a
The above two commands creates the dll file.
The job now is to create a fortran script to compile the dll file previously created.
For this purpose I am looking forward to create a fortran file capable of linking to the dll previously created.
Any help will be appreciated.
Thanks,
Adarsh
Later I tried some of the possibilities. My updated files are as follows
C file for which the DLL is created is as follows
// example_dll.c
#include <stdio.h>
#include "example_dll.h"
EXPORT void tstfunc (void)
{
printf("Hello\n");
}
EXPORT int Double11(int x)
{
printf("From the Double11\n");
printf("%d\n",x);
return x;
}
.h file used to create the DLL is as follows
// example_dll.h
#ifdef EXAMPLE_DLL_H
// the dll exports
#define EXPORT __declspec(dllexport)
#else
// the exe imports
#define EXPORT __declspec(dllimport)
#endif
// function to be imported/exported
EXPORT void tstfunc (void);
EXPORT int Double11(int x);
Fortran file used to link the dll is as follows
! fortcall.f90
program ForCall
IMPLICIT NONE
integer :: sum
integer :: inte3
INTERFACE
SUBROUTINE write() BIND(C,NAME='tstfunc')
END SUBROUTINE write
END INTERFACE
INTERFACE
SUBROUTINE get_integer(inte,inte2) BIND(C,NAME='Double11')
USE ISO_C_BINDING
IMPLICIT NONE
INTEGER (C_INT), VALUE :: inte
INTEGER (C_INT), INTENT(OUT) :: inte2
END SUBROUTINE get_integer
END INTERFACE
CALL write
CALL get_integer(1,inte3)
print*,"the output is",inte3
END PROGRAM ForCall
After entering the following directive in the command prompt
gfortran -o dll_foo_test fortcall.f90 -L. example_dll.dll
The output will be as follows
Hello
From the Double11
1
the output is -2
At this point something is not right. The code is capable of passing a value from FORTRAN to the DLL, whereas the code is not returning the right value from the dll. Some junk value of -2 is being displayed instead of 1.
I would like to fix that part in the code.