Figure 1 Delay-loading a DLL
//Function pointer type for LookUpWord
typedef BOOL (WINAPI *PFNLOOKUP)(wchar_t *);
void OnToolsSpelling(void)
{
HINSTANCE hMod;
PFNLOOKUP pfnLookup;
wchar_t *pszWord;
hMod=LoadLibrary("BASICSPL.DLL");
if (NULL==hMod)
[Spell-checker not found, show error]
//Get address of ordinal 10
pfnLookup=(PFNLOOKUP)GetProcAddress(hMod, MAKEINTRESOURCE(10));
if (NULL!=pfnLookup)
{
pszWord=GetFirstWord(); //Retrieve first word in text
while (NULL!=pszWord)
{
if (FALSE==(*pfnLookup)(pszWord)) //Check if word is in dictionary
[Alert user]
pszWord=GetNextWord(pszWord); //Go to next word in text
}
}
else
[Export not found, invalid spell checker!]
FreeLibrary(hMod);
return;
}
Figure 3 Using COM to Access a Service
void OnToolsSpelling(void)
{
ISpellChecker *pSC;
CLSID clsID;
//This hypothetical function uses the registry or invokes UI
GetCLSIDOfSpellChecker(&clsID);
if (SUCCEEDED(CoCreateInstance(clsID, NULL, CLSCTX_SERVER
, IID_ISpellChecker, (void **)&pSC)))
[Spell-checker not found, show error]
pszWord=GetFirstWord(); //Retrieve first word in text
while (NULL!=pszWord)
{
if (FAILED(=pSC->LookUpWord(pszWord))) //Check for word in dictionary
[Alert user]
pszWord=GetNextWord(pszWord); //Go to next word in text
}
pSC->Release(); //Release is a member function of IUnknown
return;
}
Figure 4 Hypothetical Specifications for SpellCheck2.0
Ordinal | Prototype | Description |
10 | BOOL WINAPI LookUpWord (wchar_t *pszWord) | Checks whether or not a particular word exists in the current dictionary |
11 | BOOL WINAPI AddWord (wchar_t *pszWord) | Adds a custom word to the dictionary |
12 | BOOL WINAPI RemoveWord (wchar_t *pszWord) | Removes a custom word from the dictionary |
Figure 5 Caching Module Handles
#define CMODULES 10 //Number of DLLs
#define DLL_ID_SPELLCHECK 0 //Array indices
#define DLL_ID_THESAURUS 1
[other defines here]
typedef BOOL (WINAPI *PFNLOOKUP)(wchar_t *);
HINSTANCE g_rghMods[CMODULES]; //Initialized to NULL on startup.
HINSTANCE ModHandle(UINT id)
{
ASSERT(id >=0 && id < CMODULES);
if (NULL==g_rghMods[id])
{
g_rghMods[id]=LoadLibrary([name of DLL]);
if (NULL==g_rghMods[id])
[Throw exception]
}
return g_rghMods[id];
}
void OnToolsSpelling(void)
{
PFNLOOKUP pfnLookup;
[Other locals]
pfnLookup=(PFNLOOKUP)GetProcAddress(ModHandle(DLL_ID_SPELLCHECK)
, MAKEINTRESOURCE(10));
if (NULL!=pfnLookup)
{
[do stuff]
}
else
[error]
return;
}
Figure 6 COM Solutions to DLL Problems
Problem | Solution | |
Path dependencies, multiple providers of a service | Use the registry to map from abstract class identifiers to absolute server locations as well as mapping between categories and class identifiers | |
Decentralized definition of identifiers | Use GUIDs generated by an algorithm that guarantees uniqueness across time and space, eliminating the need for centralized identifier allocation | |
Specific management APIs for each service category | Supply a very simple generic and universal management API that accommodates all service categories, called Implementation Location | |
Sharing instances across process/machine boundaries | Marshaling of interface pointers, Location Transparency providing the ability to implement a server as an EXE or DLL | |
Different in-process, local, and remote programming models | A single model for all types of client-object connections supported through the interface structure, Location Transparency | |
Lifetime management of servers and objects | Universal reference counting through the base interface IUnknown that all objects support and from which all other interfaces are derived | |
Multiple services per server module | Use CLSID:IID:table_offset to absolutely identify functions instead of module:ordinal | |
Versioning well as interfaces that are strongly typed at both compile time and run time | Support the concept of multiple immutable interfaces as |