Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Access to global variables in a DLL

1,432 views
Skip to first unread message

migu...@gmail.com

unread,
May 27, 2016, 9:48:26 AM5/27/16
to
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

Antoine Leca

unread,
May 30, 2016, 8:24:06 AM5/30/16
to
On 27/05/2016 15:48, migu...@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

migu...@gmail.com

unread,
May 30, 2016, 1:11:12 PM5/30/16
to
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

jacobnavia

unread,
May 30, 2016, 1:56:26 PM5/30/16
to
Le 30/05/2016 à 19:11, migu...@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)

migu...@gmail.com

unread,
May 31, 2016, 4:55:00 AM5/31/16
to
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.




jacobnavia

unread,
May 31, 2016, 5:26:38 AM5/31/16
to
Le 31/05/2016 à 10:54, migu...@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.

0 new messages