Adding and using Resources with Visual Studios Express

Posts 1–4 of 4 · Page 1 of 1
Adding and using Resources with Visual Studios Express
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
You could just surf your way around and get the "free" version of VS Pro...
~
"free" as in cracked. ;P
That seems like cheating to me. Weird saying that since Im the one cheating at games, but I like to work with what I've got, w/o torrents and such not to mention I could never get into torrents, LimeWire, etc. And I don't trust them. =/
Scan before your run.... There's a nice "free" release on tpb pre-activated '08 professional.
~
Posts 1–4 of 4 · Page 1 of 1
This thread is closed for replies.

Similar Threads

Tags for this Thread

None

Talk with us