locked
Developing Visual C++ DLLs for integration in C-written executables RRS feed

  • Pergunta

  • I was tasked with writing a DLL to be read by on runtime by an executable. I was given a C header file that acts as an interface for writing the DLL. I'm new to the world of DLL creation and I'm struggling to get the executable to recognize my DLL as having the entry points it expects. The executable tells me my module is invalid, but does not tell me why (and I lack the source to find out). I've used to tool to confirm my exports and that they match a reference DLL I was given (that works), but I'm guessing something about my function signatures signatures makes them incompatible. The README only mentions a requirement of having the three named functions exported. I've also made sure I'm building x64 as instructed in a README.

    >C Interface Header

    #include <stdint.h>
    #pragma pack(push, 1)
    
    struct Point
    {
    	int8_t id;
    	int32_t rank;
    	float x;
    	float y;
    };
    
    struct Rect
    {
    	float lx;
    	float ly;
    	float hx;
    	float hy;
    };
    #pragma pack(pop)
    
    struct SearchContext;
    
    typedef SearchContext* (__stdcall* T_create)(const Point* points_begin, const Point* points_end);
    
    typedef int32_t (__stdcall* T_search)(SearchContext* sc, const Rect rect, const int32_t count, Point* out_points);
    
    typedef SearchContext* (__stdcall* T_destroy)(SearchContext* sc);




    >My C++ Header

    #pragma once
    #include <cstdint>
    #pragma pack(push, 1)
    
    struct Point
    {
    	int8_t id;
    	int32_t rank;
    	float x;
    	float y;
    };
    
    struct Rect
    {
    	float lx;
    	float ly;
    	float hx;
    	float hy;
    };
    #pragma pack(pop)
    
    struct SearchContext
    {
    	float value;
    	float minCoverage, maxCoverage;
    	SearchContext* leftTree;
    	SearchContext* rightTree;
    	SearchContext* yTree;
    	Point* point;
    };
    
    extern "C" __declspec(dllexport) SearchContext* __cdecl create(const Point* points_begin, const Point* points_end);
    extern "C" __declspec(dllexport) int32_t __cdecl search(SearchContext * sc, const Rect rect, const int32_t count, Point * out_points);
    extern "C" __declspec(dllexport) SearchContext* __cdecl destroy(SearchContext * sc);




    Thanks in advance for any help!


    • Editado Andrewdt97 quinta-feira, 16 de julho de 2020 13:45
    terça-feira, 14 de julho de 2020 15:23

Todas as Respostas

  • Your exports of the three functions have each omitted the __stdcall calling convention.

    Another guess is that the header is using __declspec(dllexport) to export functions from the dll, but the code that is importing the functions needs to use __declspec(dllimport).

    • Editado RLWA32 terça-feira, 14 de julho de 2020 15:56
    terça-feira, 14 de julho de 2020 15:42
  • Your exports of the three functions have each omitted the __stdcall calling convention.

    Note that the OP did mention x64. As documented in the __stdcall documentation, when targeting ARM and x64 processors, __stdcall is accepted but ignored. For x64 there are only two calling conventions __cdecl which is the default x64 calling convention and __vectorcall which uses more registers than __cdecl.

    So while this isn't good practice, the lack of __stdcall isn't going to do much here.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    terça-feira, 14 de julho de 2020 20:18
  • How are you trying to access the DLL from C?

    When you are building for x64, __stdcall is ignored and silently changed to __cdecl, and there is no name mangling for __cdecl. So when you use GetProcAddress, or something that wraps this, you must use the names create, search and destroy. I assume you are using LoadLibrary and GetProcAddress because your C header has function pointer definitions.

    If you are unsure what names the compiler generated then you can use the dumpbin command line utility using the /exports option to see what the compiler generated.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Editado Darran Rowe quarta-feira, 15 de julho de 2020 00:29
    terça-feira, 14 de julho de 2020 20:23
  • It would also be helpful to run dumpbin /exports on the reference dll that the OP mentioned in order to establish the actual names that are in use for the exported functions.
    quarta-feira, 15 de julho de 2020 11:37
  • Note that the OP did mention x64.


    Are you sure?


    Sam Hobbs
    SimpleSamples.Info

    quarta-feira, 15 de julho de 2020 20:04
  • We can never be 100% sure of anything on these forums. But I am taking:

    I've also made sure I'm building x64 as instructed in a README.

    To mean that they are.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Editado Darran Rowe quinta-feira, 16 de julho de 2020 00:14
    quinta-feira, 16 de julho de 2020 00:03
  • We can never be 100% sure of anything on these forums.

    Yes, I agree.  That's why I pointed out the omission of __stdcall.  Just in case it turns out to be x86 after all. :)
    quinta-feira, 16 de julho de 2020 01:07
  • How are you trying to access the DLL from C?

    When you are building for x64, __stdcall is ignored and silently changed to __cdecl, and there is no name mangling for __cdecl. So when you use GetProcAddress, or something that wraps this, you must use the names create, search and destroy. I assume you are using LoadLibrary and GetProcAddress because your C header has function pointer definitions.

    If you are unsure what names the compiler generated then you can use the dumpbin command line utility using the /exports option to see what the compiler generated.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    I am indeed building x64. I'll upload a picture of my build configuration manager when I get the chance. I haven't tried dumpbin, but I assume it would do the same thing as the Nirsoft DLL export viewer I found recommended around the web. According to it, my DLL and the reference have the same export names.

    As far as how the DLL is read by the executable, I don't know, I don't have the source code for it. I don't even have confirmation that it is written in C, I just have assumed that because the header I was given to guide my work.

    I tried adding both __cdelc and __stdcall in my DLL header and still no luck. My DLL doesn't load, so I know it's a problem with the import and not with anything internal to the DLL.


    • Editado Andrewdt97 quinta-feira, 16 de julho de 2020 13:58
    quinta-feira, 16 de julho de 2020 13:45
  • Is anything other than the three functions exported from the reference dll?
    • Editado RLWA32 quinta-feira, 16 de julho de 2020 13:49
    quinta-feira, 16 de julho de 2020 13:49
  • No. Just the three.
    quinta-feira, 16 de julho de 2020 20:11
  • Does your dll have any dependencies that cannot be resolved at run-time that would cause LoadLibrary to fail?

    You can see any dependencies with dumpbin /dependents

    Also, when debugging do you see your dll being loaded and then unloaded?


    • Editado RLWA32 quinta-feira, 16 de julho de 2020 20:26
    quinta-feira, 16 de julho de 2020 20:24
  • As far as how the DLL is read by the executable, I don't know, I don't have the source code for it. I don't even have confirmation that it is written in C

    Do you have this executable on your machine or do you send your DLL to someone to test?

    If the former, can you debug the executable using the VS debugger or other?

    --pa

    quinta-feira, 16 de julho de 2020 23:46