Home › Forums › Programming › Quick C++ question (error fix)
- This topic has 7 replies, 4 voices, and was last updated 15 years, 4 months ago by Anonymous.
-
AuthorPosts
-
-
05/12/2008 at 11:04 pm #7055AnonymousInactive
Hey I’m back,
Just started C++ and I was following this tutorial
http://www.gamedev.net/community/forums/topic.asp?topic_id=192483&PageSize=25&WhichPage=1But I’ve run into an error and I dont know what it it means:
1>main.obj : error LNK2019: unresolved external symbol "public: void __thiscall BitMapObject::Load(struct HDC__ *,char const *)" (?Load@BitMapObject@@QAEXPAUHDC__@@PBD@Z) referenced in function "bool __cdecl GameInit(void)" (?GameInit@@YA_NXZ)
Any help? I’ve been trying for hours with no luck.
I’m using Visual Studio express 2008 C++ and a Win32 project.
Cheers.
-
05/12/2008 at 11:11 pm #43055AnonymousInactive
—
-
06/12/2008 at 12:59 am #43058AnonymousInactive
Ok here is my main.cpp
[code:1:e1b06448f2]//Tetris
//main.cpp
#ifdef UNICODE
#undef UNICODE
#endif
//tell compiler to not include many unneeded header files
#define Win32_LEAN_AND_MEAN
//need this for windows stuff
#include <windows.h>
//need this for srand and rand
#include <stdlib.h>
//now include our bitmapobject definitions
#include "bitmapobject.h"
//let’s give our window a name
#define WINDOWCLASS "FallingBlockGame"
//let’s give our window a title…er caption.
#define WINDOWTITLE "A Falling Block Game!"//since we’re using square blocks, let’s only use a single size.
const int TILESIZE=16;
//now for the map…
const int MAPWIDTH=10;
const int MAPHEIGHT=30;
const int GREY=8;
const int TILENODRAW=-1;
const int TILEBLACK=0;
const int TILEGREY=1;
const int TILEBLUE=2;
const int TILERED=3;
const int TILEGREEN=4;
const int TILEYELLOW=5;
const int TILEWHITE=6;
const int TILESTEEL=7;
const int TILEPURPLE=8;bool GameInit(); // game initialization function
void GameLoop(); //where the game actually takes place
void GameDone(); //clean up!
void DrawTile(int x, int y, int tile); //coordinates & tile type
void DrawMap(); //draw the whole map.. render function, basically
void NewBlock(); //create a new block!
void RotateBlock(); //rotate a block.. if you can!
void Move(int x, int y); //coordinates to move.
int CollisionTest(int nx, int ny); //test collision of blocks
void RemoveRow(int row); //remove a row.. that would be the ‘x’.
void NewGame(); //make a new game!HINSTANCE hInstMain=NULL; //main app handle
HWND hWndMain=NULL; //main window handleint Map[MAPWIDTH][MAPHEIGHT+1]; //the game map!
struct Piece {
int size[4][4];
int x;
int y;
};Piece sPrePiece; //preview piece.
Piece sPiece; //the ‘s’ prefixes indicate this is a ‘structure’DWORD start_time; //used in timing
bool GAMESTARTED=false; //used by NewBlock()//map for the program
BitMapObject bmoMap;
//block images
BitMapObject bmoBlocks;LRESULT CALLBACK TheWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
//which message did we get?
switch(uMsg)
{
case WM_KEYDOWN:
{
//check for escape key
if(wParam==VK_ESCAPE)
{
DestroyWindow(hWndMain);
return(0);//handled message
}
else if(wParam==VK_DOWN) //check for down arrow key
{
Move(0,1);
return(0);//handled message
}
else if(wParam==VK_UP) //check for up arrow key
{
RotateBlock();
return(0);//handled message
}
else if(wParam==VK_LEFT) //check for left arrow key
{
Move(-1,0);
return(0);//handled message
}
else if(wParam==VK_RIGHT) //check for right arrow key
{
Move(1,0);
return(0);//handled message
}
}break;
case WM_DESTROY://the window is being destroyed
{//tell the application we are quitting
PostQuitMessage(0);//handled message, so return 0
return(0);}break;
case WM_PAINT://the window needs repainting
{
//a variable needed for painting information
PAINTSTRUCT ps;//start painting
HDC hdc=BeginPaint(hwnd,&ps);//redraw the map
BitBlt(hdc,0,0,TILESIZE*MAPWIDTH+TILESIZE*GREY,TILESIZE*MAPHEIGHT,bmoMap,0,0,SRCCOPY);//end painting
EndPaint(hwnd,&ps);//handled message, so return 0
return(0);
}break;
}//pass along any other message to default message handler
return(DefWindowProc(hwnd,uMsg,wParam,lParam));
}int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
//assign instance to global variable
hInstMain=hInstance;//create window class
WNDCLASSEX wcx;//set the size of the structure
wcx.cbSize=sizeof(WNDCLASSEX);//class style
wcx.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;//window procedure
wcx.lpfnWndProc=TheWindowProc;//class extra
wcx.cbClsExtra=0;//window extra
wcx.cbWndExtra=0;//application handle
wcx.hInstance=hInstMain;//icon
wcx.hIcon=LoadIcon(NULL,IDI_APPLICATION);//cursor
wcx.hCursor=LoadCursor(NULL,IDC_ARROW);//background color
wcx.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);//menu
wcx.lpszMenuName=NULL;//class name
wcx.lpszClassName=WINDOWCLASS;//small icon
wcx.hIconSm=NULL;//register the window class, return 0 if not successful
if(!RegisterClassEx(&wcx)) return(0);//create main window
hWndMain=CreateWindowEx(0,WINDOWCLASS,WINDOWTITLE, WS_BORDER | WS_SYSMENU | WS_CAPTION| WS_VISIBLE,0,0,320,240,NULL,NULL,hInstMain,NULL);//error check
if(!hWndMain) return(0);//if program initialization failed, then return with 0
if(!GameInit()) return(0);//message structure
MSG msg;//message pump
for( ; ; )
{
//look for a message
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
//there is a message//check that we arent quitting
if(msg.message==WM_QUIT) break;//translate message
TranslateMessage(&msg);//dispatch message
DispatchMessage(&msg);
}//run main game loop
GameLoop();}
//clean up program data
GameDone();//return the wparam from the WM_QUIT message
return(msg.wParam);
}bool GameInit()
{
//set the client area size
RECT rcTemp;
SetRect(&rcTemp,0,0,MAPWIDTH*TILESIZE+TILESIZE*GREY,MAPHEIGHT*TILESIZE);//160×480 client area
AdjustWindowRect(&rcTemp,WS_BORDER | WS_SYSMENU | WS_CAPTION| WS_VISIBLE,FALSE);//adjust the window size based on desired client area
SetWindowPos(hWndMain,NULL,0,0,rcTemp.right-rcTemp.left,rcTemp.bottom-rcTemp.top,SWP_NOMOVE);//set the window width and height//create map image
HDC hdc=GetDC(hWndMain);
bmoMap.Create(hdc,MAPWIDTH*TILESIZE+TILESIZE*GREY,MAPHEIGHT*TILESIZE);
FillRect(bmoMap,&rcTemp,(HBRUSH)GetStockObject(BLACK_BRUSH));
ReleaseDC(hWndMain,hdc);bmoBlocks.Load(NULL,"blocks.bmp");
NewGame();return(true);//return success
}void GameDone()
{
//clean up code goes here
}void GameLoop()
{
if( (GetTickCount() – start_time) > 1000)
{
Move(0,1);
start_time=GetTickCount();
}}
void NewGame()
{
start_time=GetTickCount();
GAMESTARTED=false;//start out the map
for(int x=0;x< MAPWIDTH;x++)
{
for(int y=0;y< MAPHEIGHT+1;y++)
{
if(y==MAPHEIGHT) //makes Y-collision easier.
Map[x][y]=TILEGREY;
else
Map[x][y]=TILEBLACK;
}
}
NewBlock();DrawMap();
}void DrawTile(int x,int y,int tile)//put a tile
{
//mask first
BitBlt(bmoMap,x*TILESIZE,y*TILESIZE,TILESIZE,TILESIZE,bmoBlocks,tile*TILESIZE,TILESIZE,SRCAND);
//then image
BitBlt(bmoMap,x*TILESIZE,y*TILESIZE,TILESIZE,TILESIZE,bmoBlocks,tile*TILESIZE,0,SRCPAINT);
}void DrawMap()//draw screen
{
int xmy, ymx;//place the toolbar
for(xmy=MAPWIDTH; xmy< MAPWIDTH+GREY; xmy++)
for(ymx=0; ymx< MAPHEIGHT; ymx++)
DrawTile(xmy, ymx, TILEGREY);//draw preview block
for(xmy=0; xmy<4; xmy++)
for(ymx=0; ymx<4; ymx++)
if(sPrePiece.size[xmy][ymx] != TILENODRAW)
DrawTile(sPrePiece.x+xmy, sPrePiece.y+ymx, sPrePiece.size[xmy][ymx]);//draw the map
//loop through the positions
for(xmy=0;xmy< MAPWIDTH;xmy++)
for(ymx=0;ymx< MAPHEIGHT;ymx++)
DrawTile(xmy,ymx,Map[xmy][ymx]);//draw moving block
for(xmy=0; xmy<4; xmy++)
for(ymx=0; ymx<4; ymx++)
if(sPiece.size[xmy][ymx] != TILENODRAW)
DrawTile(sPiece.x+xmy, sPiece.y+ymx, sPiece.size[xmy][ymx]);//invalidate the window rect
InvalidateRect(hWndMain,NULL,FALSE);
}void NewBlock()
{
int newblock;
int i,j;
// 0 1 2 3 4 5 6
// X These
// X XX X XX XX XX XX are
// X XX XXX XX XX X X block
// X X X types//begin game! make generate a block and then one in preview.
srand(GetTickCount());
//initialize the piece to all blank.
for(i=0; i<4; i++)
for(j=0; j<4; j++)
sPiece.size[ i ][j]=TILENODRAW;sPiece.x=MAPWIDTH/2-2;
sPiece.y=-1;//let’s see if the game’s started yet
if(GAMESTARTED == false)
{
//guess not..
//Generate a piece right off.
//From now on, use previous preview block.
GAMESTARTED=true;newblock=rand()%7;
switch (newblock)
{
case 0: //Tower!
{
sPiece.size[1][0]=TILERED;
sPiece.size[1][1]=TILERED;
sPiece.size[1][2]=TILERED;
sPiece.size[1][3]=TILERED;
sPiece.y=0;
}break;
case 1: //Box!
{
sPiece.size[1][1]=TILEBLUE;
sPiece.size[1][2]=TILEBLUE;
sPiece.size[2][1]=TILEBLUE;
sPiece.size[2][2]=TILEBLUE;
}break;
case 2: //Pyramid!
{
sPiece.size[1][1]=TILESTEEL;
sPiece.size[0][2]=TILESTEEL;
sPiece.size[1][2]=TILESTEEL;
sPiece.size[2][2]=TILESTEEL;
}break;
case 3://Left Leaner
{
sPiece.size[0][1]=TILEYELLOW;
sPiece.size[1][1]=TILEYELLOW;
sPiece.size[1][2]=TILEYELLOW;
sPiece.size[2][2]=TILEYELLOW;
}break;
case 4://Right Leaner
{
sPiece.size[2][1]=TILEGREEN;
sPiece.size[1][1]=TILEGREEN;
sPiece.size[1][2]=TILEGREEN;
sPiece.size[0][2]=TILEGREEN;
}break;
case 5://Left Knight
{
sPiece.size[1][1]=TILEWHITE;
sPiece.size[2][1]=TILEWHITE;
sPiece.size[2][2]=TILEWHITE;
sPiece.size[2][3]=TILEWHITE;
}break;
case 6://Right Knight
{
sPiece.size[2][1]=TILEPURPLE;
sPiece.size[1][1]=TILEPURPLE;
sPiece.size[1][2]=TILEPURPLE;
sPiece.size[1][3]=TILEPURPLE;
}break;
}
}
else
{
for(i=0; i<4; i++)
for(j=0; j<4; j++)
sPiece.size[ i ][j]=sPrePiece.size[ i ][j];}
newblock=rand()%7;
for(i=0; i<4; i++)
for(j=0; j<4; j++)
sPrePiece.size[ i ][j]=TILENODRAW;sPrePiece.x=MAPWIDTH+GREY/4;
sPrePiece.y=GREY/4;switch (newblock)
{
case 0: //Tower!
{
sPrePiece.size[1][0]=TILERED;
sPrePiece.size[1][1]=TILERED;
sPrePiece.size[1][2]=TILERED;
sPrePiece.size[1][3]=TILERED;
}break;
case 1: //Box!
{
sPrePiece.size[1][1]=TILEBLUE;
sPrePiece.size[1][2]=TILEBLUE;
sPrePiece.size[2][1]=TILEBLUE;
sPrePiece.size[2][2]=TILEBLUE;
}break;
case 2: //Pyramid!
{
sPrePiece.size[1][1]=TILESTEEL;
sPrePiece.size[0][2]=TILESTEEL;
sPrePiece.size[1][2]=TILESTEEL;
sPrePiece.size[2][2]=TILESTEEL;
}break;
case 3://Left Leaner
{
sPrePiece.size[0][1]=TILEYELLOW;
sPrePiece.size[1][1]=TILEYELLOW;
sPrePiece.size[1][2]=TILEYELLOW;
sPrePiece.size[2][2]=TILEYELLOW;
}break;
case 4://Right Leaner
{
sPrePiece.size[2][1]=TILEGREEN;
sPrePiece.size[1][1]=TILEGREEN;
sPrePiece.size[1][2]=TILEGREEN;
sPrePiece.size[0][2]=TILEGREEN;
}break;
case 5://Left Knight
{
sPrePiece.size[1][1]=TILEWHITE;
sPrePiece.size[2][1]=TILEWHITE;
sPrePiece.size[2][2]=TILEWHITE;
sPrePiece.size[2][3]=TILEWHITE;
}break;
case 6://Right Knight
{
sPrePiece.size[2][1]=TILEPURPLE;
sPrePiece.size[1][1]=TILEPURPLE;
sPrePiece.size[1][2]=TILEPURPLE;
sPrePiece.size[1][3]=TILEPURPLE;
}break;
}DrawMap();
}void RotateBlock()
{
int i, j, temp[4][4];//copy &rotate the piece to the temporary array
for(i=0; i<4; i++)
for(j=0; j<4; j++)
temp[3-j][ i ]=sPiece.size[ i ][j];//check collision of the temporary array with map borders
for(i=0; i<4; i++)
for(j=0; j<4; j++)
if(temp[ i ][j] != TILENODRAW)
if(sPiece.x + i < 0 || sPiece.x + i > MAPWIDTH – 1 ||
sPiece.y + j < 0 || sPiece.y + j > MAPHEIGHT – 1)
return;//check collision of the temporary array with the blocks on the map
for(int x=0; x< MAPWIDTH; x++)
for(int y=0; y< MAPHEIGHT; y++)
if(x >= sPiece.x && x < sPiece.x + 4)
if(y >= sPiece.y && y < sPiece.y +4)
if(Map[x][y] != TILEBLACK)
if(temp[x – sPiece.x][y – sPiece.y] != TILENODRAW)
return;//end collision check
//successful! copy the rotated temporary array to the original piece
for(i=0; i<4; i++)
for(j=0; j<4; j++)
sPiece.size[ i ][j]=temp[ i ][j];DrawMap();
return;
}void Move(int x, int y)
{
if(CollisionTest(x, y))
{
if(y == 1)
{
if(sPiece.y<1)
{
//you lose! new game.
NewGame();
}
else
{
bool killblock=false;
int i,j;
//new block time! add this one to the list!
for(i=0; i<4; i++)
for(j=0; j<4; j++)
if(sPiece.size[ i ][j] != TILENODRAW)
Map[sPiece.x+i][sPiece.y+j] = sPiece.size[ i ][j];//check for cleared row!
for(j=0; j< MAPHEIGHT; j++)
{
bool filled=true;
for(i=0; i< MAPWIDTH; i++)
if(Map[ i ][j] == TILEBLACK)
filled=false;if(filled)
{
RemoveRow(j);
killblock=true;
}
}if(killblock)
{
for(i=0; i<4; i++)
for(j=0; j<4; j++)
sPiece.size[ i ][j]=TILENODRAW;
}
NewBlock();
}
}}
else
{
sPiece.x+=x;
sPiece.y+=y;
}DrawMap();
}int CollisionTest(int nx, int ny)
{
int newx=sPiece.x+nx;
int newy=sPiece.y+ny;int i,j,x,y;
for(i=0; i< 4; i++)
for(j=0; j< 4; j++)
if(sPiece.size[ i ][j] != TILENODRAW)
if(newx + i < 0 || newx + i > MAPWIDTH – 1 ||
newy + j < 0 || newy + j > MAPHEIGHT – 1)
return 1;for(x=0; x< MAPWIDTH; x++)
for(y=0; y< MAPHEIGHT; y++)
if(x >= newx && x < newx + 4)
if(y >= newy && y < newy +4)
if(Map[x][y] != TILEBLACK)
if(sPiece.size[x – newx][y – newy] != TILENODRAW)
return 1;
return 0;
}void RemoveRow(int row)
{
int x,y;
int counter=0;for(x=0; x< MAPWIDTH; x++)
for(y=row; y>0; y–)
Map[x][y]=Map[x][y-1];}[/code:1:e1b06448f2]
Here is bitmapobject.cpp
[code:1:e1b06448f2]
//BitMapObject.cpp
#include "bitmapobject.h"BitMapObject::BitMapObject()
{
hdcMemory=NULL;
hbmNewBitMap=NULL;
hbmOldBitMap=NULL;
iWidth=0;
iHeight=0;
}BitMapObject::~BitMapObject()
{
//if the hdcMemory hasn’t been destroyed, do so
if(hdcMemory)
Destroy();
}void BitMapObject::Load(HDC hdcCompatible, LPCTSTR lpszFilename)
{
//if hdcMemory isn’t null, make it so captain!
if(hdcMemory)
Destroy();//create memory dc.
hdcMemory=CreateCompatibleDC(hdcCompatible);
//load the bitmap
hbmNewBitMap=(HBITMAP)LoadImage(NULL,lpszFilename,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
//shove the image into the dc
hbmOldBitMap=(HBITMAP)SelectObject(hdcMemory,hbmNewBitMap);
//grab the bitmap’s properties
BITMAP bmp;
GetObject(hbmNewBitMap,sizeof(BITMAP),(LPVOID)&bmp);
//grab the width & height
iWidth=bmp.bmWidth;
iHeight=bmp.bmHeight;
}void BitMapObject::Create(HDC hdcCompatible, int width, int height)
{
//if hdcMemory isn’t null, blow it up!
if(hdcMemory)
Destroy();//create the memory dc.
hdcMemory=CreateCompatibleDC(hdcCompatible);
//create the bitmap
hbmNewBitMap=CreateCompatibleBitmap(hdcCompatible, width, height);
//shove the image into the dc
hbmOldBitMap=(HBITMAP)SelectObject(hdcMemory, hbmNewBitMap);
//change the width and height.
iWidth=width;
iHeight=height;
}void BitMapObject::Destroy()
{
//restore old bitmap.
SelectObject(hdcMemory, hbmOldBitMap);
//delete new bitmap.
DeleteObject(hbmNewBitMap);
//delete device context.
DeleteDC(hdcMemory);
//set members to 0/NULL
hdcMemory=NULL;
hbmNewBitMap=NULL;
hbmOldBitMap=NULL;
iWidth=0;
iHeight=0;
}BitMapObject::operator HDC()
{
//return hdcMemory.
return(hdcMemory);
}int BitMapObject::GetWidth()
{
//return width
return(iWidth);
}int BitMapObject::GetHeight()
{
//return height
return(iHeight);
}[/code:1:e1b06448f2]and here is the bitmapobject.h
[code:1:e1b06448f2]//BitMapObject.h
#ifndef BITMAPOBJECT_H
#define BITMAPOBJECT_H
#pragma once
//we need this for windows stuff.
#include <windows.h>class BitMapObject
{
private:
//memory dc
HDC hdcMemory;
//new bitmap!
HBITMAP hbmNewBitMap;
//old bitmap.
HBITMAP hbmOldBitMap;
//width & height as integers.
int iWidth;
int iHeight;public:
//constructor
BitMapObject();//destructor
~BitMapObject();//loads bitmap from a file
void Load(HDC hdcCompatible,LPCTSTR lpszFilename);//creates a blank bitmap
void Create(HDC hdcCompatible, int width, int height);//destroys bitmap and dc
void Destroy();//return width
int GetWidth();//return height
int GetHeight();//converts to HDC
operator HDC();
};[/code:1:e1b06448f2]Sorry for this ridiculously long post.
Any help appreciated thanks!
-
06/12/2008 at 1:40 am #43059AnonymousInactive
—
-
06/12/2008 at 5:44 pm #43063AnonymousInactive
Hey, Just back from DIT open day,
Sorry that was a miss by me, I had #endif at the end must of missed it when copying.
Anyway what program are using and what proj type did you put it in.
1>main.obj : error LNK2019: unresolved external symbol "public: void __thiscall BitMapObject::Load(struct HDC__ *,char const *)" (?Load@BitMapObject@@QAEXPAUHDC__@@PBD@Z) referenced in function "bool __cdecl GameInit(void)" (?GameInit@@YA_NXZ)
Thats the error I get in visual studio express 2008.
Again, any help appreciated
-
06/12/2008 at 6:19 pm #43064AnonymousInactive
Found your problem. Seems to be a conflict between unicode and mult-byte character sets.
Some parts of your program are using Unicode, others are using standard 8-bit chars.. Your project setting is at unicode but your main.cpp file is forcing multi-byte with the #ifdef UNICODE block of preprocessor statements. The meaning of LPCSTR is thus changing from const char * to const * wchar_t, i.e from 8-bit to 16-bit chars, which is producing differing declarations of your functions in different parts of the code. Thats why the linker was unable to find your function, it was declared under one name and implemented under another.
There are two ways of solving this problem:
1 – Stick this statement into your BitmapObject.h file – just below the include guard (the #ifdef BITMAPOBJECT_H statments) and BEFORE the #include <Windows.h>:
#ifdef UNICODE
#undef UNICODE
#endif2 – Change the project settings so only the multi-byte (8-bit) character set is used. Right click on the project item in the solution explorer and click on ‘properties’. Under ‘configuration properties’ and ‘general’ set the ‘character set’ property from ‘Use unicode character set’ to ‘Use multi-byte character set’
The second solution is much better because you’ll only have to do it once for your program. If you opt for the first you’ll have to remember to disable unicode for every source and header you create. Also it’s not a good idea to force a character set from within source code, because it makes difficult to change later.
Let us know if you run into any more difficulties.
-
06/12/2008 at 6:30 pm #43065AnonymousInactive
Legend!!
Thank you that was driving me insane.
Cheers Thane aswell for your input.
-
06/12/2008 at 10:42 pm #43066AnonymousInactive
Jeebus…you guys are somethin else. *bows down* That is CRAZY. Can’t make heads or tails of it. I guess programmers are just wired differently :D
-
-
AuthorPosts
- The forum ‘Programming’ is closed to new topics and replies.