locked
Sharing data with a DLL RRS feed

  • Question

  • My C++ program loads a dll.  The client has some data structures such as

        extern "C" struct lens1s {
            double CVD[JC][NS+1];
            double CCD[JC][NS+1];
            double THD[JC][NS+1];
            double RINDEX[JC][NS+1][NBCOL];
            double ANUM[JC][NS+1][30];
            double WAVL[JC][NBCOL];
            double WGTD[JC][NBCOL];
            double CATND[JC][NS+1];
            double CATVD[JC][NS+1];
            int ICORD[JC][NBCOL];
            int JUCODE[JC];
            int NSPACE[JC][NS+1];
        } LENS1;

    I want the dll program to be able to use these data when it runs.  How do I get the data across?

    Wednesday, December 21, 2016 8:16 PM

Answers

  • I'll do something with the pointer once I know it showed up.  Here's how I'm exporting the function now:

    lens1s* pL1 = NULL;
    extern __declspec( dllexport) void InitStruct( lens1s* sp )
    {    
        pL1 = sp;
    }

    I note that I did not export anything related to DoUserFunc, and yet it linked just fine.  That's why I'm confused.  Rather than tell me I'm not exporting properly, it would be very nice to show the right way.

    I have shown you the right way but you refuse to use the examples provided.  Did it occur to you that you neglected to specify  extern "C" in order to get C linkage for the exported InitStruct function?  The linker is likely exporting a decorated C++ name.

    • Marked as answer by DonDilworth Thursday, December 22, 2016 7:06 PM
    Thursday, December 22, 2016 6:57 PM

All replies

  • On 12/21/2016 3:16 PM, DonDilworth wrote:

    I want the dll program to be able to use these data when it runs.  How do I get the data across?

    You pass it as a parameter to some function the DLL exports.

    Wednesday, December 21, 2016 8:47 PM
  • For example with  #pragma data_seg or with exported functions or memory mapped files , etc...


    • Edited by Castorix31 Wednesday, December 21, 2016 8:50 PM
    Wednesday, December 21, 2016 8:48 PM
  • I appreciate the prompt replies, but I am really ignorant about too many things.  Can you give me an example of passing or exporting this structure?  I've tried exporting and importing, using hints from the Internet, but probably did it all wrong.  It compiles, but the data never show up.
    Wednesday, December 21, 2016 8:54 PM
  • Don,

    Create a new Win32 project for a dll.  Select the option to export symbols.  After the wizard has created the project look at how it structured the .h and .cpp files to export code and data.

    Wednesday, December 21, 2016 9:46 PM
  • Hi DonDilworth,

    thanks for posting here.

    >>I want the dll program to be able to use these data when it runs.  How do I get the data across?

    If the DLL is your own created project, you could add reference from the application to the DLL project. Then you could include the library header file and use the Functions in your application. Or use LoadLibrary (or AfxLoadLibrary) to explicitly link to a DLL. If the function succeeds, it maps the specified DLL into the address space of the calling process and returns a handle to the DLL that can be used with other functions in explicit linking—for example, GetProcAddress and FreeLibrary. Then pass this struct as a parameter to this function like Igor suggested.

    For more information and sample codes, please refer to this document below.

    https://msdn.microsoft.com/en-us/library/ms235636.aspx?f=255&MSPPError=-2147217396

    Hope this could be help of you.

    Best Regards,
    Sera Yu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, December 22, 2016 7:11 AM
  • I put together a simple example.  The following MFCDLLexport.h and MFCDLLexport.cpp files can be added to an MFC  DLL project.  They contain data that will be exported from the DLL along with the functions.  In the DLL project you should define the preprocessor directive MFCDLL_EXPORT so that MFCDLL_API resolves to __declspec(dllexport).  When you include the header file in an MFC application  MFCDLL_API will resolve to __declspec(dllimport).

    Also included is a function that would be used from the MFC application to use the DLL's exported functions and data.  I have included two versions, one that uses static linkage and one that uses LoadLibrary and GetProcAddress. In both cases the MFCDLLexport.h header is included.

    MFCDLLexport.h -

    #pragma once
    
    #ifdef MFCDLL_EXPORT
    #define MFCDLL_API __declspec(dllexport)
    #else
    #define MFCDLL_API __declspec(dllimport)
    #endif
    
    
    struct DllStruct {
    	int i;
    	double d;
    	wchar_t s[MAX_PATH];
    };
    
    extern "C" MFCDLL_API DllStruct mystruct;
    
    extern "C" MFCDLL_API void GetData(DllStruct *pData);
    
    extern "C" MFCDLL_API void PutData(const DllStruct newData);
    
    extern "C" MFCDLL_API void ShowDataFromDLL();

    MFCDllexport.cpp -

    #include "stdafx.h"
    #include "MFCDllexport.h"
    
    DllStruct mystruct = { 1, 2.2, L"Exported from a Dll" };
    
    DllStruct notExportedStruct = { 100, 7.7, L"This struct was not exported" };
    
    MFCDLL_API void GetData(DllStruct *pData)
    {
    	pData->i = notExportedStruct.i;
    	pData->d = notExportedStruct.d;
    	wcscpy_s(pData->s, MAX_PATH, notExportedStruct.s);
    }
    
    MFCDLL_API void PutData(const DllStruct newData)
    {
    	notExportedStruct.i = newData.i;
    	notExportedStruct.d = newData.d;
    	wcscpy_s(notExportedStruct.s, MAX_PATH, newData.s);
    }
    
    MFCDLL_API void ShowDataFromDLL()
    {
    	AFX_MANAGE_STATE(AfxGetStaticModuleState());
    	CString strMsg;
    
    	strMsg.Format(L"DLL i is %d\nDLL d is %f\nDLL s is \'%s\'", notExportedStruct.i, notExportedStruct.d, notExportedStruct.s);
    	AfxMessageBox(strMsg);
    }

    Call Dll - Statically linked

    void CMainFrame::OnButton()
    {
    	DllStruct data;
    	CString strExported;
    
    	// Directly access exported data from DLL
    	strExported.Format(L"Exported i is %d\nExported d is %f\nExported s is \'%s\'", mystruct.i, mystruct.d, mystruct.s);
    	AfxMessageBox(strExported);
    
    	ShowDataFromDLL();
    
    	//Retrieve data from unexported struct
    	GetData(&data);
    
    	data.i += 5;
    	data.d *= 2;
    	wcscpy_s(data.s, L"New Txt Value");
    
    	//Write new data to unexported struct
    	PutData(data);
    
    	ShowDataFromDLL();
    }

    Call Dll - Dynamically linked

    typedef void(*DLLFUNC)(void);
    typedef void(*DLLGET)(DllStruct*);
    typedef void(*DLLPUT)(DllStruct);
    
    
    
    void CMainFrame::OnButton()
    {
    	DllStruct data, *pExportedData;
    	DLLFUNC pfnShowData;
    	DLLGET pfnGetData;
    	DLLPUT pfnPutData;
    
    	CString strExported;
    
    	HMODULE hMod = LoadLibrary(L"MFCDll.dll");
    
    	pExportedData = (DllStruct*) GetProcAddress(hMod, "mystruct");
    	pfnShowData = (DLLFUNC)GetProcAddress(hMod, "ShowDataFromDLL");
    	pfnGetData = (DLLGET)GetProcAddress(hMod, "GetData");
    	pfnPutData = (DLLPUT)GetProcAddress(hMod, "PutData");
    
    	// Directly access exported data from DLL
    	strExported.Format(L"Exported i is %d\nExported d is %f\nExported s is \'%s\'", pExportedData->i, pExportedData->d, pExportedData->s);
    	AfxMessageBox(strExported);
    
    	pfnShowData();
    
    	//Retrieve data from unexported struct
    	pfnGetData(&data);
    
    	data.i += 5;
    	data.d *= 2;
    	wcscpy_s(data.s, L"New Txt Value");
    
    	//Write new data to unexported struct
    	pfnPutData(data);
    
    	pfnShowData();
    
    	FreeLibrary(hMod);
    }



    • Edited by RLWA32 Thursday, December 22, 2016 12:28 PM
    Thursday, December 22, 2016 12:27 PM
  • These suggestions all describe how to make the client program share data created by the dll.  I want to go the other direction.  In my client program I define this:

    struct lens1s {
        double CVD[JC][NS+1];
        double CCD[JC][NS+1];
        double THD[JC][NS+1];
        double RINDEX[JC][NS+1][NBCOL];
        double ANUM[JC][NS+1][30];
        double WAVL[JC][NBCOL];
        double WGTD[JC][NBCOL];
        double CATND[JC][NS+1];
        double CATVD[JC][NS+1];
        int ICORD[JC][NBCOL];
        int JUCODE[JC];
        int NSPACE[JC][NS+1];
        } ;
    extern "C" __declspec( dllexport ) struct lens1s LENS1;

    It compiles and runs.

    In the dll I tried this:

    struct lens1s {
            double CVD[JC][NS+1];
            double CCD[JC][NS+1];
            double THD[JC][NS+1];
            double RINDEX[JC][NS+1][NBCOL];
            double ANUM[JC][NS+1][30];
            double WAVL[JC][NBCOL];
            double WGTD[JC][NBCOL];
            double CATND[JC][NS+1];
            double CATVD[JC][NS+1];
            int ICORD[JC][NBCOL];
            int JUCODE[JC];
            int NSPACE[JC][NS+1];
        };
    extern "C" __declspec(dllimport) struct lens1s LENS1;

    It won't link:

    USERDLL.obj : error LNK2001: unresolved external symbol __imp__LENS1

    I must be missing something simple.

    Thursday, December 22, 2016 3:35 PM
  • Look at the PutData function in the example code.  It copies a struct from the application to the DLL

    Or you could pass the address of the data in the application to the DLL so that the DLL could reference the data through the passed pointer.

    • Edited by RLWA32 Thursday, December 22, 2016 3:59 PM
    Thursday, December 22, 2016 3:39 PM
  • It looks to me like your example exports local data and the dll puts it into a structure that is not exported.  I want to export the structure itself and all of the data therein.  Did I miss something?
    Thursday, December 22, 2016 4:00 PM
  • What you are trying to do creates circular dependencies between the exe and the dll.

    Instead of trying to export data from the exe you can easily make it available to the dll by passing a pointer as I suggested.

    Building on the example, in the DLL

    Add to MFCDllexport.h

    extern "C" MFCDLL_API void InitStruct(DllStruct *pStruct);
    
    extern "C" MFCDLL_API void ShowDataFromEXE();

    Add to MFCDllexport.cpp

    DllStruct *pExeData = NULL;
    
    MFCDLL_API void InitStruct(DllStruct *pStruct)
    {
    	pExeData = pStruct;
    }
    
    
    MFCDLL_API void ShowDataFromEXE()
    {
    	AFX_MANAGE_STATE(AfxGetStaticModuleState());
    	CString strMsg;
    
    	strMsg.Format(L"DLL i is %d\nDLL d is %f\nDLL s is \'%s\'", pExeData->i, pExeData->d, pExeData->s);
    	AfxMessageBox(strMsg);
    }

    Add to application

    DllStruct exeData = { 42, 42.42, L"Data Struct in Application" };
    
    InitStruct(&exeData); // pass pointer to DLL
    
    ShowDataFromEXE();  //Access App data from DLL


    • Edited by RLWA32 Thursday, December 22, 2016 4:18 PM
    Thursday, December 22, 2016 4:17 PM
  • Well, this is close.  It looks like the dll gets its own private copy of the data in the structure.  I would rather it share the address with the client so it can read and change anything.  When it returns, the data will already be there.  Is that possible?
    Thursday, December 22, 2016 4:43 PM
  • Well, this is close.  It looks like the dll gets its own private copy of the data in the structure.  I would rather it share the address with the client so it can read and change anything.  When it returns, the data will already be there.  Is that possible?

    In the above example the DLL is sharing the data with the application through the pointer. It is not a "private copy".  The DLL can read and write through the pointer.  Try it!
    Thursday, December 22, 2016 4:44 PM
  • It should work, but I don't know the syntax.  Here's my client stuff;

    extern HMODULE dllMod;
    typedef void (*DLLFUNC) ( void );
    typedef void (*STRFUNC) (lens1s *LENS1 );

    ...

        if ( dllMod != NULL ) {
            STRFUNC pfnInitStruct = (STRFUNC) GetProcAddress( dllMod, "InitStruct");
            DLLFUNC pfnDoUserFunc = (DLLFUNC) GetProcAddress( dllMod, "DoUserFunc");

            LENS1.CVD[0][1] = 1.2345;

            if ( pfnInitStruct != NULL ) {
                pfnInitStruct( &LENS1 );
            }


            if ( pfnDoUserFunc != NULL ) {
                pfnDoUserFunc( );
            }
        }

    And here's what's in the DLL:

    void DoUserFunc(void)
    {
        theApp.UserProgram();
    }

    lens1s* pL1 = NULL;
    void InitStruct( lens1s* sp )
    {
        pL1 = sp;
    }

    Everything compiles, and I can get into DoUserFunc(), but pfnInitStruct always comes back NULL.  Can you spot the error?

    Thursday, December 22, 2016 5:39 PM
  • The very first example I provided called a member function of a class in the DLL.  We've moved past that.

    Please don't combine examples.  Try the last example code exactly as I provided it.



    • Edited by RLWA32 Thursday, December 22, 2016 5:55 PM
    Thursday, December 22, 2016 5:54 PM
  • Well, I have not moved past it.  I can call pfnDoUserFunc just fine.  But I don't get a link to pfnInitStruct that works.  Working your example will not help, since you did not duplicate my situation.  Can you spot an error in my code?
    Thursday, December 22, 2016 6:25 PM
  • Well, I have not moved past it.  I can call pfnDoUserFunc just fine.  But I don't get a link to pfnInitStruct that works.  Working your example will not help, since you did not duplicate my situation.  Can you spot an error in my code?

    If you understood the concepts from working the examples I provided you would be able to apply them to your own code.

    If GetProcAddress fails to return a valid pointer to pfnInitSruct its likely because you are not properly exporting the InitStruct function from the DLL.

    Furthermore, even if you succeed in passing a valid pointer from the application to the DLL and it is received in the pL1 variable I don't see any code that does anything with the pL1 pointer thereafter.

    Thursday, December 22, 2016 6:39 PM
  • I'll do something with the pointer once I know it showed up.  Here's how I'm exporting the function now:

    lens1s* pL1 = NULL;
    extern __declspec( dllexport) void InitStruct( lens1s* sp )
    {    
        pL1 = sp;
    }

    I note that I did not export anything related to DoUserFunc, and yet it linked just fine.  That's why I'm confused.  Rather than tell me I'm not exporting properly, it would be very nice to show the right way.

    Thursday, December 22, 2016 6:48 PM
  • I'll do something with the pointer once I know it showed up.  Here's how I'm exporting the function now:

    lens1s* pL1 = NULL;
    extern __declspec( dllexport) void InitStruct( lens1s* sp )
    {    
        pL1 = sp;
    }

    I note that I did not export anything related to DoUserFunc, and yet it linked just fine.  That's why I'm confused.  Rather than tell me I'm not exporting properly, it would be very nice to show the right way.

    I have shown you the right way but you refuse to use the examples provided.  Did it occur to you that you neglected to specify  extern "C" in order to get C linkage for the exported InitStruct function?  The linker is likely exporting a decorated C++ name.

    • Marked as answer by DonDilworth Thursday, December 22, 2016 7:06 PM
    Thursday, December 22, 2016 6:57 PM
  • I got it working, thank you.  You have been very helpful.

    Thursday, December 22, 2016 7:06 PM
  • You're welcome. :)
    Thursday, December 22, 2016 7:32 PM