[comp.windows.ms.programmer] Passing data to a DLL; strange problem!

lwallace@javelin.sim.es.com (Raptor) (04/23/91)

(One wonders if I'll ever find a Windows technique that works the
first time I try it...)

I've recently broken my application up into a DLL and a main program
module.  One of the functions I've exported to the DLL needs to
enumerate top-level windows, so I want to pass it my application's
top-level window handle to feed FindWindow().

First, if you've got a better technique to do this, I'm interested in
hearing it.  But my problem remains.

I've written a tiny function to pass the handle to a static variable
in the DLL.  This is what's in the DLL:

HWND ParentHandle;
...
void FAR PASCAL TxferParentHandle(HWND hwnd)
{
ParentHandle = hwnd;
}

This is how I call it from my main module:

HWND ParentHandle;
...
WinMain(...)
{
...
TxferParentHandle(hwnd);
}

The DLL's copy of ParentHandle remains 0.  hwnd is set as expected.
It was baffling to execute the assignment statement in CodeView and
see that it doesn't work!

I have discovered, through CodeView, that the address of ParentHandle
in the DLL is in a different segment from that shown in DS and SS
(which are equal):

(for example)
&ParentHandle = 0c15:2794
DS = 0bea
SS = 0bea

This is in my DLL, just after TxferParentHandle() is called.  The
assembly code uses the correct offset (2794 in this case).  It's just
going to a different segment, for some reason.

Both modules are compiled (and linked) with the small model.

Has anyone encountered this?  Any suggestions?
-- 
            Lynn Wallace           |           I do not represent E&S.
Evans and Sutherland Computer Corp.|   Internet: lwallace@javelin.sim.es.com
      Salt Lake City, UT 84108     |           Compu$erve:  70242,101
	      Revenge is a dish best not served at all.

rybicki@parc.xerox.com (Adam Rybicki) (04/23/91)

In article <1991Apr22.173022.8930@javelin.sim.es.com> lwallace@javelin.sim.es.com (Raptor) writes:
>(One wonders if I'll ever find a Windows technique that works the
>first time I try it...)
>
>I've recently broken my application up into a DLL and a main program
>module.  One of the functions I've exported to the DLL needs to
>enumerate top-level windows, so I want to pass it my application's
>top-level window handle to feed FindWindow().
[...]


>HWND ParentHandle;
>...
>void FAR PASCAL TxferParentHandle(HWND hwnd)
>{
>ParentHandle = hwnd;
>}
>
>This is how I call it from my main module:
>
>HWND ParentHandle;
>...
>WinMain(...)
>{
>...
>TxferParentHandle(hwnd);
>}
>
>
>
>The DLL's copy of ParentHandle remains 0.  hwnd is set as expected.
>It was baffling to execute the assignment statement in CodeView and
>see that it doesn't work!
>
>I have discovered, through CodeView, that the address of ParentHandle
>in the DLL is in a different segment from that shown in DS and SS
>(which are equal):
>
[...]
>Has anyone encountered this?  Any suggestions?
>-- 

Yes, I have...  There is no problem with your code.  You have two
variables with the same name--ParentHandle.  CodeView gets confused
and displays the contents of the application's ParentHandle, not the
DLL's.  Try using a different variable name.


>            Lynn Wallace           |           I do not represent E&S.
>Evans and Sutherland Computer Corp.|   Internet: lwallace@javelin.sim.es.com
>      Salt Lake City, UT 84108     |           Compu$erve:  70242,101
>	      Revenge is a dish best not served at all.

					----- Adam Rybicki -----

lwallace@javelin.sim.es.com (Raptor) (04/23/91)

rybicki@parc.xerox.com (Adam Rybicki) writes:
>Yes, I have...  There is no problem with your code.  You have two
>variables with the same name--ParentHandle.  CodeView gets confused
>and displays the contents of the application's ParentHandle, not the
>DLL's.  Try using a different variable name.

I used to have them named identically.  But I changed that.  I'll double-
check to make sure I don't have another ParentHandle floating around, but
I doubt that's the problem.  Thanks anyway.

I'm going to go with dynamic allocation, I think.
-- 
            Lynn Wallace           |           I do not represent E&S.
Evans and Sutherland Computer Corp.|   Internet: lwallace@javelin.sim.es.com
      Salt Lake City, UT 84108     |           Compu$erve:  70242,101
	      Revenge is a dish best not served at all.

press@venice.SEDD.TRW.COM (Barry Press) (04/25/91)

In article <1991Apr23.152726.18318@javelin.sim.es.com> lwallace@javelin.sim.es.com (Raptor) writes:
>rybicki@parc.xerox.com (Adam Rybicki) writes:
>>Yes, I have...  There is no problem with your code.  You have two
>>variables with the same name--ParentHandle.  CodeView gets confused
>
>I used to have them named identically.  But I changed that.  I'll double-

When you go checking, consider that there may be no references in the source
code at all any more but the problem may still persist.  The reason would
be that, if you had the global declared in a header file, its existence
may have been compiled into a whole bunch of obj files.

For instance,

int foo;

in a project-wide header will put that variable into each and every object
compiled with it, and until you recompile all the files, it simply
won't go away.

This, at least, is true for MSC.  C mavens may want to flame.  Your
mileage may vary.
-- 
Barry Press                                 Internet: press@venice.sedd.trw.com

risto@tuura.UUCP (Risto Lankinen) (04/25/91)

lwallace@javelin.sim.es.com (Raptor) writes:

> ... so I want to pass it [a function in a DLL] my application's
>top-level window handle to feed FindWindow().

>First, if you've got a better technique to do this, I'm interested in
>hearing it.

Hi!

You can import the data *itself* without *calling* the DLL at all:

*** in DLL.C ***
// as static data, ie. before any functions:
HWND ParentHandle;

*** in DLL.DEF ***
DATA     PRELOAD NONDISCARDABLE ...

EXPORTS  ...
         PARENTHANDLE NODATA
         ...

*** in EXE.H ***
extern HWND FAR ParentHandle;

*** in EXE.C ***
...
ParentHandle = hWnd;
...
hWhatWasIt = ParentHandle;
...

*** in EXE.DEF ***
IMPORTS  DLL.PARENTHANDLE

******

A few words of explanation:

At the time Windows loads your DLL (or your application, in case there's
already an instance of your DLL loaded) it patches all references to the
imported objects in your application, to point to their true locations in
memory.  This patching has two stages:

 - All offsets are copied from the DLL's table of exported objects (which
   you can study from a DLL with the EXEHDR.EXE).
 - All segment addresses are copied from Windows' internal tables, which
   keep track of which selector has been allocated for any given segment
   of a module.

(In case Windows later moves or discards a segment, objects in which have
'active' exports, then only the latter stage will be rerun).

In real mode this is a bit different, because the export is first made
a procedure call thunk for.  Fortunately, this can be prevented by using
the NODATA with the exported data object (we sort of pretend, that it is
a function, which will not need the Dseg in AX, and therefore no thunk)
after which the SEG:PTR used to patch external references truly point to
the object itself.  The thunk is also used to reload any discarded code,
which is why the segment that contains the object must be NONDISCARDABLE .

When we refer to the data object, the only thing we need to provide for
the Windows' loader is a place, where it can patch its segment selector.
This is done with 'extern <typeofdata> FAR <nameofdata>;', upon which
the compiler places a word in the CONST segment, and a message to linker
to place its address into IMPORT table (also seen with EXEHDR.EXE using
switch '/v').  Subsequent references to the object each have preceding
'mov es,WORD PTR CONST:<segofdata>' and use it via ES:BX (normally).

For an additional point, if the data is referenced in both sides of, say,
SendMessage() or GlobalAlloc(), it surely is safest to set it 'volatile'
because the optimizer of the compiler may make assumptions either of the
actual value (which might have been changed by another process handling
the SendMessage() et al.) or its address (which might have been changed
because Windows moved the segment during GlobalAlloc() et al.).

This is, btw. closely related to how the __AHINCR, __AHSHIFT and other
non-function data have been exported from Kernel.  Haven't seen it, but
I guess that somewhere in KERNEL.ASM there,s ...

   PUBLIC __AHINCR,__AHSHIFT

   __AHINCR = <absvalue>
   __AHSHIFT = <absvalue>

They're probably exported in KERNEL.DEF, and referred to from an other
(assembly language) program as EXTRN, which is sufficiently to make the
Windows' loader put the actual values 08h and 03h wherever programmer
of a C program accesses an array declared 'huge' (in this case).  But
because they're not actual data, but absolute values instead, it seems
that the LINK 5.10 reserves the segment #254 for them.

Terveisin: Risto Lankinen

Disclaimer:  The author of this article assures, that best possible
care has been taken to prevent errors and provide accurate facts.
However, the reader alone, of this article is responsible for any
possible problems, losses or damages arising from actually making
use of the information contained therein.
-- 
Risto Lankinen / product specialist ***************************************
Nokia Data Systems, Technology Dept *  2                              2   *
THIS SPACE INTENTIONALLY LEFT BLANK * 2 -1 is PRIME!  Now working on 2 +1 *
replies: risto@yj.data.nokia.fi     ***************************************

kentfo@polari.UUCP (Kent Forschmiedt) (04/26/91)

In article <1991Apr22.173022.8930@javelin.sim.es.com> lwallace@javelin.sim.es.com (Raptor) writes:

>I have discovered, through CodeView, that the address of ParentHandle
>in the DLL is in a different segment from that shown in DS and SS
>(which are equal):

ALARM BELL!!  DS is not equal to SS in a DLL!

>
>(for example)
>&ParentHandle = 0c15:2794
>DS = 0bea
>SS = 0bea
>
>Both modules are compiled (and linked) with the small model.

Read chapter 20 of the SDK "Guide to Programming" 3 or 4 times...
DLL source files must be compiled with -Aw to tell the compiler
that DS != SS.

-- 
Kent Forschmiedt ... kentfo@polari ... uw-beaver!sumax!polari!kentfo