Introduction
This article is about demonstrating the creation of a compact application that can still take advantage of rich graphics. It also demonstrates how to access resources with the IImgCtx
interface.
As mentioned in strnghrs article there are numerous ways to use free image decoding source. However each of these libraries adds at least 200 K + to the file size and are usually more sophisticated than necessary for simple image display.
You may ask why C and not C++, well there were two main reasons:
- Mingw compiled C applications are significantly smaller than the C++ equivalents.
- I like to understand the fundamentals of the process and C tends to hide less of the detail.
Creating an instance of IImgCtx
In C accessing the COM creation objects is slightly different, so I thought I would discuss the basic startup code first:
CoInitialize( NULL );
...
if ( FAILED(hr) ) {
hr = CoCreateInstance( &CLSID_IImgCtx, NULL,
CLSCTX_INPROC_SERVER, &IID_IImgCtx,
(LPVOID*) &m_pImgCtx);
ErrorDescription(hr);
PostQuitMessage (0) ;
}
hr = m_pImgCtx->lpVtbl->Load(m_pImgCtx,
L"res://loadimg.exe/EXIT.PNG", 0);
if ( FAILED(hr) ) {
ErrorDescription(hr);
PostQuitMessage (0) ;
}
do {
m_pImgCtx->lpVtbl->GetStateInfo(m_pImgCtx,
&ulState, &sizeImage, FALSE);
Sleep(5);
} while( (ulState & IMGLOAD_LOADING) );
m_pImgCtx->lpVtbl->GetPalette(m_pImgCtx, &m_hPal);
The most important difference to note in C is that there is no concept of the &
alias for functions and there is no this
pointer. This means that the Class ID items for CoCreateInstance
need to be prefixed and each call to a COM object needs to have ->lpVtbl
and the COM instance pointer(m_pImgCtx)
included. Example:
m_pImgCtx->lpVtbl->GetPalette(m_pImgCtx, &m_hPal);
As shown in the code, the steps for "instantiating" an image include creating an instance of ImgCtx
object and then loading the resource/file.
Setting up the image resource
This is where I have used a different approach from strnghrs. When creating smaller executables, I prefer to keep the images with the binary, making it easy to move around. After noticing the way IE/MS Help uses the res:// protocol I found two articles that help explain the use of this with the ImgCtx
interface.
- Syntax of the Res: Protocol
- res Protocol
There is also an excellent CodeProject article by Santosh Rao about using res:// through the MSHTML component.
- How to use the res: protocol in Developer Studio
Santosh also explains how to setup the .rc file correctly. The key to it is the use of the file name and the 2110 directive.
[from loadimg.rc]
EXIT.PNG 2110 DISCARDABLE "./res/Exit.png"
Once the resource file is setup correctly the control can be called file res://loadimg.exe/Exit.png. Note the use of L"" for the expected Unicode string from the file. The load process is an asynchronous call, so it is important to confirm that the loading is finished before continuing to work with the image. This is achieved simply by waiting (sleeping for 5 ms) in my code.
Rendering the image
With the image loaded we can now render the image to a Device Context of our choice. To keep the example simple I have chosen to render the image directly into the primary window during the WM_PAINT
call.
case WM_PAINT :
hdc = BeginPaint (hwnd, &ps);
GetClientRect (hwnd, &rect);
DrawText (hdc, "ImgLoad!", -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
SelectPalette(hdc, m_hPal, TRUE);
RealizePalette(hdc);
imgrect.left = imgrect.top = 0;
imgrect.bottom = sizeImage.cy;
imgrect.right = sizeImage.cx;
m_pImgCtx->lpVtbl->Draw(m_pImgCtx,
hdc, &imgrect);
EndPaint (hwnd, &ps) ;
return 0 ;
The ImgCtx
interface requires a handle to a Device Context and a pointer to RECT. While experimenting, I noted that the rect
can be of a different size from the original image and it will resize correctly.
Cleaning up
Using the ImgCtx
interface requires that the "instance" be cleaned up after it is being used. It is also important to clean up after the rest of the COM work as well. This is achieved with the following two lines:
m_pImgCtx->lpVtbl->Release(m_pImgCtx);
...
CoUninitialize();