Link to home
Start Free TrialLog in
Avatar of mco
mco

asked on

LoadLibrary behaves strangely on Win98

I have an MFC program that should run on W2K, NT, and 98.
The program uses features that exist in the RichEdit control version 2 & 3, that are in riched20.dll.

MFC calls LoadLibraryA("RICHED32.DLL") .
In W2K it works great because the riched32.dll there, is actually an emulator that runs version 2 from riched20.

In NT it doesn't work naively, but I solved the problem by copying the riched32.dll emulator to the same folder where my executables reside. Since LoadLibrary uses a normal directory search algorithm, this riched32.dll is loaded (and not the one from the Windows\System32 directory) and everything again works OK.

In Win 98, I tried the same trick as in NT but it doesn't work. The riched32.dll loaded is always the one from the Windows\system directory, no matter how I play with the PATH. Replacing riched32.dll solves the problem, but that is something I do not want to do on a user's PC because I am changing the system.

How can I get LoadLibrary to take the DLL from the application executable directory (as is documented)?
Alternatively , how else can I resolve the problem?
Avatar of jkr
jkr
Flag of Germany image

>>How can I get LoadLibrary to take the DLL from the application executable directory (as is documented)?


Use a fully qualified path, e.g.

char acPath [ MAX_PATH];

GetModuleFileName ( NULL, acPath, MAX_PATH);

PathRemoveFileSpec ( acPath);

lstrcat ( acPath, "\\dllname.dll");

HINSTANCE hDll = LoadLibrary ( acPath);
Avatar of mco
mco

ASKER

Sorry, I should have stressed the following point: I do not intend to modify MFC source code. It is a maintenance hell.
>>I do not intend to modify MFC source code

Why should you?
Avatar of mco

ASKER

As I said, the call LoadLibraryA("RICHED32.DLL") , is made from MFC source. That is not my code.
BTW, there's another point -however, so far I was not able to locate the article on MSDN again, so just a quote here:

"There's also a new approach called 'Private DLLs', see http://msdn.microsoft.com/library/techart/dlldanger1.htm :
Private DLLs are also referred to as side-by-side DLLs, because a private copy of a DLL is used in one
specific application while the system DLL is used by other applications. If you run WordPad and SuperApp
concurrently, two copies of Msvcrt.dll are loaded into memory (hence, the "side-by-side" terminology),
even if WordPad and SuperApp use the same version of Msvcrt.dll.
There are two approaches to implementing private DLLs. If you're writing a new application or a new
component, you give each version a unique version number. You then register each DLL or component in
the application directory where you want a private copy. Your application knows to load a private copy
of a shared DLL by version information in the application.
The second side-by-side approach is geared toward existing applications. Suppose C:\SuperApp\SuperApp.exe
is an existing application that you want to protect from future DLL upgrades or was broken by a service
pack upgrade. You simply copy the DLLs you want private to SuperApp into .\SuperApp and create an empty
file in this directory called ".\SuperApp.exe.local." Now when SuperApp fires up and finds the .local
file it searches the current directory for DLLs and COM servers before it searches the standard path.
If your application is broken by a service pack upgrade, you create an install program with the .local
file and the older DLLs you need and provide them to your customers."
I agree with jkr ... do something like this instead of calling
AfxInitRichEdit(), i.e. in InitInstance of your app:

extern _AFX_RICHEDIT_STATE* AFX_CDECL AfxGetRichEditState();

_AFX_RICHEDIT_STATE* pState = AfxGetRichEditState();
ASSERT (pState->m_hInstRichEdit == NULL); // to ensure it's not already loaded.
// create path as in jkr's post
...
pState->m_hInstRichEdit = LoadLibrary(<thePathToDLL>);


ZOPPO
Avatar of mco

ASKER

Zoppo,
Actually, writing my own version of AfxInitRichEdit was my first attempt , but I failed even to compile. Did you manage to compile your suggestion?

The code:
#include "afxrich.h"
.
.
.
BOOL CREApp::InitInstance()
{
_AFX_RICHEDIT_STATE* pState = AfxGetRichEditState();
pState->m_hInstRichEdit = 99;

I get an error: error C2027: use of undefined type '_AFX_RICHEDIT_STATE' , on the last line above.
I.e. there is no error on the line where pState is declared and assigned, although the same type is used, but
there is an error on the last line where a field of pState is accessed.
>>error C2027: use of undefined type '_AFX_RICHEDIT_STATE'

You do

#include <afxrich.h>

?
ASKER CERTIFIED SOLUTION
Avatar of Zoppo
Zoppo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mco

ASKER

I'll try it out soon.
Are there any pitfalls with including an *impl.h file?
I thought they were only for building MFC, not for applications linking with it.
>Are there any pitfalls with including an *impl.h file?

Well, I'm not absoluteley sure, but I found some articles in MSDN where <afximpl.h> is included to workaround known
problems, i.e. http://support.microsoft.com/default.aspx?scid=kb;[LN];Q230377

ZOPPO
Avatar of mco

ASKER

Zoppo,
I am going to give you an A because you solved the problem.
For the record, there is a more elegant method that does not require including an internal MFC file: If I just pre-load the desired riched32.dll before calling MFC's original AfxInitiRichEdit, then the load in MFC will not load a different version. It will use the one I have preloaded.
So, using the full path had nothing to do with the solution?
Maybe solution was a co-production ... if you want I can offer you half of the points, ok?
Avatar of mco

ASKER

No need. I posted the same question in the W98 topic area and a person there gave the preloading idea and he got full points.
Avatar of mco

ASKER

jkr, of course the full path is needed, but that was not part of the problem. (I knew how to get the fullpath but had  a problem getting MFC to load from there).
> jkr, of course the full path is needed, but that was not part of the problem.

Well, sorry, but I don't agree ... the main problem was that
the full path was needed ... how to load the riched20.dll from
a given path was a secondary problem then ...

Therefore I asked jkr whether he agrees if I offer him half of the points.
Avatar of mco

ASKER

1) It is up to you, they are your points and you can do whatever you want with them :-)
2) I am just stating that loading with the full path was not the problem I presented. The problem I presented was that I did not know how to change which DLL MFC will load on a Win98 OS. It is correct that in the solution you also need to load the full path, but you also need to do other things.
Your reply by itself without jkr's, solved the problem.
>>Your reply by itself without jkr's, solved the problem.

The reply was "I agree with jkr"

*shrug*

Have a nice time on EE.
Avatar of mco

ASKER

Look, I also agree with you, jkr. Your posting was correct.
I think though, that points should go to whoever helps solve the problem that was posted, not necessarily to everyone writing truthful information.
Again, the problem I posed was of getting MFC to load the correct DLL, not on loading a specific DLL in general.