Skip to content

Instantly share code, notes, and snippets.

@rdinse
Last active June 23, 2020 00:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rdinse/0696f2cd3509a01237e5c3385dc54869 to your computer and use it in GitHub Desktop.
Save rdinse/0696f2cd3509a01237e5c3385dc54869 to your computer and use it in GitHub Desktop.
Building a DLL for VBA and MS Access SQL with Mingw-w64 and CMake with unit tests

./CMakeLists.txt

cmake_minimum_required(VERSION 3.17)
include(GenerateExportHeader)
project(MyDLL)
set(LIB_SRCS dllmain.cpp)
SET (LIB_TYPE SHARED)
add_library(MyDLL ${LIB_TYPE} ${LIB_SRCS})
GENERATE_EXPORT_HEADER(MyDLL)
ENABLE_TESTING()
ADD_SUBDIRECTORY(tests)

./dllmain.cpp

#include <windows.h>
#include <iostream>

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call,  LPVOID lpReserved)
{
    return TRUE;
}

extern "C" __declspec(dllexport) int foo()
{
    return 1;
}

./tests/CMakeLists.txt

link_directories (${CMAKE_CURRENT_BINARY_DIR}/../)
include_directories (${CMAKE_CURRENT_BINARY_DIR}/../)
ADD_EXECUTABLE(test1 test1.cpp)
ADD_TEST(NAME mytest COMMAND test1)
target_link_libraries(test1 MyDLL.dll)

./tests/test1.cpp

#include <windows.h>
#include <iostream>
#include <mydll_export.h>
extern "C" __declspec(dllimport) int foo();

int main(int, char**)
{
    std::cout << foo() << std::endl;
}

NOTE: The exported function symobls need to be lower case to work with the dllimport/dllexport macros! Otherwise you will get a undefined reference to __imp_foo linker error.

Compile, debug and test:

mkdir debug; cd debug; rm CMakeCache.txt; cmake .. -DCMAKE_BUILD_TYPE=Debug "-GMinGW Makefiles"
mingw32-make.exe
 & "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\devenv.exe" /DebugExe ".\tests\test1.exe"

Compile for release and import:

mkdir release; cd release; rm CMakeCache.txt; cmake .. -DCMAKE_BUILD_TYPE=Release "-GMinGW Makefiles"
mingw32-make.exe

In e.g. Microsoft Access 2019, create a module or add at the top of an existing one for the functions to be available in MS Access SQL. I failed to call the function directly in MS Access SQL, but it was possible to call a VBA wrapper function.

Option Compare Database
Public Declare PtrSafe Function foo _
   Lib "libMyDLL" Alias "foo" _
   (ByVal strOne As String, ByVal strTwo As String) As Double
Function fooWrapper()
   fooWrapper = foo()
End Function

Now you can use the function in an SQL query like this:

"SELECT * FROM mytable ORDER BY fooWrapper() ASC"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment