CREDITS:
Bradley Grainger (Splash Screen Source)
Guy Lecky-Thompson (For the Resource Hack)
Intro:(skip)
Let me start off by thanking Microsoft for the great tool which is Visual Studios 2008 (though Im sure some are using different versions). One Problem with the Express is however that its resource editor is disabled. This is pretty much a shot in the leg for anyone not used to command line compiling or adding resources manually. Now one option is ofcourse to buy Microsoft Visual Studios Professional, which I might do myself one day if I can ever cough up $200.00, but as of now Im just a hobbyist and haven't made a single redcent programming, so I feel no need in investing in something that so far hasn't made me any money, but enough of my justifying being cheap.
Another way to add resources to your files is with an external resource editor.
The Hack:
1. To start off you will need to take a look at this tutorial.
VC++ Express External Res Editor: Attach External Tool to Visual C++ Express for Editing Resources
2. Now you should know how to edit in your resources and compile, but there is a missing part of this tutorial. How do you use these resources? I will fill you in. Usually when you add resources to a files a resource header is added to your project defining certain resources, but all a these defines really do is assign a value to a token. These values reference certain resources.
Now if you have used XN Resource Editor you may have noticed that when adding resources a number is assigned on the folder of that resource. That number is its reference. And by using the
MAKEINTRESOURCE() you can for most cases reference that resource as if it were a file location.

All that fancy macro really does is just change your int to a string.
3. Now that that's all settled give it a shot. Here is an excellent tutorial for a splash screen in C++. Check it out:
Splash Screen
Check out this code too see how I edited it to work with resources:
Code:
// whatchmacallit.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
//#include "whatchmacallit.h"
//#include "Objidl.h"
#include <atlbase.h>
#include <wincodec.h>
#include <wincodecsdk.h>
// Creates a stream object initialized with the data from an executable resource.
IStream* CreateStreamOnResource(LPCTSTR lpName, LPCTSTR lpType)
{
// initialize return value
IStream * ipStream = NULL;
// find the resource
HRSRC hrsrc = FindResource(NULL, lpName, lpType);
if (hrsrc == NULL)
goto Return;
// load the resource
DWORD dwResourceSize = SizeofResource(NULL, hrsrc);
HGLOBAL hglbImage = LoadResource(NULL, hrsrc);
if (hglbImage == NULL)
goto Return;
// lock the resource, getting a pointer to its data
LPVOID pvSourceResourceData = LockResource(hglbImage);
if (pvSourceResourceData == NULL)
goto Return;
// allocate memory to hold the resource data
HGLOBAL hgblResourceData = GlobalAlloc(GMEM_MOVEABLE, dwResourceSize);
if (hgblResourceData == NULL)
goto Return;
// get a pointer to the allocated memory
LPVOID pvResourceData = GlobalLock(hgblResourceData);
if (pvResourceData == NULL)
goto FreeData;
// copy the data from the resource to the new memory block
CopyMemory(pvResourceData, pvSourceResourceData, dwResourceSize);
GlobalUnlock(hgblResourceData);
// create a stream on the HGLOBAL containing the data
if (SUCCEEDED(CreateStreamOnHGlobal(hgblResourceData, TRUE, &ipStream)))
goto Return;
FreeData:
// couldn't create stream; free the memory
GlobalFree(hgblResourceData);
Return:
// no need to unlock or free the resource
return ipStream;
}
// Loads a PNG image from the specified stream (using Windows Imaging Component).
IWICBitmapSource* LoadBitmapFromStream(IStream * ipImageStream)
{
CComPtr<IStream> stream = ipImageStream;
// initialize return value
IWICBitmapSource * ipBitmap = NULL;
char buf[10] = "\0";
// load WIC's PNG decoder
CComPtr<IWICBitmapDecoder> decoder;
HRESULT hr = decoder.CoCreateInstance(CLSID_WICJpegDecoder);
if (FAILED(hr)){MessageBoxA(NULL, "failed", "here", MB_OK); goto Return;}//NULL, CLSCTX_INPROC_SERVER, __uuidof(ipDecoder), reinterpret_cast<void**>(&ipDecoder))))
// load the PNG
hr = decoder->Initialize(stream,WICDecodeMetadataCacheOnLoad);//WICDecodeMetadataCacheOnLoad WICDecodeMetadataCacheOnDemand
if (FAILED(hr)){MessageBoxA(NULL, itoa((int)hr,buf,16), "here", MB_OK); goto ReleaseDecoder;}
// check for the presence of the first frame in the bitmap
UINT nFrameCount = 0;
if (FAILED(decoder->GetFrameCount(&nFrameCount)) || nFrameCount != 1)
goto ReleaseDecoder;
// load the first frame (i.e., the image)
IWICBitmapFrameDecode * ipFrame = NULL;
if (FAILED(decoder->GetFrame(0, &ipFrame)))
goto ReleaseDecoder;
// convert the image to 32bpp BGRA format with pre-multiplied alpha
// (it may not be stored in that format natively in the PNG resource,
// but we need this format to create the DIB to use on-screen)
WICConvertBitmapSource(GUID_WICPixelFormat32bppPBGRA, ipFrame, &ipBitmap);
ipFrame->Release();
ReleaseDecoder:
decoder.Release();
Return:
return ipBitmap;
}
// Creates a 32-bit DIB from the specified WIC bitmap.
HBITMAP CreateHBITMAP(IWICBitmapSource * ipBitmap)
{
// initialize return value
HBITMAP hbmp = NULL;
// get image attributes and check for valid image
UINT width = 0;
UINT height = 0;
if (FAILED(ipBitmap->GetSize(&width, &height)) || width == 0 || height == 0)
goto Return;
// prepare structure giving bitmap information (negative height indicates a top-down DIB)
BITMAPINFO bminfo;
ZeroMemory(&bminfo, sizeof(bminfo));
bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bminfo.bmiHeader.biWidth = width;
bminfo.bmiHeader.biHeight = -((LONG) height);
bminfo.bmiHeader.biPlanes = 1;
bminfo.bmiHeader.biBitCount = 32;
bminfo.bmiHeader.biCompression = BI_RGB;
// create a DIB section that can hold the image
void * pvImageBits = NULL;
HDC hdcScreen = GetDC(NULL);
hbmp = CreateDIBSection(hdcScreen, &bminfo, DIB_RGB_COLORS, &pvImageBits, NULL, 0);
ReleaseDC(NULL, hdcScreen);
if (hbmp == NULL)
goto Return;
// extract the image into the HBITMAP
const UINT cbStride = width * 4;
const UINT cbImage = cbStride * height;
if (FAILED(ipBitmap->CopyPixels(NULL, cbStride, cbImage, static_cast<BYTE *>(pvImageBits))))
{
// couldn't extract image; delete HBITMAP
DeleteObject(hbmp);
hbmp = NULL;
}
Return:
return hbmp;
}
// Loads the PNG containing the splash image into a HBITMAP.
HBITMAP LoadSplashImage()
{
HBITMAP hbmpSplash = NULL;
// load the PNG image data into a stream
IStream * ipImageStream = CreateStreamOnResource(MAKEINTRESOURCE(1), _T("JPEG"));
if (ipImageStream == NULL){MessageBoxA(NULL, "failed", "1", MB_OK); goto Return;}
// load the bitmap with WIC
IWICBitmapSource * ipBitmap = LoadBitmapFromStream(ipImageStream);
if (ipBitmap == NULL){MessageBoxA(NULL, "failed", "2", MB_OK); goto ReleaseStream;}
// create a HBITMAP containing the image
hbmpSplash = CreateHBITMAP(ipBitmap);
ipBitmap->Release();
if(!hbmpSplash)MessageBoxA(NULL, "failed", "3", MB_OK);
ReleaseStream:
ipImageStream->Release();
Return:
return hbmpSplash;
}
/*void RegisterWindowClass()
{
WNDCLASS wc = { 0 };
wc.lpfnWndProc = DefWindowProc;
wc.hInstance = g_hInstance;
wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SPLASHICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = c_szSplashClass;
RegisterClass(&wc);
}*/
void SetSplashImage(HWND hwndSplash, HBITMAP hbmpSplash)
{
// get the size of the bitmap
BITMAP bm;
GetObject(hbmpSplash, sizeof(bm), &bm);
SIZE sizeSplash = { bm.bmWidth, bm.bmHeight };
// get the primary monitor's info
POINT ptZero = { 0 };
HMONITOR hmonPrimary = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
MONITORINFO monitorinfo = { 0 };
monitorinfo.cbSize = sizeof(monitorinfo);
GetMonitorInfo(hmonPrimary, &monitorinfo);
// center the splash screen in the middle of the primary work area
const RECT & rcWork = monitorinfo.rcWork;
POINT ptOrigin;
ptOrigin.x = rcWork.left + (rcWork.right - rcWork.left - sizeSplash.cx) / 2;
ptOrigin.y = rcWork.top + (rcWork.bottom - rcWork.top - sizeSplash.cy) / 2;
// create a memory DC holding the splash bitmap
HDC hdcScreen = GetDC(NULL);
HDC hdcMem = CreateCompatibleDC(hdcScreen);
HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcMem, hbmpSplash);
// use the source image's alpha channel for blending
BLENDFUNCTION blend = { 0 };
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
// paint the window (in the right location) with the alpha-blended bitmap
UpdateLayeredWindow(hwndSplash, hdcScreen, &ptOrigin, &sizeSplash,
hdcMem, &ptZero, RGB(0, 0, 0), &blend, ULW_ALPHA);
// delete temporary objects
SelectObject(hdcMem, hbmpOld);
DeleteDC(hdcMem);
ReleaseDC(NULL, hdcScreen);
}
int main()
{
CoInitialize(NULL);
HBITMAP hbit = LoadSplashImage();
// Window Class name
char* c_szSplashClass = "SplashWindow";
// Registers a window class for the splash and splash owner windows.
WNDCLASSA wc = { 0 };
wc.lpfnWndProc = DefWindowProc;
wc.hInstance = NULL;
wc.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(1));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = c_szSplashClass;
RegisterClassA(&wc);
HWND hwndOwner = CreateWindowA(c_szSplashClass, NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
HWND hwndSplash = CreateWindowExA(WS_EX_LAYERED, c_szSplashClass, NULL, WS_POPUP | WS_VISIBLE,0, 0, 0, 0, hwndOwner, NULL, NULL, NULL);
SetSplashImage(hwndSplash, hbit);
if(hbit)MessageBoxA(NULL, "You really did it!", "WOW", MB_OK);
system("pause");
return 0;
}
Finally let me just say before you head out on this endeavor that you will need the COM SDK which does not come with Visual Studios Express (no wonder). Luckily there is a deprecated SDK (Microsoft Platform SDK for Windows Server 2003 R2) Which Microsoft still distributes which contains all the files you need for working with COM. You can get the
Platform SDK here.
Regards, why06