
The dllhello example that ships with OWL in BC 2.0 and 3.0
is a good demonstration of creating the required TModule object
an OWL Dll needs, and of using an Object Window alias.  It works as a good
model for many Dll's that use OWL, but falls short in a couple of specific
situations.

One of these situations occurs when the Dll acts as a server for several
different EXE's.  A second is when the window, that is being aliased,
persists after the Dll has been unloaded.

The first situation refers to a case where two or more EXE's link to
the same Dll and will be running simultaneously.  The traditional dllhello
example poses a problem for this scenario because of one fact about
Dll's, they do not own the memory which they allocate.  That is, if
a Dll calls GlobalAlloc, then that memory is considered to be owned
by the EXE task current at that time.  When that EXE is
terminated, the memory it used is freed; any subsequent references
to the freed memory will cause a general protection fault (GP fault).

So consider this scenario: EXE A and EXE B both link to dllhello.  EXE A
loads up.  Along with it, Dllhello is loaded.  The memory allocation
it does in LibMain is considered, by Windows, to be owned by EXE A.
It allocates a TModule in LibMain as follows:

	DLLHelloLib = new TModule("DLLHello", hInstance, lpCmdLine);

The TModule constructor also does the following:

  lpCmdLine = _fstrdup(ACmdLine? ACmdLine: "");

So, _fstrdup will allocate the required memory to copy the command line
string.

To Windows, the allocated memory has been accessed on behalf of EXE A.
Now suppose EXE B gets run.  Since dllhello is already loaded, LibMain does not
get called.  Then, EXE A is closed.  The allocated memory for the
TModule and the command line is freed.  The next time EXE B uses
the Dll's function CreateDLLWindow, there will be a GP fault since that
function uses the pointer to the TModule, that was freed upon the closing of EXE A.

There are two solutions to this problem.  Memory for the Dll, the TModule and the
saved command line string could be allocated from the Dll's local
heap. Or, global memory can be allocated as shared memory. Shared memory allocated
in a Dll is not automatically freed until the Dll is unloaded, as it is
considered a part owner.

The solution used in this example is to allocate the memory from
the Dll's local heap.  This is done by overloading the new operator
for a descendent of the TModule class.

The next situation where dllhello has shortcomings occurs when the window
dllhello is aliasing persists after the Dll is unloaded.  The key things
the CreateDllWindow function does are the following:

  AParentAlias = DLLHelloLib->GetParentObject(ParentHWnd);
  TheWindow = new TWindow(AParentAlias, "Hello from a DLL!", DLLHelloLib);

The GetParentObject returns a TWindow alias around
ParentHWnd (which is an HWND).  Part of what this does is subclass
the window. That is, it installs its own WndProc in ParentHWnd
via the following code in the TWindow( HWND, PTModule ) constructor:

  DefaultProc = (WNDPROC) SetWindowLong(AnHWindow, GWL_WNDPROC,
										  (DWORD)GetInstance());

This means that any messages which the parent window receives now go
through code in dllhello.  If dllhello is unloaded after a call to
CreateDllWindow, and the window it was aliasing still exists, then
there will most likely be a GP fault the next time a message comes
for that window.  This is because the message will be routed to
the WndProc in DllHello which no longer exists.

The simplest way to work around this is to restore the old WndProc
right after creating the Object Window Alias.  We will do that in the following example.
The disadvantage is that we cannot trap messages to the parent anymore.
There is no need to do that in dllhello.cpp, but a different application
might want to derive something from TWindow and use it as an alias for an existing window.

If one needs to subclass an aliased window, and that window is going
to exist after the aliasing window goes away (for example the window
is the main window in Object Vision), then one must ensure that the
old WndProc is restored.  Keep in mind though, that at the point when
you wish to restore the old wndProc, someone else may be subclassing
you.  That is messages for the window are being routed to some other
module that is in turn calling you.  Restoring the original WndProc
would disable that modules sub classing.

When looking at ways to restore the old WndProc, you cannot just delete
the object Window Alias, because our destructor
does not restore the old WndProc.  This is true up to and including
BC++ 3.1. This may change in the future.

One could look at adding it to the destructor of a derived TWindow object,
or WEP code for a Dll.  WEP is called at a sensitive point in Windows,
and it adviseable to do as little as possible there.

This zip file includes a project for building dllhello, and calldll.
Calldll has been changed only to provide a test function to display
the command line string in dllhello (which will be null in this example).

One will need to change the include and lib directories specified under
options | directories, and the location of owl.def in the calldll project.



