Opening Patch Files when Compiled for Unicode

Opening Patch Files when Compiled for Unicode

  • Comments 5

If you want to open a .msp file with the Windows Installer APIs, you must pass MSIDBOPEN_PATCHFILE to the MsiOpenDatabase function, or ERROR_OPEN_FAILED (110) is returned. Below is the definition of both MSIDBOPEN_PATCHFILE and MSIDBOPEN_READONLY from msiquery.h in the Windows Installer SDK.


LPCTSTR is defined as LPCWSTR when UNICODE is defined, which is defined as wchar_t*. Since sizeof(wchar_t) is 2, the value of MSIDBOPEN_PATCHFILE is 16 when UNICODE is defined. If you pass this to either the MsiOpenDatabaseA function or the MsiOpenDatabaseW function ERROR_OPEN_FAILED is still returned. The value must always be defined as 32.

For the automation method Installer.OpenDatabase the second parameter must be set to msiOpenDatabaseModePatchFile to open a patch, which is always defined as 32.

Most developers probably haven't run into this problem yet because of support for Windows 95, 98, and Me, where Unicode is not natively supported and it's typically undesirable to have to ship and support two bootstrap applications. Since Windows NT, 2000, XP, 2003, and future platforms support both ANSI and Unicode it makes sense to compile bootstrap applications for ANSI or MBCS. But when you choose to or need to support only Unicode, be sure to pass 32 as the szPersist parameter to MsiOpenDatabase.

UINT uiError = MsiOpenDatabase(TEXT("Patch.msp"), (LPCTSTR)32, &hDatabase);

Leave a Comment
  • Please add 5 and 4 and type the answer here:
  • Post
  • The documentation for MSIDBOPEN_PATCHFILE states: "Add this flag to indicate a patch file."  Thus, you should use

    MsiOpenDatabase(TEXT("Patch.msp"), MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hDatabase)

    which currently results in (LPCTSTR)32 whether or not UNICODE is defined, and will hopefully be more portable to implementations of Win32 on future platforms.
  • Thanks, Kalle, you're right. The word "Add" in the documentation I found is very important here. While not a traditional use of "flags", adding MSIDBOPEN_READONLY - an LPTSTR - and MSIDBOPEN_PATCHFILE - also an LPTSTR - result in pointer arithmatic where the value of MSIDBOPEN_PATCHFILE is doubled because it is a wchar_t*, which is 2 bytes wide, such that the final value when UNICODE is defined would be 32/sizeof(wchar_t)*2 = 32/2*2 = 32.

    Thank you for pointing this out.

    BTW, I appreciate your continued reading, questions, and comments, but I'm curious as to what you're using to post messages. I always get 11 comment requests from you. It's quick to remedy, but thought I'd just let you know and am curious why it's happening myself.
  • MSIDBOPEN_PATCHFILE isn't an LPTSTR at all, but an integer.  Really, if you use that alone as the second argument of MsiOpenDatabase, then the C compiler should warn about the suspicious conversion.

    The browser I'm using is ELinks 0.12.GIT (3146ceea22f1ac06f46961ef0a3c06de1de427c8), configured to prompt before accepting cookies.  This version appears to follow redirections in the background even before I've answered to the prompts; if the MSDN site then redirects back to the same page and expects to receive the cookie it tried to set, this could result in a loop that causes the duplicate posts.  But if that hypothesis is correct, the same would happen with a browser configured to reject cookies without prompting, so I don't think the fault is entirely on ELinks here.  Anyway, I'm now logging the system calls and network packets for posting ths comment, so that the browser can be fixed if it turns out to be acting incorrectly.
  • Actually, MSIDBOPEN_PATCHFILE is an LPTSTR because it's being cast as such, so that when you add two LPTSTR types together the second and successive types are multiplied by the size of the type (so wchar_t when UNICODE is defined). This is why adding MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE is compiled as 32 instead of 16 when using just MSIDBOPEN_PATCHFILE by itself.
  • It might take you back to Almost Live and the Lame List, and if so then I was able to inspire the right...
Page 1 of 1 (5 items)