• Access to global variables in a DLL

    From miguiman@gmail.com@21:1/5 to All on Fri May 27 06:48:25 2016
    Hi,

    I've built a DLL with a few functions and global variables. Then I've used buildlib to create an import library for it.

    The .exp file is:

    CSC_FFSW.dll
    _CSC_FFSW_B _CSC_FFSW_B data
    _CSC_FFSW_DWork _CSC_FFSW_DWork data
    _CSC_FFSW_M _CSC_FFSW_M data
    _CSC_FFSW_U _CSC_FFSW_U data
    _CSC_FFSW_Y _CSC_FFSW_Y data
    _CSC_FFSW_initialize _CSC_FFSW_initialize
    _CSC_FFSW_step0 _CSC_FFSW_step0
    _CSC_FFSW_step1 _CSC_FFSW_step1


    When I import the DLL from a program, I can read the global variables (e.g. CSC_FFSW_U), but when I try to write them I get a Segment Violation exception.

    Instead of using an import library, I tried manually importing the symbols from the DLL using:

    dllHandle = LoadLibrary("CSC_FFSW.dll");
    myType* pCSC_FFSW_U = (myType*)GetProcAddress(dllHandle, "_CSC_FFSW_U");
    ...
    etc.


    With this approach I can write to the variables fine. However, this method is not so nice because it requires more manual, error prone work.

    Should it be possible to have read-write access to the variables in the import library created by buildlib? How should I specify this in the .exp file?

    Many thanks,
    Miguel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Antoine Leca@21:1/5 to miguiman@gmail.com on Mon May 30 14:24:05 2016
    On 27/05/2016 15:48, miguiman@gmail.com wrote:
    When I import the DLL from a program, I can read the global variables
    (e.g. CSC_FFSW_U), but when I try to write them I get a Segment
    Violation exception.

    How do you "write them"?
    How are they declared to the C compiler?

    Win32 DLL-shared variables are really pointers (much like functions are
    in C); when reading, things works smoothly because the compiler silently perform the indirection; but on writing, you need to perform explicit dereference. One way is to do it is to code explicitly
    *CSC_FFSW_U = 1;
    but for more than 20 years now, the solution uses to be to "decorate"
    the declaration of the variable with __declspec(dllimport); then the
    compiler will insert the required code.

    Of course, this requires a Win32-aware C compiler; lcc-win32 is such a
    thing; I am not sure the original lcc does.

    Antoine

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jacobnavia@21:1/5 to All on Mon May 30 19:56:25 2016
    Le 30/05/2016 à 19:11, miguiman@gmail.com a écrit :
    double k = CSC_FFSW_U.field; // this works
    CSC_FFSW_U.field = 2.0; // this causes a segment violation

    In the code that uses the dll declare the variables as

    __declspec(dllimport) int foo;

    In the dll declare the variables as dll export

    __declspec(dllexport)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From miguiman@gmail.com@21:1/5 to All on Mon May 30 10:11:12 2016
    Hi, and thanks for your answer.

    When I import the DLL from a program, I can read the global variables
    (e.g. CSC_FFSW_U), but when I try to write them I get a Segment
    Violation exception.

    How do you "write them"?
    How are they declared to the C compiler?

    I declare the variable in a header.h as:

    extern myType CSC_FFSW_U;

    In the DLL implementation, I define the actual variable:

    #include "header.h"
    myType CSC_FFSW_U;

    In the code that uses the DLL, I import the header and use the variable as a regular value, not a pointer.

    #include "header.h"

    double k = CSC_FFSW_U.field; // this works
    CSC_FFSW_U.field = 2.0; // this causes a segment violation

    With the alternative of GetProcAddress, I do use pointers:

    myType* pCSC_FFSW_U = (myType*)GetProcAddress(dllHandle, "_CSC_FFSW_U");
    double k = pCSC_FFSW_U->field; // this works
    pCSC_FFSW_U->field = 2.0; // this also works

    Win32 DLL-shared variables are really pointers (much like functions are
    in C); when reading, things works smoothly because the compiler silently perform the indirection; but on writing, you need to perform explicit dereference. One way is to do it is to code explicitly
    *CSC_FFSW_U = 1;

    Does this mean that the variable should be accessed as a pointer regardless of its declaration in header.h?

    but for more than 20 years now, the solution uses to be to "decorate"
    the declaration of the variable with __declspec(dllimport); then the
    compiler will insert the required code.

    Unfortunately I'm working with generated code (from Matlab) and I can't modify it to add decorations. That's why I took this complicated approach.

    Thanks a lot,
    Miguel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jacobnavia@21:1/5 to All on Tue May 31 11:26:37 2016
    Le 31/05/2016 à 10:54, miguiman@gmail.com a écrit :

    To sum up, the issue in my code comes indeed from not being able to put the dllimport/dllexport, but the old LCC version I'm using has some weird behaviour with dllimport and I think I won't be able to fix the problem that way. However, the newer
    version of LCC doesn't have this issue and should work fine.

    Thanks Antoine and Jacob for your help.


    If you experience any further problems please do not hesitate to contact me.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From miguiman@gmail.com@21:1/5 to All on Tue May 31 01:54:59 2016
    Indeed the missing dllimport and dllexport are the problem, but as I said I'm working with some generated code that I can't modify.

    I checked again with a simpler example and I saw that I was wrong about the read access: it doesn't crash, but it returns a wrong value.

    I'm forced to use an old version of LCC, the 2.4.1. In this version, dllimport seems to have some weird behaviour with variables (maybe because I didn't specify the dllexport).

    In main.c:

    extern double __declspec(dllimport) a;
    // a is initialized in the DLL with:
    // double a = 1.0;
    // Note that a is NOT declared with dllexport in the DLL

    void main(void)
    {
    double* q = NULL;
    HMODULE hdl;

    printf("a = %f \n", a); // prints 0.0
    printf("a as pointer = %p \n", a); // prints 00404138
    printf("*a = %f \n", *a); // prints 0.0
    *a = 2.0;
    printf("*a = %f (after assignment) \n", *a); // prints 2.0

    hdl = LoadLibrary("dll.dll");
    q = (double*)GetProcAddress(hdl, "_a");
    printf("q = %p \n", q); // prints 1000303C
    printf("*q = %f \n", *q); // prints 1.0

    *a = 3.0;
    printf("*a = %f \n", *a); // prints 3.0
    printf("*q = %f \n", *q); // prints 1.0
    }

    Note that the identifier a is accepted both as double and double*. In addition, it doesn't match the pointer obtained with GetProcAddress.

    This works fine in a newer version of LCC, the 3.8.

    extern double __declspec(dllimport) a;
    // a is initialized in the DLL with:
    // double a = 1.0;
    // Note that a is NOT declared with dllexport in the DLL

    void main(void)
    {
    double* q = NULL;
    HMODULE hdl;

    printf("a = %f \n", a); // prints 0.0
    //printf("*a = %f \n", *a); // error, not a pointer
    //*a = 2.0; // error, not a pointer
    //printf("*a = %f (after assignment) \n", *a);

    hdl = LoadLibrary("dll.dll");
    q = (double*)GetProcAddress(hdl, "_a");
    printf("q = %p \n", q); // prints 0x1000303c
    printf("*q = %f \n", *q); // prints 1.0

    a = 3.0;
    printf("a = %f \n", a); // prints 3.0
    printf("*q = %f \n", *q); // prints 3.0
    }

    If I try to remove the dllimport specification, the write access a=3.0 produces a segment violation.

    extern double a;
    // a is initialized in the DLL with:
    // double a = 1.0;
    // Note that a is NOT declared with dllexport in the DLL

    void main(void)
    {
    double* q = NULL;
    HMODULE hdl;

    printf("a = %f \n", a); // prints 0.0
    //printf("*a = %f \n", *a); // error, not a pointer
    //*a = 2.0; // error, not a pointer
    //printf("*a = %f (after assignment) \n", *a);

    hdl = LoadLibrary("dll.dll");
    q = (double*)GetProcAddress(hdl, "_a");
    printf("q = %p \n", q); // prints 0x1000303c
    printf("*q = %f \n", *q); // prints 1.0

    a = 3.0; // segment violation
    printf("a = %f \n", a);
    printf("*q = %f \n", *q);
    }

    To sum up, the issue in my code comes indeed from not being able to put the dllimport/dllexport, but the old LCC version I'm using has some weird behaviour with dllimport and I think I won't be able to fix the problem that way. However, the newer version
    of LCC doesn't have this issue and should work fine.

    Thanks Antoine and Jacob for your help.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)