Oct 31
What’s wrong with this code? (It is adapted from something I wrote yesterday)
-
void f()
-
{
-
HRESULT hr;
-
-
hr = ::CoInitialize(NULL);
-
if (SUCCEEDED(hr)) {
-
MSXML2::IMXWriterPtr spMXWriter;
-
hr = spMXWriter.CreateInstance(__uuidof(MSXML2::MXXMLWriter30));
-
if (SUCCEEDED(hr)) {
-
// Use spMXWriter
-
}
-
-
::CoUninitialize();
-
}
-
}
Read the rest of this entry »
Oct 30
In my posts Implementing IXmlWriter Series, I wrote a streaming XML writing class whose interface is based on .NET’s XmlWriter. I recently discovered that MSXML provides its own method to write streaming XML through the class MXXMLWriter.
MXXMLWriter supports a large set of functionality including encoding, indentation, disabling output escaping, and writing XML fragments. The generated XML can be written to an IStream, a BSTR, or a DOMDocument object. However, it’s interface leaves much to be desired. Usage looks like this:
-
#import <msxml3.dll>
-
-
…
-
-
// I’m using the #import-generated _com_ptr_t-based smart pointers
-
MSXML2::IMXWriterPtr spMXWriter;
-
hr = spMXWriter.CreateInstance(__uuidof(MSXML2::MXXMLWriter30));
-
_ASSERT(SUCCEEDED(hr)); // TODO
-
-
// Configure the IMXWriter as appropriate. We will be using the default of
-
// writing to a BSTR which can be retrieved using spMXWriter->get_output().
-
-
MSXML2::ISAXContentHandlerPtr spSAXContentHandler(spMXWriter);
-
_ASSERT(spSAXContentHandler != NULL); // TODO
-
-
// Be sure to check the hrs below
-
-
hr = spSAXContentHandler->startDocument();
-
hr = spSAXContentHandler->startElement(L"", 0, L"root", 4, L"root", 4, NULL);
-
hr = spSAXContentHandler->characters(L"text", 4);
-
// endElement also takes the element name. This means we may need to
-
// maintain our own open element stack.
-
hr = spSAXContentHandler->endElement(L"", 0, L"root", 4, L"root", 4);
-
hr = spSAXContentHandler->endDocument();
The rough IXmlWriter equivalent is:
-
#include "StringXmlWriter.h"
-
-
…
-
-
StringXmlWriter xw;
-
xw.WriteStartDocument();
-
xw.WriteStartElement("root");
-
xw.WriteString("text");
-
xw.WriteEndElement(); // /root
-
xw.WriteEndDocument();
However, there might be a case to change IXmlWriter to use MXXMLWriter internally.
Jul 03
Here is a block of code which correctly performs the COM self-registration process on a DLL (distilled from the source code of regsvr32.exe):
BOOL SelfRegisterDll(LPCTSTR szDllName)
{
BOOL bRet = FALSE;
if (SUCCEEDED(OleInitialize(NULL))) {
HMODULE hm = LoadLibraryEx(szDllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (hm != NULL) {
FARPROC fp = GetProcAddress(hm, "DllRegisterServer");
if (fp != NULL) {
typedef HRESULT (STDAPICALLTYPE *FnDllRegisterServer)(void);
FnDllRegisterServer fn = (FnDllRegisterServer) fp;
HRESULT hr = (*fn)();
if (SUCCEEDED(hr)) {
bRet = TRUE;
}
}
FreeLibrary(hm);
}
OleUninitialize();
}
return bRet;
}
The most notable subtlety is the use of LoadLibraryEx() with the LOAD_WITH_ALTERED_SEARCH_PATH flag instead of LoadLibrary(). As the MSDN article Dynamic-Link Library Search Order explains, the LOAD_WITH_ALTERED_SEARCH_PATH tells Windows to first look for DLL dependencies in the directory which contains the loading DLL as opposed to the directory from which the application loaded.
This flag turns out to be rather important. I recently was informed of a bug in which the COM DLL self-registration part of an installer created with InstallShield 5.5 would fail, but regsvr32 on the DLL succeeded. Apparently InstallShield 5.5 uses its own self-registration code which does not use the LOAD_WITH_ALTERED_SEARCH_PATH to LoadLibraryEx. This caused the COM DLL to attempt to load an incompatible, third-party DLL dependency from the SYSTEM32 directory (which was installed by another product) rather than the correct version from the application directory1.
Recent Comments