dll callback common blocks information

dll callback common blocks information

The problem is how to access information in a common block, by using a callback subroutine from a DLL. On Linux all is well, but on Windows, the values of the common block are 0. Consider the following calling sequence:

program aa
--> cycler (defined in aa.lib)
    --> eout (subroutine defined in bb.dll)
        --> get_info (call back into aa.lib)
           --> get_number(defined in aa.lib)

suborutine cycler has a common block with a variable "inum". Subroutine cycler calls a subroutine eout. eout is compiled/linked into bb.dll. Subroutine eout has a call to subroutine get_info and it calls subroutine get_number. The last two are compiled and linked into the same static library as cycler. Therefore we call it a callback, because eout makes a call back into the library. Subroutine get_number also has the same common block as cycler with variable inum. As it turns out, inum is zero at this level. But in cycler it still has a good value of 24.

The question is what do I need to do to make it work? I read about importing and exporting of common blocks, but it seems to me that nothing needs to be imported/exported as all is defined in the same static library. Any help is greatly appreciated.

15 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

You need a DLLIMPORT declaration for the COMMON in every procedure that references the COMMON, as the compiler has to generate different code to access it.

Retired 12/31/2016

Hi Steve, Thanks for responding. Yes, I used:


in every subroutine that is using the common block. The linker actually says that I am importing it:

aa.lib(get_number.obj) : warning LNK4049: locally defined symbol COMMUN imported

Yet still the value of inum is 0.

Try this. In the DLL, initialize one of the COMMON variables to 0 (use a DATA statement in a BLOCK DATA subprogram to do this.) I know that for multiprocess read-write shared COMMONs in DLLs you need to do this - maybe here too.

It isn't a case of whether it is linked in or not. You have to use DLLIMPORT in every routine that accesses the COMMON, or else it won't use the one from the DLL.

Retired 12/31/2016

So I put the common block in an include file and added:


And recompiled all the fortran subroutines. It still did not work.

Then I added a BLOCK DATA. The compiler did not like it:

eout.f(7): error #7371: An object in a COMMON block with DEC$ ATTRIBUTES DLLIMPORT cannot be initialized. [INUM]
data INUM /2/

When I removed the DLLIMPORT from the BLOCK DATA it did compile, but it still did not save the value for INUM properly.

The variable inum in the common block is not used in eout and eout is the only subroutine that is defined inside the DLL. All other subroutines are defined in aa.lib, which is a static library. So I do not understand why the DLL has to know the common block. The common block only has to be known in subroutine get_number which is not in the DLL but included in aa.lib.

On another note, does every DLLIMPORT have to be complimented by a DLLEXPORT? If so, where should I add it (since you suggested to use DLLIMPORT in all subroutines that use the common block)?

I think you misunderstood my suggestion, but I think I misunderstood your program description.

How exactly do you do this "callback"? I think that is the key. You may be ending up with two independent copies of the common block, one in the executable and one in the DLL. In order to avoid this, the common needs to be defined and DLLEXPORTed from the DLL (in a BLOCK DATA subprogram would be my recommendation), and DLLIMPORTed where it is used in the executable. That you use a .lib for both of these confuses things - try to keep that separate.

Can you attach a ZIP of a short example that illustrates your program structure with the common and the DLL? I am still unsure I understand what you're doing.

Retired 12/31/2016

Thank you for your suggestion to make a small example. I have attached it here. There is a readme.txt file with the 4 steps in which I was able to reproduce the problem. 

Second try to upload the file.


Downloadapplication/zip test.zip1.32 KB

Ok, I got it.  As I suspected, you are getting two copies of the COMMON. The one that gets updated is in the DLL, and if cycler was referenced from the DLL, it would work. But cycler isn't built into the DLL - it gets linked into the EXE and it calls eout, which is in the DLL. This means that cycler's inclusion of the COMMON is local to the executable, and not the same one as in the DLL.

You could solve this by:

  1. Remove the .def file from the link of the DLL

This should take care of it.  An alternative is to move CYCLER to the DLL and DLLEXPORT it - as long as all references to the common are inside the DLL, you don't need to worry about exporting the common.

Retired 12/31/2016

Hi Steve, I did exactly as you told me and I am afraid to tell it still did not work. The value of INUM in GET_NUMBER stays 0. Did it work when you tried the test problem?

CYCLER represents a source code with roughly 1000 subroutines and INUM is used all over the place. I would like to stay away from adding all 1000 subroutines into the DLL. 

Yes, it worked when I tested it.But I see I missed a step - sorry!


In your real application, you will want to DLLIMPORT the COMMON in the include file that is used in the executable, then, and DLLEXPORT it from a BLOCK DATA in the DLL.

Retired 12/31/2016

Steve, Thanks. Yes, now it works! I think I can use this, but I am still wondering about two things:

1) The variable INUM is set in the executable and used in the dll. I would expected the IMPORT and the EXPORT to be reversed. But alas.

2) In order to use the BLOCK DATA, I tried the following:

a) Use the original files from the zip file.

b) Added "!DEC$ ATTRIBUTES DLLIMPORT :: /COMMUN/" to the include file.

c) Add to the top of eou.f:

      include "uim.inc"
      DATA INUM /0/

The compiler did not like this at all, so I made a mistake. I am sorry, but I would like to ask you if you can spell out each change from the original zip file to make it work with BLOCK DATA?

You're not going to be able to put DLLIMPORT in the same include file that is used when you DLLEXPORT - this is why I was suggesting separate include files, as problematic as that can be. You don't need the DATA statement it turns out. Ordinarily I would suggest using conditional compilation and the _DLL preprocessor symbol to decide which to use, but the way you build doesn't make that practical. (_DLL is defined when you compile and /dll is specified.)

I have attached a zip of what I used.


Downloadapplication/zip u389100.zip1.58 KB
Retired 12/31/2016

Steve, Thanks for sending the attachment. I think I understrand now what to do. I was able to get it to work in the application as well. Even by keeping the def definition, which makes things a little easier too. One thing that did not work is that get_number is also called directly by cycler. But I figured that is a limitation on windows because of the import/export directives. So I copied get_number to get_number2 and used DLLIMPORT and then it was working again. So for any subroutine that is called under the eout I need to use DLLEXPORT and any subroutine that is called under cycler I need to use DLLIMPORT. So I got the work cut out for me the next couple of days.  :-)

Leave a Comment

Please sign in to add a comment. Not a member? Join today