syphilis has asked for the wisdom of the Perl Monks concerning the following question:

I must be going mad. First up here's what double.h looks like:
C:\_32\c>type double.h double __declspec(dllexport) my_double(int); C:\_32\c>
And here is double.c:
C:\_32\c>type double.c #include "double.h" double __declspec(dllexport) my_double(int num) { return (double) num; } C:\_32\c>
Let's turn double.c into a dll, using Visual Studio 7.0 as the compiler, and making sure to invoke the __stdcall calling convention:
C:\_32\c>cl /Gz /LD double.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.00.9466 for +80x86 Copyright (C) Microsoft Corporation 1984-2001. All rights reserved. double.c Microsoft (R) Incremental Linker Version 7.00.9466 Copyright (C) Microsoft Corporation. All rights reserved. /out:double.dll /dll /implib:double.lib double.obj Creating library double.lib and object double.exp C:\_32\c>
Let's check that double.dll does, in fact, export the my_double function:
C:\_32\c>dumpbin /exports double.dll Microsoft (R) COFF/PE Dumper Version 7.00.9466 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file double.dll File Type: DLL Section contains the following exports for double.dll 00000000 characteristics 4837FFED time date stamp Sat May 24 19:45:49 2008 0.00 version 1 ordinal base 1 number of functions 1 number of names ordinal hint RVA name 1 0 00001000 _my_double@4 Summary 2000 .data 2000 .rdata 1000 .reloc 7000 .text C:\_32\c>
That looks about right. Why the leading underscore ? Does that matter ?

By my reckoning, we should be able to access the my_double function using Win32::API. (I have version 0.53, and perl-5.10.0.) Here's the script I'm using:
C:\_32\c>type double.pl use Win32::API; use warnings; $function = Win32::API->new('double', 'my_double', 'N', 'D'); $ret = $function->Call(123); print $ret, "\n"; C:\_32\c>
Let's run that script:
C:\_32\c>perl double.pl Can't call method "Call" on an undefined value at double.pl line 5. C:\_32\c>
What gives ? (If I check the contents of $^E I find "The specified procedure could not be found")

Let's run a C program to check that the dll is ok. Here's the test program:
C:\_32\c>type double_test.c #include <stdio.h> #include "double.h" int main(void) { double d = my_double(123); printf("%f\n", d); return 0; } C:\_32\c>
Now let's build the app:
C:\_32\c>cl double_test.c double.lib Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.00.9466 for +80x86 Copyright (C) Microsoft Corporation 1984-2001. All rights reserved. double_test.c Microsoft (R) Incremental Linker Version 7.00.9466 Copyright (C) Microsoft Corporation. All rights reserved. /out:double_test.exe double_test.obj double.lib double_test.obj : error LNK2019: unresolved external symbol _my_double + reference d in function _main double_test.exe : fatal error LNK1120: 1 unresolved externals C:\_32\c>
Wtf ?

Let's try a slightly different approach. I'll compile double.c into double.obj, and then link to double.obj instead of double.lib:
C:\_32\c>cl -c double.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.00.9466 for +80x86 Copyright (C) Microsoft Corporation 1984-2001. All rights reserved. double.c C:\_32\c>
Now build double_test.exe by linking to double.obj:
C:\_32\c>cl double_test.c double.obj Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.00.9466 for +80x86 Copyright (C) Microsoft Corporation 1984-2001. All rights reserved. double_test.c Microsoft (R) Incremental Linker Version 7.00.9466 Copyright (C) Microsoft Corporation. All rights reserved. /out:double_test.exe double_test.obj double.obj Creating library double_test.lib and object double_test.exp C:\_32\c>
And finally run double_test.exe:
C:\_32\c>double_test.exe 123.000000 C:\_32\c>
That looks fine ... so, two questions:
1) Why can't double.pl access double.dll ?
2) Why can't I build double_test.exe by linking to double.lib ?

Cheers,
Rob

Replies are listed 'Best First'.
Re: [OT - MS Visual Studio] How to build a dll that Win32::API can access
by Anonymous Monk on May 24, 2008 at 12:05 UTC
      What is the error ($! $^E ...)?

      As I said in my original post, $^E contains "The specified procedure could not be found". I find that $! contains "Unknown error".

      Cheers,
      Rob
        Ah, so its able to access double.dll, it just can't find my_double
Re: [OT - MS Visual Studio] How to build a dll that Win32::API can access
by JMD-Rome (Initiate) on May 25, 2008 at 17:32 UTC
    Hi, Rob ! As for your 2nd question : cl /Gz double_test double.lib works fine. /Gz forces __stdcall which means : look for decorated names like _my_double@4 (while default __cdecl makes the linker look for decorated names like _my_double = exactly the LNK2019 error you get) See http://msdn.microsoft.com/en-us/library/x7kb4e2f.aspx for (C) decorated names. Regards, Jean-Marc
      As for your 2nd question : cl /Gz double_test double.lib

      Aaah ... I see. Thanks. (You meant "double_test.c", not "double_test".)

      As regards http://msdn.microsoft.com/en-us/library/x7kb4e2f.aspx, it says there that __cdecl is decorated with a leading underscore, yet dumpbin /exports reports that there is no leading underscore when I build with __cdecl (/Gd). On the other hand, what is written on that page regarding __fastcall (/Gr) and __stdcall (/Gz), is in complete agreement with what dumpbin /exports reports for dll's built with those calling conventions.

      I have just managed to build a dll that Win32::API can access ... but only if the function being accessed takes no arguments.

      Cheers,
      Rob