locked
Can you share global variables between a DLL and a calling program? RRS feed

  • Question

  • Can you share global variables between a DLL and a calling program?  If so I would appreciate any tips.  I tried putting the global variables in the DLL but it crashed when the VB porgram tried to call it.
    Friday, January 19, 2007 5:29 PM

Answers

  • Yes, global variables can be shared between DLLs and calling programs.  In the DLL if you export a variable, e.g.

    extern "C" __declspec(dllexport) int mytestvar;

    and in the EXE, you import it, you should not have problems.  As for VB, I'm not sure how you are trying to access them.

     

    Friday, January 19, 2007 7:10 PM
  • In the C/C++ languages, global variables and external variables are implemented by the languages and therefore only are accessible by source code written using the languages.

    Just to ensure I was clear (I might not have been), a global variable exists at file scope. There is nothing more that needs to be done to make a variable global than it's location outside all functions. A global in a source file is unknown outside that source file. A variable however can be made external but an external variable cannot be accessed outside the linked file (exe or dll). Variables, including global and external variables, can be exported from a dll and then imported into an exe, however VB does not support import of variables, or at least I don't know how to do that and no one else has provided a way.

    Wednesday, January 24, 2007 6:35 PM

All replies

  • Yes, global variables can be shared between DLLs and calling programs.  In the DLL if you export a variable, e.g.

    extern "C" __declspec(dllexport) int mytestvar;

    and in the EXE, you import it, you should not have problems.  As for VB, I'm not sure how you are trying to access them.

     

    Friday, January 19, 2007 7:10 PM
  • I tried the method you described.  The compiler didn't like the "extern "C" __declspec(dllexport)" part.  I was referring to the use of variables that don't have to be passed in the dll function parameter list.  Is that what you are referring to also?
    Friday, January 19, 2007 7:51 PM
  • So you can see what I did, I posted the following code.  It compiles with those decorations commented out, but the computer generates an access error when the VB calling program tries to call the dll.

     

    // d.cpp : Defines the entry point for the DLL application.\par

    #include "stdafx.h"
    #include "stdio.h"
    #include"math.h"
    #include"string.h"
    #include"windows.h"
    #include"string.h"

    /*extern "C" __declspec(dllexport) */char *filepath2;
    /*extern "C" __declspec(dllexport) */double EF;

    void __stdcall PaperType(long &Ftn,/* char *filepath2, */char P[12])
    {
    int MultFilNum;
    char Ptemp;
    //char P;
    char P3;
    int n;
    int k;
    int x;
    int xflag;
    int m;
    FILE *fp1;
    char filename[256];
    strcpy(&filename[0], filepath2);
    strcat(&filename[0], "PaprType");
    strcat(&filename[0], ".Dat");
    //MessageBox(NULL,&filename[0],NULL,MB_YESNO);

    fp1 = fopen(&filename[0], "r");

    fseek(fp1, (Ftn + 1), 0);

    fread(&P[0], 11, 1, fp1);

    fclose(fp1);
    P[11] = '\0';
    //MessageBox(NULL,&P[0],NULL,MB_YESNO);

    k = 0;
    for (k=0;k<11;k++)
    {
    //MessageBox(NULL,&P[k],NULL,MB_YESNO);
     xflag = 1;
     x = int(P[k]);
     if ((x >= 48) && (x <= 57))
      xflag = 0;
     if ((x >= 65) && (x <= 90))
      xflag = 0;
     if ((x >= 97) && (x <= 122))
      xflag = 0;
     if (xflag == 1)
      P[k] = '\0';
    //MessageBox(NULL,&P[k],NULL,MB_YESNO);
    }

     

    //MessageBox(NULL,&P[0],NULL,MB_YESNO);
    P3 = P[0];
    //return P3;
    }

    int __stdcall GetPaperAbsorbency(long Ftn/*, char *filepath2*/)
    {
    //int PAtemp;
    //int PAtemp2;

    char P[12];
    int k;
    int PAtmp;
    //float PAtmp;
    int MultFilNum;
    //float *PA;
    //int PA;
    char PA[4];
    FILE *fp;
    char filename[256];

    PaperType(Ftn, /*filepath2, */&P[0]);

    //P2 = PaperType(Ftn, filepath2);
    //MessageBox(NULL,&P2,NULL,MB_YESNO);
    //MessageBox(NULL,P[0],NULL,MB_YESNO);
    strcpy(&filename[0], filepath2);

    strcat(&filename[0], &P[0]);
    strcat(&filename[0], ".mlt");
    //MessageBox(NULL,&filename,NULL,MB_YESNO);
    PA[3] = '\0';
    //PA[2] = "0";


    fp = fopen(&filename[0], "r+");
    fseek(fp, 2, 0);
    fread(&PA[0], 3, 1, fp);
    //MessageBox(NULL,&PA[0],NULL,MB_YESNO);
    fclose(fp);
    k = 0;
    for (k=0;k<4;k++)
    {
    //Atmp2 = "0";
     if (PA[k] ==' ')
      PA[k] = '\0';
    }
    //printf("%c", filename[0]);
    PAtmp = atoi(&PA[0]);
    return PAtmp;
    }

    extern "C" double __declspec(dllexport) __stdcall Cov2Key2(/*long*/__int32 Coverage, /*long*/__int32 Ftn, /*long*/__int32

    MultFunct/*,double EF, char **filepath2*/)
    {
    char **FilePath;
    int PAbstemp;
    float PAbstemp2;
    int PAbstemp3;
    int PAbstemp4;
    int KeyV;
    double tmp;
    int PAbs;
    //float PAbs;
    char PAbs2[3];
    //added the following 4 lines of code on friday dec 22 '06 to troubleshoot,
    //must eventually be taken out because it will affect the type on Ftn
    char Ftn1;
    Ftn1 = char(Ftn);
    //MessageBox(NULL, &Ftn1,NULL,MB_YESNO);
    //MessageBox(NULL,("filepath2 = %c",*filepath2),NULL,MB_YESNO);
    //PAbs = 1;
    PAbs = GetPaperAbsorbency(Ftn/*, *filepath2*/);
    tmp = double(Coverage) * (double(MultFunct)/100000);
    KeyV = (pow(tmp,EF) * (PAbs)+0.5);
    //printf("hello");
    return KeyV;
    }

     

    Friday, January 19, 2007 8:06 PM
  • No, actually I was thinking of something else (accessing variables in a DLL from a C++ EXE), taking out the extern "C" and placing the variable definitions in a .C file instead of .CPP would compile ok. 

    I'm not sure what the solution is for VB, so I'll leave this to someone else.

    Friday, January 19, 2007 9:30 PM
  • Perhaps people in the VB forums and newsgroups would be more familiar with this. I am not familiar with current versions of VB but previous versions don't have this feature or an equivalent.

    Obviously you can create a function in the DLL to get and put the value(s).

    Another possibility is to write a COM object (I am not sure of the terminology) which is a special version of a DLL. Then the object can have properties and functions.

    Saturday, January 20, 2007 7:20 PM
  • seems extern is not required for exporting a variable.

    extern "C" using to avoid name mangling of C++ functions and to get the exact syntax what we defined in the calling process

    E.g
    #ifdef WIN32DLL_EXPORTS
    #define WIN32DLL_API __declspec(dllexport)
    #else
    #define WIN32DLL_API __declspec(dllimport)
    #endif

    // This is an example of an exported variable
    WIN32DLL_API int nWin32DLL=0;

    Sunday, January 21, 2007 3:52 AM
  •  Sarath. wrote:
    seems extern is not required for exporting a variable.
    Correct. I was undecided whether to say something, but since it is not relevant, I decided not to. Your comment makes comparison of external and exported variables relevant.

    External variables and exported variables are totally different. Neither depends on the other or is influenced by either. External variables are part of the standard and have been since the first C standard, whereas exported variables are a Microsoft extension for Windows.

     Sarath. wrote:
    extern "C" using to avoid name mangling of C++ functions and to get the exact syntax what we defined in the calling process
    That is irrelevant without external and/or exported variables, but since they are irrelevant, so is extern "C". If however you know something we don't, then please provide us with the important part.

     Sarath. wrote:

    E.g
    #ifdef WIN32DLL_EXPORTS
    #define WIN32DLL_API __declspec(dllexport)
    #else
    #define WIN32DLL_API __declspec(dllimport)
    #endif

    // This is an example of an exported variable
    WIN32DLL_API int nWin32DLL=0;
    That is good, if it is possible for VB to use an exported variable. The main question is how can VB use an exported variable; if you can tell us that, then the rest, such as the details you show here, is easy.

    Sunday, January 21, 2007 4:22 AM
  • The short answer to your question is no.

    Might I make a suggestion here. I assume this is for your workplace where more than one dev is working on an application and you're trying to mix languages. If at all possible, code the whole thing in one or the other. The code you posted doesn't seem overly complex and could easily be ported to visual basic. However if you want to continue the DLL approach here's my thoughts.

    Instead of using global variables for file paths etc, use thread local storage. Windows has a set of functions beginning with "Tls*"  that manage storage specific to one thread. Your code doesn't look multithreaded to me, so therefore this would be, for all intents and purposes, a global storage space. Use your API text viewer in the start menu > visual basic tools folder, grab the Tls* functions and CopyMemory, and use them to retrieve the value you need in VB. (This is simply a parser for WIN32API.TXT, if you can find that file instead.) The idea is to pass data through the API instead of directly reading memory. This will also prevent undefined behavior if someone opens 2 copies of your program. That could be problematic with traditional global variables because "global" in a DLL means system-wide. Both instances of the VB program would use the same DLL, and the same global variable, and might not mix well. There are functions for synchronizing things shared between processes but that seems a bit much for your app. You may have to warn your users about that if you do succeed with this idea.

    Otherwise, I don't think its possible to import variables from a DLL in VB. What you can do however, is create a wrapper function (a la windows Get* and Set* functions) for your variable. E.g.

    char* GetFilepath2() {return Filepath2;}
    void SetFilepath2(char* fp) {Filepath2 = fp;}
    double GetEF() {return EF;}
    void SetEF(double ef_new) {EF = ef_new;}


    and in VB create/modify a module, at the top put:

    Public Declare Function GetFilepath2 Lib "yourdll" () As String
    Public Declare Function GetEF Lib "yourdll" () As Double
    Public Declare Sub SetFilepath2 Lib "yourdll" (ByVal newfp As String)
    Public Declare Sub SetEF Lib "yourdll" (ByVal newef As Double)

    So instead of using EF in code, use GetEF()
    and instead of EF = x, say SetEF(x)

    Sunday, January 21, 2007 6:49 AM
  •  DFPercush wrote:
    Instead of using global variables for file paths etc, use thread local storage. Windows has a set of functions beginning with "Tls*"  that manage storage specific to one thread. Your code doesn't look multithreaded to me, so therefore this would be, for all intents and purposes, a global storage space. Use your API text viewer in the start menu > visual basic tools folder, grab the Tls* functions and CopyMemory, and use them to retrieve the value you need in VB. (This is simply a parser for WIN32API.TXT, if you can find that file instead.) The idea is to pass data through the API instead of directly reading memory.

    Are you sure that that is a practical use of Thread Local Storage? I admit I am not familiar with tls, but it seems to be intended for use within a DLL, not for communicating between a DLL and the application. It seems to me that it would be easier for the application to call a function in the DLL to exchange data directly instead of using tls.

     DFPercush wrote:
    This will also prevent undefined behavior if someone opens 2 copies of your program. That could be problematic with traditional global variables because "global" in a DLL means system-wide.
    Definitely not. Memory for each process is totally separate and (unless a shared data segment is used explicitly) each instance (use by a process/application) of a DLL has totally separate data.

     DFPercush wrote:
    There are functions for synchronizing things shared between processes but that seems a bit much for your app. You may have to warn your users about that if you do succeed with this idea.
    Dangerous! If there is a need for synchronization, synchronization is needed, no matter how simple the requirement is.

     DFPercush wrote:
    Otherwise, I don't think its possible to import variables from a DLL in VB. What you can do however, is create a wrapper function (a la windows Get* and Set* functions) for your variable. E.g.

    char* GetFilepath2() {return Filepath2;}
    void SetFilepath2(char* fp) {Filepath2 = fp;}
    double GetEF() {return EF;}
    void SetEF(double ef_new) {EF = ef_new;}


    and in VB create/modify a module, at the top put:

    Public Declare Function GetFilepath2 Lib "yourdll" () As String
    Public Declare Function GetEF Lib "yourdll" () As Double
    Public Declare Sub SetFilepath2 Lib "yourdll" (ByVal newfp As String)
    Public Declare Sub SetEF Lib "yourdll" (ByVal newef As Double)

    So instead of using EF in code, use GetEF()
    and instead of EF = x, say SetEF(x)

    Which is what I said. I am sorry if I was not clear, but that is what I meant.

     

    Sunday, January 21, 2007 8:06 AM
  • A lot of what you guys wrote goes over my head, but from what I can tell, the concensus seems to be that there is no practical way to do this, without resorting to a method that doesn't really use global variables as we know them.  Is that correct?  I can make it work by passing the variables to the functions via the parameter list.  I was trying to make it as transparent to the user as possible, but perhaps it is not necessary.
    Monday, January 22, 2007 9:32 PM
  • It depends on what you know whether it is possible to "use global variables as we know them". I don't know a way to use global variables between a DLL and an application so it makes sense to me that it is not possible. A global variable is a variable that is shared among source files compiled separately but linked together. A DLL and an application are linked as separate files as output of the linker.

    A critical distinction is that a global variable is global only within a DLL or EXE file. It can be confusing if you are not familiar with the purpose of the linker.

    Tuesday, January 23, 2007 1:01 AM
  • Not entirely accurate - a global variable can be per process, not necessarily per module, i.e. it can be shared between a DLL and EXE (both built in C++) simply using the __declspec(dllexport) and __declspec(dllimport) keywords (or by using a DEF file).  Create a DLL, and export a variable from it, and you can access it from any other DLL within the process, or the EXE that links to the DLL.
    Tuesday, January 23, 2007 3:58 PM
  •  Ted. wrote:
    Not entirely accurate - a global variable can be per process, not necessarily per module, i.e. it can be shared between a DLL and EXE (both built in C++) simply using the __declspec(dllexport) and __declspec(dllimport) keywords (or by using a DEF file).  Create a DLL, and export a variable from it, and you can access it from any other DLL within the process, or the EXE that links to the DLL.
    It depends on terminology.

    The term global is used to refer to variables made global using "extern". Actually, even that is not accurate. A global variable actually is a variable that has file scope; look up extern in the documentation if you are not familiar with that. I was interpreting the term global in the original question as if it were an external variable, but global is the wrong term. An external variable is used in more than one source file that are linked together.

    An exported variable is not called global; it is called exported. An exported variable should not be called global, since the terminology then becomes confusing, as in this discussion.

    Tuesday, January 23, 2007 5:24 PM
  • is there a way to share the variables between the VB program and the VC DLL using external variables instead of global?
    Wednesday, January 24, 2007 5:34 PM
  • In the C/C++ languages, global variables and external variables are implemented by the languages and therefore only are accessible by source code written using the languages.

    Just to ensure I was clear (I might not have been), a global variable exists at file scope. There is nothing more that needs to be done to make a variable global than it's location outside all functions. A global in a source file is unknown outside that source file. A variable however can be made external but an external variable cannot be accessed outside the linked file (exe or dll). Variables, including global and external variables, can be exported from a dll and then imported into an exe, however VB does not support import of variables, or at least I don't know how to do that and no one else has provided a way.

    Wednesday, January 24, 2007 6:35 PM
  • Thanks for the info
    Monday, January 29, 2007 9:01 PM