Hi, I'm trying to load a 24 bit image, and then render it on the primary surface via DirectX. The application compiles fine, but quits with an appcrash error. What is wrong?

Game.cpp
Code:
/*************************************************************************/
// Called in this order

// Code to initialize game - called once

#include "main.h" // your header file

// Global varables for this source file

LPDIRECTDRAW7        lpdd              = NULL;  // dd object
LPDIRECTDRAWSURFACE7 lpddsprimary      = NULL;  // dd primary surface
LPDIRECTDRAWSURFACE7 lpddssecondary    = NULL;  // dd back surface
LPDIRECTDRAWSURFACE7 lpoffscreen       = NULL;  // offscreen working surface
LPDIRECTDRAWPALETTE  lpddpal           = NULL;  // a pointer to the created dd palette
DDSURFACEDESC2       ddsd;                      // a direct draw surface description struct
DDSCAPS2             ddscaps;                   // a direct draw surface capabilities struct
HRESULT              ddrval;                    // result back from dd calls

UCHAR                *primary_buffer = NULL;    // primary video buffer


int Game_Init(void *parms)
{
    // this function is where you do all the initialization 
    // for your game

    log_file = fopen("log.txt","w");

    debug("Initializing Game...\n\n\n");
   
    // create object and test for error
    if (DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL) == DD_OK)
            debug("-> DirectDraw Object Created Successfully\n\n");
            
    else
    {
            debug("***Error creating DDraw object***\n\n\n");
            return(0);
    }

    // set cooperation level to windowed mode normal
    if (lpdd->SetCooperativeLevel(g_hwnd,
           DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN | 
           DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT) == DD_OK)
            debug("-> Cooperation Level Set\n\n");
    else
    {
            debug("***Couldn't set cooperation level***\n\n\n");
            return(0);
    }

    // set the display mode
    if (lpdd->SetDisplayMode(WINDOW_WIDTH,WINDOW_HEIGHT,BITS,0,0) == DD_OK)
            debug("-> Display Mode Set\n\n");
    else
    {
            debug("***Failed to set display mode***\n\n\n");
            return(0);
    }

    // Create the primary surface
    memset(&ddsd,0,sizeof(ddsd));
    ddsd.dwSize         = sizeof(ddsd);
    ddsd.dwFlags        = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;

    // For secondary surface
    ddsd.dwBackBufferCount = 1;

    if (lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL) == DD_OK)
            debug("-> Primary Surface Created at lpddsprimary\n\n");
    else
    {
            debug("***Error Creating Primary Surface***\n\n\n");
            return(0);
    }
   
    ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
   
    if (lpddsprimary->GetAttachedSurface(&ddscaps,&lpddssecondary) == DD_OK)
            debug("-> Secondary Surface Created at lpddssecondary off of lpddsprimary\n\n");
    else
    {        
            debug("***Error Creating Secondary Surface***\n\n\n");
            return(0);
    }
   
    // For Offscreen surface
   
    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
   
    // set dimensions
   
    ddsd.dwWidth = 600;
    ddsd.dwHeight = 400;
   
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
   
    // create offscreen surface
    if (lpdd->CreateSurface(&ddsd,&lpoffscreen,NULL) == DD_OK)
            debug("-> Offscreen Surface Created at lpoffscreen\n\n");
    else
    {
            debug("***Error Creating Offscreen Surface***\n\n\n");
            return(0);
    }
    
    if(!Load_Bitmap_File(&bitmap, "image.bmp"))
    {        
            debug("***Couldn't Load Bitmap***");
            return(0);
    }
    else debug("-> Loaded bitmap");
    
    debug("Done\n\n\n");

// return success
return(1);
} // end Game_Init



/**************************************************************************/



// Main Game - loops

// this is the workhorse of your game it will be called
// continuously in real-time this is like main() in C
// all the calls for you game go here!



int Game_Main(void *parms)
{
         // check of user is trying to exit
         if (KEY_DOWN(VK_ESCAPE) || KEY_DOWN(VK_SPACE))
            PostMessage(g_hwnd, WM_DESTROY,0,0);
            
         // set up the surface description to lock the surface
         memset(&ddsd,0,sizeof(ddsd)); 
         ddsd.dwSize = sizeof(ddsd);

         // lock the primary surface, note in a real game you would
         lpddsprimary->Lock(NULL,&ddsd, 
                   DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);

         // get video pointer
         primary_buffer = (UCHAR *)ddsd.lpSurface;

         // copy each bitmap line into primary buffer 
         // taking into consideration non-linear video 
         // cards and the memory pitch lPitch
         for (int y = 0; y < WINDOW_HEIGHT; y++)
         {
             // copy the line
             memcpy(&primary_buffer[y*ddsd.lPitch], // dest address
             &bitmap.buffer[y*WINDOW_WIDTH*4],   // src address
             WINDOW_WIDTH*4);                         // bytes to copy
         } // end for y

         // unlock the surface
         lpddsprimary->Unlock(NULL);


         // return success
         return(1);
} // end Game_Main



/*************************************************************************/



// Called before WM_DESTROY



int Game_Shutdown(void *parms)
{
    // this function is where you shutdown your game and
    // release all resources that you allocated

    debug("Shutting Game down...\n\n\n");
    
    // release attached surface first
    if (lpddssecondary!=NULL)
    lpddssecondary->Release();

    debug("-> Released Secondary Surface\n\n");

    // first release the primary surface
    if (lpddsprimary!=NULL)
       lpddsprimary->Release();

    debug("-> Released Primary Surface\n\n");

    // release offscreen surface
    if (lpoffscreen!=NULL)
       lpoffscreen->Release();
   
    debug("-> Released Offscreen Surface\n\n");
   
    // release the directdraw object
    if (lpdd!=NULL)
       lpdd->Release();
   
    debug("-> Released DirectDraw Object\n\n");
    
    if(!Unload_Bitmap_File(&bitmap))
       debug("***Failed to unload bitmap***");
       
    else debug("-> Unloaded bitmap\n\n");

    debug("Done\n");
   
    fclose(log_file);

// return success
return(1);
} // end Game_Shutdown
Dexterous.cpp

Code:
#include "main.h"

void debug(char *text)
{
     fprintf(log_file,"%s",text);
}


/***************************************************************************/


int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)
{
     // this function opens a bitmap file and loads the data into bitmap

     int file_handle,  // the file handle
         index;        // looping index
         
     char *buffer;

     UCHAR *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
     OFSTRUCT file_data;        // the file data information

     // open the file if it exists
     if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
        return(0);

     // now load the bitmap file header
     _lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));

     // test if this is a bitmap file
     if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
     {
        // close the file
        _lclose(file_handle);

        // return error
        return(0);
     } // end if

     // now we know this is a bitmap, so read in all the sections

     // first the bitmap infoheader

     // now load the bitmap file header
     _lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));


     // finally the image data itself
     _lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);

     // now read in the image, if the image is 16, 24, or 32 bit then simply read it
     if (bitmap->bitmapinfoheader.biBitCount == 16 || bitmap->bitmapinfoheader.biBitCount == 24 || bitmap->bitmapinfoheader.biBitCount == 32)
     {
        // allocate the memory for the image
        if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
        {
           // close the file
           _lclose(file_handle);

           // return error
           return(0);
        } // end if

     // now read it in
     _lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);

   } // end if
   else
   {
        debug("***8-bit image***");
        return(0);
   } // end if


   // write the file info out 
   sprintf(buffer,"-> Bitmap Information\n\n\tfilename:%s \n\tsize=%d \n\twidth=%d \n\theight=%d \n\tbitsperpixel=%d \n\tcolors=%d \n\timpcolors=%d\n\n",
        filename,
        bitmap->bitmapinfoheader.biSizeImage,
        bitmap->bitmapinfoheader.biWidth,
        bitmap->bitmapinfoheader.biHeight,
		bitmap->bitmapinfoheader.biBitCount,
        bitmap->bitmapinfoheader.biClrUsed,
        bitmap->bitmapinfoheader.biClrImportant);
        
   debug(buffer);


   // close the file
   _lclose(file_handle);

   // flip the bitmap
   Flip_Bitmap(bitmap->buffer, 
               bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8), 
               bitmap->bitmapinfoheader.biHeight);

   // return success
   return(1);

} // end Load_Bitmap_File

///////////////////////////////////////////////////////////

int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)
{
    // this function releases all memory associated with "bitmap"
    if (bitmap->buffer)
    {
       // release memory
       free(bitmap->buffer);

       // reset pointer
       bitmap->buffer = NULL;

    } // end if

    // return success
    return(1);

} // end Unload_Bitmap_File

///////////////////////////////////////////////////////////


int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
{
    // this function is used to flip upside down .BMP images

    UCHAR *buffer; // used to perform the image processing
    int index;     // looping index

    // allocate the temporary buffer
    if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
       return(0);

    // copy image to work area
    memcpy(buffer,image,bytes_per_line*height);

    // flip vertically
    for (index=0; index < height; index++)
        memcpy(&image[((height-1) - index)*bytes_per_line], &buffer[index*bytes_per_line], bytes_per_line);

    // release the memory
    free(buffer);

    // return success
    return(1);

} // end Flip_Bitmap
main.h

Code:
// Compiler Includes

#include <windows.h>   // include important windows stuff
#include <windowsx.h> 
#include <mmsystem.h>
#include <iostream> // include important C/C++ stuff
#include <conio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#include <io.h>
#include <fcntl.h>

#include <ddraw.h>


// Project Includes


// Defines

#define WINDOW_TITLE "Dexterous"

#define WINDOW_WIDTH 1280
#define WINDOW_HEIGHT 1024

#define BITS 24

#define _RGB24BIT(r,g,b) ((b) + ((g) << 8) + ((r) << 16))
#define _RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24))

#define BITMAP_ID     0x4D42      // universal id for a bitmap


// Macros

// these read the keyboard asynchronously
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

// Typedefs

// container structure for bitmaps .BMP file
typedef struct BITMAP_FILE_TAG
{
        BITMAPFILEHEADER bitmapfileheader;  // this contains the bitmapfile header
        BITMAPINFOHEADER bitmapinfoheader;  // this is all the info including the palette
        UCHAR            *buffer;           // this is a pointer to the data

} BITMAP_FILE, *BITMAP_FILE_PTR;


// Prototypes

int Game_Init(void *parms=NULL);
int Game_Shutdown(void *parms=NULL);
int Game_Main(void *parms=NULL);

void debug(char *text);

int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename);
int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap);
int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height);


// Global Variables

extern HWND g_hwnd; // save the window handle
extern HINSTANCE g_hInstance; // save the instance

extern FILE *log_file;

extern BITMAP_FILE          bitmap;            // a bitmap file
There is also another file, title Windows.cpp. That file is definately not the problem, since it's only initializing the standard window and calling the game functions.

Help is very appreciated, thanks!

P.S. I have this feeling the error or bug is in Game_Main, specifically where it tries to copy memory onto the primary surface...