4

I have written a function in C (for some bitwise operations on 64-bit) and I want to use that function in my excel vba macro. I used steps described here to create a DLL file using cygwin (64-bit).

Here are the commands I used to create the actual dll:

gcc -c tokenid.c
gcc -shared -o tokenid.dll tokenid.o -Wl,--add-stdcall-alias

The function declaration inside tokenid.c is like this:

extern __declspec(dllexport) unsigned long long __stdcall calculateToken(double epoch_time, LPSTR enb_market[], LPSTR file_type[], long source)

I have tested the dll with a small c program and it works fine. Here's the source code for test.c:

#include<stdio.h>
#include<windows.h>

//typedef unsigned long long (__stdcall *calcToken)(double, char[], char[], long);
typedef unsigned long long (__stdcall *calcToken)(double, LPSTR, LPSTR, long);

int main(){

  HANDLE ldll;

  calcToken calculateToken = NULL;

  ldll = LoadLibrary("tokenid.dll");
  if(ldll > (void*)HINSTANCE_ERROR){
    FARPROC fptr = GetProcAddress(ldll, "calculateToken");
    calculateToken = (calcToken)(fptr);

    char market[] = {'A','B','C'};
    char usage[] = {'D','E','F'};

    printf("%llu", calculateToken(1431680395, market, usage, 90));
  } else {
    printf("ERROR.");
  }

}

tokenid.c and test.c (and all other intermediate files) are in the same same directory (cygwin's default).

Then I copied the tokenid.dll (cygwin1.dll - dependency walker said it was missing) to the folder where the macro enabled workbook is stored. Here's the test macro I wrote:

Option Explicit

Public Declare Function calculateToken Lib "tokenid" (ByVal epoch_time As Double, ByVal market As String, ByVal usageType As String, ByVal source_id As Long) As Currency

Public Sub test()
    '*****************
    'Declare Variables
    '*****************

    Dim market As String, usageType As String
    Dim epoch As Double
    Dim source_id As Long
    Dim tokenid As Currency

        market = "ABC"
        usageType = "DEF" 'file type in the C program
        epoch = 1431680395
        source_id = 90

        tokenid = calculateToken(epoch, market, usageType, source_id)

        Debug.Print tokenid

End Sub

But excel is unable to find the dll. Whenever I try to run the macro, I get

Run-time error 48. File not found

I have already tried the following:

  • I tried hardcoding the path but its the same story.
  • I added the path of the current working directory to the system path but to no avail.
  • Dependency Walker does not find any missing dll. The cygwin1.dll (which it said was missing earlier) is picked up from the current working directory.

Can someone point me to the right direction? What am I doing wrong here?

EDIT: I am using Windows 7 (64-bit), Office 2013 and Cygwin 64-bit.

Also, noticed one weird thing. If I place the dll file in system32 folder and hardcode the path in the code, the error code changes from 48 to 53. The error code is always 48 no matter what else I do. Not sure why!

Solved:

I compiled the dll using the following statements:

i686-w64-mingw32-gcc -c tokenid.c
i686-w64-mingw32-gcc -shared -o tokenid.dll tokenid.o -Wl,--add-stdcall-alias -static-libgcc

I was on 64-bit Windows but Office was still 32-bit.

I also changed the return type of the declaration in VBA to Currency since I was returning a 64-bit value from the C program.

Community
  • 1
  • 1
fonzie
  • 43
  • 4

1 Answers1

2

1- you must mark your function as extern to prevent renaming it (if any).
2- your function returns long not double.
3- no need to put the extension (i.e .dll) in the declaration.

extern __declspec(dllexport) unsigned long long __stdcall calculateToken(double epoch_time, LPSTR enb_market[], LPSTR file_type[], long source)
{
    return 10;
}

and:

Public Declare Function calculateToken Lib "tokenid" (ByVal epoch_time As Double, ByVal market As String, ByVal usageType As String, ByVal source_id As Long) As Long

this is worked for me (windows 7 32 bit + office 2010 + minGW).
if problem still exists, try to run Excel as administrator.
EDIT
I have got the same error that you had got when I tried Cygwin; after some research I have got the solution:
you must use the cross-compiler (from Cygwin) as following:
1- for windows 64 bit:

x86_64-w64-mingw32-gcc -c tokenid.c
x86_64-w64-mingw32-gcc -shared -o tokenid.dll tokenid.o -Wl,--add-stdcall-alias

2- for windows 32 bit:

i686-w64-mingw32-gcc -c tokenid.c
i686-w64-mingw32-gcc -shared -o tokenid.dll tokenid.o -Wl,--add-stdcall-alias

As I understood: DLLs built with gcc on Cygwin can only be linked by EXE built with gcc on Cygwin.

houssam
  • 1,823
  • 15
  • 27
  • Thanks for the answer. I made the changes but it didn't work. Also, I should have mentioned the windows and office versions I am using. Added them to the original post. – fonzie May 16 '15 at 14:14
  • Also ran excel in administrator mode (opened excel.exe by right clicking and selecting "Run as Administrator") but same issue. – fonzie May 16 '15 at 14:21
  • @fonzie : I modified the answer. – houssam May 16 '15 at 18:07
  • Thanks @houssam. It worked. I have modified the original question with the steps that solved it. – fonzie May 16 '15 at 21:40
  • @fonzie : thanks for you also for providing the steps. – houssam May 16 '15 at 21:51
  • Thanks a lot for the last statement. I have been trying to build a dll using Cygwin and using it in Excel VBA. – Sandrocottus Jun 25 '20 at 17:52