Mar 12
In an effort to EOL MSXML 4 and encourage developers to use MSXML 6, the MSXML team is going to kill-bit MSXML4 in Q4 2007. This means that you will no longer be able to create instances of MSXML 4 from within Internet Explorer.
Be sure to update your applications accordingly. For this, the MSXML team’s post Upgrading to MSXML 6.0 may prove quite useful.
Mar 12
Apparently Microsoft has an API for just about everything. Today I read about Microsoft’s Delta Compression Application Programming Interface, an API for creating and applying binary diffs. This API looks ideal for building an application’s incremental online update facility.
Feb 01
The Win32 shell lightweight utility API (shlwapi.dll) is a cornucopia of useful functions. It appears to be Microsoft’s “dumping ground” for functions without a better home. (I believe Microsoft internal DLL ownership also played a part.) Had I known about shlwapi years ago, it would have saved me considerable programming effort.
Particularly useful are SHCreateStreamOnFile, the path family of functions (e.g. PathCombine), and the registry family of functions (e.g. SHRegGetPath).
However, it appears that Microsoft is slowly moving functionality out of shlwapi into other places. For example, many of shlwapi’s string handling functions have better-designed replacements in Microsoft’s safe string library strsafe. Similarly, shlwapi’s SHRegGetValue has been deprecated in favor of advapi32.dll’s RegGetValue.
Be sure to look at all the functionality shlwapi provides — you may find a hidden gem of your own!
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.
Oct 30
The Microsoft XML team recently posted in their blog a set of recommendations on which version of MSXML to use. In short, they recommend using MSXML 6.0 but falling back to 3.0 if it isn’t available.
My product currently tries MSXML 4.0 first — but only SP2 and above. We ran into bugs with previous versions of MSXML 4.0. I will have to evaluate moving to MSXML 6.0.
Jul 19
I was intending to revisit and possibly rewrite my Win32 LD_PRELOAD application when I discovered Microsoft Research has written something which does far, far more: Detours.
Jul 17
I was about to write a tutorial on how to create a custom Win32 control in C when I found that someone had beat me to it: Creating Custom Controls From Scratch. Overall it is quite good, and I learned a few new things myself. (By the way, the entire Catch22 Tutorials site is filled with fascinating material for Win32 developers.)
One thing to note: If you separate your custom control into a DLL, you will need to create an initialization function which registers the window classes (similar to InitCommonControls()). Be sure to pass the CS_GLOBALCLASS flag to RegisterClass() to register it as application global. If you don’t, you will only be able to instantiate your control manually by passing the DLL’s HMODULE as a parameter to CreateWindow().
By the way, MFC seems to support customizing controls primarily through window subclassing, which is a related but slightly different mechanism.
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