ATL’s CenterWindow

It appears that ATL does not center window correctly on multi-monitor systems. ATL code checks screen work area coordinates in CWindow::CenterWindow to ensure new position is within visible area, however since SystemParametersInfo/SPI_GETWORKAREA is used target rectangle is always on a primary monitor.

This hotfix works the problem around:

Continue reading →

Default Struct Member Alignment surprise with Visual C++.NET 2005

I am compiling C++ project which is using IJG JPEG library using Visual Studio .NET 2005 (yes, 2008 is yet to come) and it came as a surprise that I stumbled upon struct data alignment issue. I am pretty sure this was not a problem with Visual Studio .NET 2003.

The project includes my C++ files and C source from the library. C++ code includes:

extern "C"
{

#undef FAR
#define XMD_H // Otherwise INT32 is redefined

// NOTE: See jmorecfg.h for condition compilation options
#include "cdjpeg.h"
#include "jversion.h"

};

Running this, I receive an error from the library (thanks for pointing this out early anyway!):

JPEG parameter struct mismatch: library thinks size is 360, caller expects 347.

How comes? Project settings are default and set to use default alignment /Zp. It seems as if compiler uses default value of 1 for my C++ code and uses default value of 8 for C code… with a result of break on runtime.

The workaround is in referencing C code with alignment override using #pragma pack:

extern "C"
{

#undef FAR
#define XMD_H // Otherwise INT32 is redefined

//#pragma pack(show)
#pragma pack(push, 8 )

// NOTE: See jmorecfg.h for condition compilation options
#include "cdjpeg.h"
#include "jversion.h"

#pragma pack(pop)

};

Crap around the world: Importing IMAPI2.DLL type library (Part 2)

IMAPI version 2 is well designed – no arguments – file systems, recorders, data streams, notifications, dispatch interfaces to be compatible with scripting, higher level development environments and interoperation layer. Still I am armed with C++ at the very moment and back to type library imports using #import.

I want to know why the hell it is required to sort out mess even between the two API modules: IMAPI2.DLL and IMAPI2FS.dll:

#pragma warning(disable: 4192)
#import “libid:2735412F-7F64-5B0F-8F00-5D77AFBE261E” no_namespace raw_interfaces_only raw_dispinterfaces // IMAPI2
#import “libid:2C941FD0-975B-59BE-A960-9A2A262853A5” no_namespace raw_interfaces_only raw_dispinterfaces exclude(“_IMAPI_MEDIA_PHYSICAL_TYPE”, “IDiscRecorder2”) // IMAPI2FS
#pragma warning(default: 4192)

In order to import into C++ project, it is required to exclude two items which are duplicate between the modules. OMFG.

Still it is not the end. Since I am subscribing to events using ATL’s IDispEventImpl and SINK_ENTRY_EX, I need DISPID values for the Update methods of DDiscFormat2DataEvents and DFileSystemImageEvents. How do I find them? Type library as usual? No, my dear friend, type library does not mention this useless value… For further reference:

  • DFileSystemImageEvents::Update – DISPID is 256
  • DDiscFormat2DataEvents::Update – DISPID is 512

Crap around the world: Importing IMAPI2.DLL type library

Trying to import IMAPI2.DLL type library to be able to use IMAPI version 2 in application:

//#pragma warning(disable: 4192)
#import “libid:2735412F-7F64-5B0F-8F00-5D77AFBE261E” no_namespace raw_interfaces_only raw_dispinterfaces // IMAPI2
//#pragma warning(default: 4192)

Compiler output I see:

warning C4192: automatically excluding ‘IConnectionPointContainer’ while importing type library ‘2735412F-7F64-5B0F-8F00-5D77AFBE261E’
warning C4192: automatically excluding ‘IEnumConnectionPoints’ while importing type library ‘2735412F-7F64-5B0F-8F00-5D77AFBE261E’
warning C4192: automatically excluding ‘IConnectionPoint’ while importing type library ‘2735412F-7F64-5B0F-8F00-5D77AFBE261E’
warning C4192: automatically excluding ‘IEnumConnections’ while importing type library ‘2735412F-7F64-5B0F-8F00-5D77AFBE261E’
warning C4192: automatically excluding ‘tagCONNECTDATA’ while importing type library ‘2735412F-7F64-5B0F-8F00-5D77AFBE261E’
warning C4192: automatically excluding ‘IStream’ while importing type library ‘2735412F-7F64-5B0F-8F00-5D77AFBE261E’
warning C4192: automatically excluding ‘ISequentialStream’ while importing type library ‘2735412F-7F64-5B0F-8F00-5D77AFBE261E’
warning C4192: automatically excluding ‘_LARGE_INTEGER’ while importing type library ‘2735412F-7F64-5B0F-8F00-5D77AFBE261E’
warning C4192: automatically excluding ‘_ULARGE_INTEGER’ while importing type library ‘2735412F-7F64-5B0F-8F00-5D77AFBE261E’
warning C4192: automatically excluding ‘tagSTATSTG’ while importing type library ‘2735412F-7F64-5B0F-8F00-5D77AFBE261E’
warning C4192: automatically excluding ‘_FILETIME’ while importing type library ‘2735412F-7F64-5B0F-8F00-5D77AFBE261E’

I was of an opinion that Microsoft people is quite familiar about hiding identifiers from automatic embedding into type library (they are probably using ATL and attributed code) and avoiding duplicating well known identifiers like IConnectionPointContainer.

Windows Image Mastering IMAPI

In continuation of Nero API

Windows IMAPI is much more convenient to use, it is built on COM, it is “more Windows” etc, however there was an issue even there.

Normally IEnumXXX::Next enumerator method accepts third parameter NULL since if we are getting items one by one, we are fine processing return code S_OK/S_FALSE and we don’t need extra parameter pceltFetched to get us number of fetched items. It is ok to pass NULL in most cases, not with IMAPI enumerators however – they require a valid pointer.

Nero API

I have recently been working on CD/DVD burning feature and I was using Ahead Nero API as an option. Frankly, I was of a better opinion of this API. It is more or less well documented and C++ definitions looks fine, however…

The first problem was it failed to operate on a worker thread. My lord! I have to have burning task running on the application GUI STA thread using crappy poll-style abort callbacks. Anyway it did not work on a worker thread stumbling on a number of memory access violations. It was ludicrous that I already made everything look almost like in their sample application but API kept throwing exceptions. Until I realized it makes difference if it was running on a worker thread or not.

Anyway it keeps throwing int exceptions, and when under debugger and you stop on the exception, then chances are high that there will be anyway access violations later after burn is complete.

First-chance exception at 0x7c81eb33 in DVRRunDll.exe: Microsoft C++ exception: dummy_exception @ 0x0013a688.
First-chance exception at 0x7c81eb33 in DVRRunDll.exe: Microsoft C++ exception: int @ 0x00139594.
First-chance exception at 0x7c81eb33 in DVRRunDll.exe: Microsoft C++ exception: int @ 0x00139594.
First-chance exception at 0x7c81eb33 in DVRRunDll.exe: Microsoft C++ exception: int @ 0x00139594.
First-chance exception at 0x7c81eb33 in DVRRunDll.exe: Microsoft C++ exception: int @ 0x00139594.
First-chance exception at 0x7c81eb33 in DVRRunDll.exe: Microsoft C++ exception: int @ 0x00139594.
First-chance exception at 0x7c81eb33 in DVRRunDll.exe: Microsoft C++ exception: int @ 0x00139594.
First-chance exception at 0x7c81eb33 in DVRRunDll.exe: Microsoft C++ exception: int @ 0x00139594.
First-chance exception at 0x7c81eb33 in DVRRunDll.exe: Microsoft C++ exception: int @ 0x00139594.
First-chance exception at 0x7c81eb33 in DVRRunDll.exe: Microsoft C++ exception: int @ 0x00139594.
First-chance exception at 0x7c81eb33 in DVRRunDll.exe: Microsoft C++ exception: int @ 0x00139594.

Did you know that: LVN_GETINFOTIP?

Did you know that when you handle LVN_GETINFOTIP notification message and you are provided with NMLVGETINFOTIP structure, you cannot just supply your own pszText string for the tooltip text? Instead you have to copy your string into supplied buffer, such as using _tcsncpy function. Otherwise things would not work.

BEGIN_MSG_MAP_EX(CFooPropertyPage)
	CHAIN_MSG_MAP(CPropertyPageT)
	...
	MSG_LVN_GETINFOTIP(IDC_FOOLISTVIEW, OnFooListViewGetInfoTip) 
	REFLECT_NOTIFICATIONS()
END_MSG_MAP()
...
LRESULT OnFooListViewGetInfoTip(NMLVGETINFOTIP* pHeader)
{
	ATLASSERT(!pHeader->lParam);
	CFoo* pFoo = m_FooListView.GetItemData(pHeader->iItem);
	CString& sTextBuffer = m_ModelListView.GetTextBufferString(TRUE);
	...
	sTextBuffer.TrimRight(_T("\t\n\r "));
	_tcsncpy(pHeader->pszText, sTextBuffer, pHeader->cchTextMax - 1);
	pHeader->pszText[pHeader->cchTextMax - 1] = 0;
	return 0;
}