Contents
- Introduction
- The name of Nura Quadris
- The rules of Nura Quadris
- The features of Nura Quadris
- The usage of Nura Quadris
- Background
- The source code
- Environment
- Using the code
- Entire Structure
- The Classes CMainFrame and CQuadrisWTLView
- The Class QuadrisWindowWTL
- The user-defined Message NM_QUADRIS (= UM_QUADRIS) of QuadrisWindowWTL
- The Class NextWindow
- The Class QuadrisCore
- How to support Win95, Win98, Win98SE and WinME
- How to embed a help function
- Points of Interest
- Quadris Customizer
- Acknowledgement
Introduction
Nura Quadris is a computer game where user must stack bricks and fill a whole row or rows to clear them. We call it "Quadris" when we clear four rows at once like we call "strike" in bowling when we hit all the pins at once. Nura is my wife's name. So, I named my program Nura Quadris. Nur means light in Arabic, and -a is a feminine suffix, so that Nura can mean bright lady. It is a very popular Arabic name of women in Middle East.
The rules of Nura Quadris are same as the rules of the normal Quadris game. The rule is as follows:
- A brick is made of four blocks.
- When a brick falls down, you shall turn it and/or shift it left or right in order to make it fit to stacked bricks before it lands on the stacked bricks.
- When it lands on the stacked bricks, if whole a row or rows are fully filled, the filled row(s) will be cleared and the brick(s) stacked on the cleared row(s) will come down to fill the empty row(s).
- Then, a new brick will fall down.
- It automatically detects the language of Windows, and shows all the instructions in either Korean or English. If your Windows is Korean Windows, it will have Korean mode, but if it is non-Korean Windows, it will have English mode. However, you can customize Nura Quadris into your language by using NuraQuadris.ini. You can generate NuraQuadris.ini by using QuadrisCustomizer.exe. I will introduce QuadrisCustomizer.exe later.
- It has the option to show a helping grid. The default is showing no grid.
- It has the option to make sounds. The default is making sounds.
- It has the option to show a next brick in advance. The default is showing a next brick in advance.
- Before you start the game, if you press the key 'F1', you can get help-information. If you press the key 'F12', an About-message box will pop up. You can see simple information about Nura Quadris there.
- To start the game, click the button "Start".
- During the game, if you want to cancel the game, click the button "Cancel".
- During the game, if you want to pause the game, click the button "Pause". And then, if you want to continue the game again, click the button "Continue".
- If you want helping grid, check "Grid" option.
- If you do not want sound, check "Mute" option.
- Press Up-arrow key to rotate the brick.
- Press Left-arrow key to shift the brick left.
- Press Right-arrow key to shift the brick right.
- Press Down-arrow key to move the brick down faster.
- Press Space-bar key to drop down the brick to the bottom.
Background
It includes five things: a Quadris engine, a control-like window, a next window, a view window and a skin window. I will give some brief descriptions about those things in this article. I used a design pattern: the Bridge Pattern (exactly speaking, a modified version of the Bridge Pattern), but I would not explain about design pattern here.
This source code uses the WTL library. The source code includes four projects: QuadrisCore, QuadrisWindowWTL, NuraQuadris (in the QuadrisWTL folder), and QuadrisCustomizer. The project QuadrisCore is the library of the Quadris engine. QuadrisWindowWTL is the control-like window of the Quadris window for WTL. The project NuraQuadris is the executable project which is actually a Quadris game program. But, it does not use the library of Quadris window but, here to make things simple, uses the sources of Quadris window and Quadris core directly. Finally, the project QuadrisCustomizer is the executable project which is a language customizer for NuraQuadris.
Environment
Nura Quadris was created with VC++ .NET 2003 Standard Edition SP1 (hereinafter, referred to as VC++ 7.1) with WTL 8.0. You can get WTL 8.0 from here unless the website is changed. It was mainly tested under Windows XP SP2, Windows 2000 SP4 and Windows 98 SE. To compile the source code, you need to have WTL installed. Also, it can be compiled with either VC++ 2005 Express Edition (hereinafter, referred to as VC++ 8.0X) or VC++ 2008 Express Edition (hereinafter, referred to as VC++ 9.0X). Of course, you have to take some steps before compiling it. It is disclosed here about using VC++ 8.0X for Windows programming, and here about WTL installation for VC++ 8.0X. To use WTL 8.0 for VC++ 9.0X by creating WTL-App wizzard in VC++ 9.0X, put setup90x.js in the folder "AppWiz" of installed WTL 8.0 and use it, which I created by tweaking setup80x.js. To make it be able to be compiled with VC++ 8.0X or VC++ 9.0X which uses ATL 3.0, I made ATLVersion.h and included it in stdafx.h. Quadris.sln is for VC++ 7.1 while Quadris2008.sln is for VC++ 9.0X. QuadrisWTL.vcproj is for VC++ 7.1 while QuadrisWTL2008.vcproj is for VC++ 9.0X. All the file name conventions for solution files (*.sln) and project files (*.vcproj) are the same as the above examples.
I have mentioned that Nura Quadris consists of five parts: a Quadris engine, a control-like window, a next window, a view window and a skin window. The skin window is a SDI application framework itself, and it contains a view window as its child window. The skin window is implemented by a class CMainFrame
. The view window contains the control-like window and the next window as its child windows, and it is implemented by a class CQuadrisWTLView
. The control-like window is the Quadris game window itself, and is implemented by the class QuadrisWindowWTL
. The reason why I call this window control-like window is that this window is not actually a control but it functions as a control. The control-like window contains the Quadris engine. The Quadris engine is implemented by the classes QuadrisCore
. The next window is the window which shows the next brick in advance while the Quadris game is going on, and is implemented by the class NextWindow
.
The class CMainFrame
and CQuadrisWTLView
are provided by the WTL-App Wizard, and I coded on them. CQuadrisWTLView
receives the user-defined message NM_QUADRIS
(in this case, UM_QUADRIS
) from QuadrisWindowWTL
. Its member function OnQuadrisMessage
will deal with the message UM_QUADRIS
. The following code is related with the processing of the user-defined message UM_QUADRIS
.
LRESULT CQuadrisWTLView::OnQuadrisMessage (UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case TN_NEXT: OnNext(lParam); break;
case TN_PURGE: OnPurge((int) lParam); break;
case TN_FINISH: OnFinish((int) lParam); break;
}
return 0;
}
void CQuadrisWTLView::OnPurge (int lines)
{
TCHAR str[STRINGMAX];
_stprintf(str, m_strScore, m_pQuadris->GetScore());
m_Score.SetWindowText(str);
}
void CQuadrisWTLView::OnFinish (int score)
{
m_Start.ShowWindow(SW_SHOW);
m_Cancel.ShowWindow(SW_HIDE);
m_Pause.ShowWindow(SW_HIDE);
m_Continue.ShowWindow(SW_HIDE);
m_pNext->PostMessage(UM_QUADRIS, TN_FINISH, (LPARAM) score);
}
void CQuadrisWTLView::OnNext (LPARAM lParam)
{
m_pNext->PostMessage(UM_QUADRIS, TN_NEXT, lParam);
}
It also receives instructions from users through push buttons and check buttons. If you want to set the language to be English regardless the system language of your Windows, uncomment the statements of line 62 in stdafx.h in the folder QuadrisWTL, as follows:
#define Quadris_LANG LANG_ENGLISH
It uses a user-defined message: NM_QUADRIS
(exactly speaking, m_Message
or UM_QUADRIS
, in this case). QuadrisWindowWTL
sends NM_QUADRIS
to QuadrisWTLView
whenever a new brick falls and/or whenever fully filled row(s) is/are cleared. It will also send NM_QUADRIS
to QuadrisWTLView
when the game is over. To avoid message conflicts in QuadrisWTLView
, the constructor of QuadrisWindowWTL
can receive a different value for the user-defined message of NM_QUADRIS
as a parameter and keep it in m_Message
. QuadrisWindowWTL
is very loosely bound to QuadrisWTLView
. The public member functions of QuadrisWindowWTL
are as follows:
class QuadrisWindowWTL : public CWindowImpl<QuadrisWindowWTL>
{
...
public:
QuadrisWindowWTL (UINT message = NM_QUADRIS, bool bAuto = true);
QuadrisWindowWTL (UINT message, int lang, bool bAuto);
virtual ~QuadrisWindowWTL (void);
...
inline bool Start (void) { return StartStop(true); }
inline bool Stop (void) { return StartStop(false); }
inline bool Pause (void) { return PauseContinue(true); }
inline bool Continue (void) { return PauseContinue(false); }
inline int GetScore (void) { return m_pQuadris->GetScore(); }
inline int GetLevel (void) { return m_Level; }
inline void SetGrid (bool bGrid = true) { m_bGrid = bGrid; }
inline void SetSound (bool bSound = true) { m_bSound = bSound; }
inline int GetSpeed (void) { return m_Interval; }
bool SetSpeed (int interval);
HWND Create (HWND hParentWnd, int x, int y, UINT nID);
HWND Create (HWND hParentWnd, const POINT& pt, UINT nID);
HWND Create (HWND hParentWnd, int x, int y, int nWidth, int nHeight, UINT nID);
HWND Create (HWND hParentWnd, const RECT& rect, UINT nID);
HWND Create (HWND hParentWnd, int x, int y,
DWORD dwStyle, DWORD dwExStyle, UINT nID);
HWND Create (HWND hParentWnd, const POINT& pt,
DWORD dwStyle, DWORD dwExStyle, UINT nID);
HWND Create (HWND hParentWnd, int x, int y, int nWidth, int nHeight,
DWORD dwStyle, DWORD dwExStyle, UINT nID);
HWND Create (HWND hParentWnd, const RECT& rect,
DWORD dwStyle, DWORD dwExStyle, UINT nID);
BOOL Move (int x, int y, BOOL bRepaint = TRUE);
BOOL Move (POINT& pt, BOOL bRepaint = TRUE);
BOOL Move (int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE);
BOOL Move (RECT& rect, BOOL bRepaint = TRUE);
...
}
QuadrisWindowWTL (UINT message = NM_QUADRIS, bool bAuto = true);
- It is a constructor.
- The first parameter
message
is the message which QuadrisWindowWTL
will sent to the parent window. To avoid message conflict, you can give a different value for the message. The default is NM_QUADRI
S.
- The second parameter is whether it deals with the end process by itself or not. If the second parameter
bAuto
is set to be true
, it would not send NM_QUADRI
S (or the message you gave) to the parent window and it will deal with the end process. The default is true
.
- Language will be automatically chosen according to the default system language of Windows.
QuadrisWindowWTL (UINT message, int lang, bool bAuto);
- It is another constructor.
- The first and third parameters are the same as described above.
- The second parameter
lang
is for the language. If you set it to be LANG_ENGLISH
, it will use Korean regardless of the default language of Windows.
inline bool Start (void);
- It makes the Quadris game start.
- The return value is
true
when the game starts, and is false
when it fails.
inline bool Stop (void);
- It makes the Quadris game stop.
- The return value is
true
when the game stops, and is false
when it fails.
inline bool Pause (void);
- It makes the Quadris game pause.
- The return value is
true
when the game is paused and is false
when it fails.
inline bool Continue (void);
- It makes the Quadris game continue.
- The return value is
true
when the game is continued and is false
when it fails.
inline int GetScore (void);
- It gives the current score of Quadris game.
- The return value is the current score.
inline int GetLevel (void);
- It gives the current level of Quadris game.
- The return value is the current level.
inline void SetGrid (bool bGrid = true);
- It determines whether the Quadris Window have helping grids or not.
- If the parameter
bGrid
is true
, the Quadris Window will have helping grids. If the parameter bGrid
is false
, the Quadris Window will have no helping grids.
inline void SetSound (bool bSound = true);
- It determines whether the Quadris Window makes effect sounds.
- If the parameter
bSound
is true
, the Quadris Window will make effect sounds. If he parameter bSound
is false
, the Quadris Window will not make effect sounds.
inline int GetSpeed (void);
- It gives the current speed of Quadris game.
- The return value is the current speed.
bool SetSpeed (int interval);
- It sets the speed.
- The parameter
interval
is the interval between moving. It is in the unit of milliseconds.
HWND Create (HWND hParentWnd, const RECT& rect, DWORD dwStyle, DWORD dwExStyle, UINT nID);
- It creates Quadris control-like Window. Its window class name is
Quadris_CLASS
, which is defined as "Quadris" for ASCII code, and L"Quadris" for UNICODE.
- The return value is the window handle to the Quadris window.
- The first parameter
hParentWnd
is the window handle to its parent window.
- The second parameter
rect
is the reference to the rectangle of the Quadris window.
- The third parameter
dwStyle
is the window style of the Quadris window.
- The fourth parameter
dwExStyle
is the extended window style of the Quadris window.
- The fifth parameter
nID
is the ID given to the Quadris window.
HWND Create (HWND hParentWnd, const POINT& pt, DWORD dwStyle, DWORD dwExStyle, UINT nID);
- It creates the Quadris control-like Window. Its window class name is
Quadris_CLASS
, which is defined as "Quadris" for ASCII code, and L"Quadris" for UNICODE.
- The return value is the window handle to the Quadris window.
- The first parameter
hParentWnd
is the window handle to its parent window.
- The second parameter
pt
is the reference to the left-top point of the Quadris window. Its width and height will be both determined to be 400 pixels.
- The third parameter
dwStyle
is the window style of the Quadris window.
- The fourth parameter
dwExStyle
is the extended window style of the Quadris window.
- The fifth parameter
nID
is the ID given to the Quadris window.
HWND Create (HWND hParentWnd, const RECT& rect, UINT nID);
- It creates the Quadris control-like Window. Its window class name is
Quadris_CLASS
, which is defined as "Quadris" for ASCII code, and L"Quadris" for UNICODE.
- The return value is the window handle to the Quadris window.
- The first parameter
hParentWnd
is the window handle to its parent window.
- The second parameter
rect
is the reference to the rectangle of the Quadris window.
- The third parameter
nID
is the ID given to the Quadris window.
- The style and the extended style of the Quadris window are both
NULL
, by default.
HWND Create (HWND hParentWnd, const POINT& pt, UINT nID);
- It creates Quadris control-like Window. Its window class name is
Quadris_CLASS
, which is defined as "Quadris" for ASCII code, and L"Quadris" for UNICODE.
- The return value is the window handle to the Quadris window.
- The first parameter
hParentWnd
is the window handle to its parent window.
- The second parameter
pt
is the reference to the left-top point of the Quadris window. Its width and height will be both determined to be 400 pixels.
- The third parameter
nID
is the ID given to the Quadris window.
- The style and the extended style of the Quadris window are both
NULL
, by default.
BOOL Move (int x, int y, BOOL bRepaint = TRUE);
- It moves the window to the specified position.
- The return value is
true
if it succeeds, and false
if it fails.
- The first and second parameters
x
and y
are the left-top position of the Quadris window.
- The third parameter
bRepaint
is related to whether the Quadris window will be redrawn when it moves. If bRepaint
is true, the Quadris window will be redrawn. If bRepaint
is false, the Quadris window will not be redrawn. The default of bRepaint
is true
.
- The width and height of the Quadris window will be retained as before.
BOOL Move (POINT& pt, BOOL bRepaint = TRUE);
- It moves the window to the specified position.
- The return value is
true
if it succeeds, and false
if it fails.
- The first parameter
pt
is the left-top position of the Quadris window.
- The second parameter
bRepaint
is related to whether the Quadris window will be redrawn when it moves. If bRepaint
is true
, the Quadris window will be redrawn. If bRepaint
is false
, the Quadris window will not be redrawn. The default of bRepaint
is true
.
- The width and height of the Quadris window will be retained as before.
BOOL Move (int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE);
- It moves the window to the specified position.
- The return value is
true
if it succeeds, and false
if it fails.
- The first, second, third, and fourth parameters
x
, y
, nWidth
, nHeight
are the Quadris window's position.
- The fifth parameter
bRepaint
is related to whether the Quadris window will be redrawn when it moves. If bRepaint
is true
, the Quadris window will be redrawn. If bRepaint
is false
, the Quadris window will not be redrawn. The default of bRepaint
is true
.
BOOL Move (RECT& rect, BOOL bRepaint = TRUE);
- It moves the window to the specified position.
- The return value is
true
if it succeeds, and false
if it fails.
- The first parameter
rect
is the reference to the Quadris window's position.
- The second parameter
bRepaint
is related to whether the Quadris window will be redrawn when it moves. If bRepaint
is true
, the Quadris window will be redrawn. If bRepaint
is false
, the Quadris window will not be redrawn. The default of bRepaint
is true
.
The patterns of Create(...) and Move(...) are the same as those of Nura Tritris. I prefer these patterns of the functions Create(...) and Move(...).
The user-defined message NM_QUADRIS (= UM_QUADRIS in this case) has WPARAM as a notice code and LPARAM as the information related with the notice code. The notice codes are defined in QuadrisWindowWTL.h. The notice code is as follows:
<< Table of User-defined Message NM_QUADRIS (= UM_QUADRIS) >>
WPARAM (notice code)
|
LPARAM
|
Description
|
TN_FINISH
|
Score
|
To inform of the end of game
|
TN_NEXT
|
HDC for Next window to do double buffering
|
To inform of the next brick
|
TN_PURGE
|
The number of purged lines
|
To inform of clearing line(s)
|
TN_LEVEL
|
New level
|
Reserved for the future
|
TN_START
|
Not determined yet
|
Reserved for the future
|
TN_STOP
|
Not determined yet
|
Reserved for the future
|
TN_PAUSE
|
Not determined yet
|
Reserved for the future
|
TN_CONTINUE
|
Not determined yet
|
Reserved for the future
|
TN_GRID
|
Not determined yet
|
Reserved for the future
|
TN_SOUND
|
Not determined yet
|
Reserved for the future
|
TN_SHOWNEXT
|
Not determined yet
|
Reserved for the future
|
It is the window to show the next brick. It receives a user-defined messages: NM_QUADRIS
(exactly speaking, m_Message
or UM_QUADRIS
, in this case). If QuadrisWindowWTL
sends NM_QUADRIS
with the notice code TN_NEXT
or TN_FINISH
as WPARAM
to QuadrisWTLView
, QuadrisWTLView
sends them to NextWindow
. This is the way in which two different windows QuadrisWindowWTL
and NextWindow
communicate with each other. NextWindow
shows the next brick by StretchBlt(...)
using a handle to Device Context (HDC) which is passed through LPARAM. See LRESULT NextWindow::OnPaint(...)
. The related source of NextWindow is as follows:
LRESULT NextWindow::OnQuadrisMessage (UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case TN_NEXT: OnNext((HDC) lParam); break;
case TN_FINISH: OnFinish(); break;
}
return 0;
}
void NextWindow::OnNext (HDC hDC)
{
m_hDC = hDC;
Invalidate();
}
void NextWindow::OnFinish (void)
{
m_hDC = NULL;
Invalidate();
}
LRESULT NextWindow::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (!m_hDC)
{
SetMsgHandled(FALSE);
return 0;
}
CPaintDC dc(m_hWnd);
CRect rc;
GetClientRect(rc);
dc.StretchBlt(0, 0, rc.Width(), rc.Height(), m_hDC,
0, 0, Quadris_NEXTBMWIDTH, Quadris_NEXTBMHEIGHT, SRCCOPY);
return 0;
}
The handle to Device Context (HDC) which is passed through LPARAM has been already prepared by QuadrisWindowWTL::DrawNext(void)
. The functions Create(...)
and Move(...)
have the same patterns as those of QuadrisWindowWTL.
Quadris algorithm is such a famous algorithm that I do not have to explain all the member functions. Instead, I would explain the usage of the public member functions of QuadrisCore.
class QuadrisCore
{
...
public:
QuadrisCore (int width, int height, int colors);
~QuadrisCore (void);
inline char GetBoard (int x, int y) { return Board(x, y); }
inline LOCATION GetCurLoc () { return m_Pos; }
inline int GetScore () { return m_Score; }
inline int GetCurCol () { return m_CurCol; }
inline int GetNextCol () { return m_NextCol; }
inline int GetLoopStep () { return (int) m_LoopStep; }
inline BLOCK* GetCurBrick () { return (BLOCK*) &m_Brick[m_CurBrick]; }
inline BLOCK* GetNextBrick () { return (BLOCK*) &m_Brick[m_NextBrick]; }
void InitGame (void);
bool RotateBrick (bool bClockwise = true);
bool ShiftLeft (void);
bool ShiftRight (void);
bool ShiftDown (void);
void PullDown (void);
bool Shuffle (void);
int Loop ();
};
QuadrisCore (int width, int height, int colors);
- It is a constructor.
- The first parameter
width
is the width of the inside of the Quadris board.
- The second parameter
height
is the height of the inside of the Quadris board.
- The third parameter
colors
is the number of the colours of the bricks.
inline char GetBoard (int x, int y);
- It gives one cell of the Quadris board.
- The first parameter
x
is x-coordinate.
- The second parameter
y
is y-coordinate.
- The return value is one of WALL (= -1), BLANK (= 0) and BRICK (= 1, 2, ...).
inline LOCATION GetCurLoc () ;
- It gives the current position of a falling brick.
- The return value is the current position of the falling brick in the form of
struct LOCATION
. struct LOCATION
is as follows:
struct LOCATION
{
char x, y;
LOCATION (void) {}
LOCATION (char xx, char yy) : x(xx), y(yy) {}
LOCATION operator+ (LOCATION loc) { return LOCATION(x + loc.x, y + loc.y); }
LOCATION operator- (LOCATION loc) { return LOCATION(x - loc.x, y - loc.y); }
LOCATION operator+= (LOCATION loc) { x += loc.x; y += loc.y; return *this; }
LOCATION operator-= (LOCATION loc) { x -= loc.x; y -= loc.y; return *this; }
};
inline int GetScore ();
- It gives the current score.
inline int GetCurCol ();
- It gives the colour of the current falling brick.
- The return value is 1 ~ colors which is the third parameter of constructor.
inline int GetNextCol ();
- It gives the colour of the next waiting brick.
- The return value is 1 ~ colors which is the third parameter of constructor.
inline int GetLoopStep ();
- It gives the current loop step.
- The return value is one of
QUADRIS_LOOPNEW
, QUADRIS_LOOPFALL
, QUADRIS_LOOPUPDATE
, QUADRIS_LOOPCLEAR
, QUADRIS_LOOPPURGE
, and QUADRIS_LOOPEND
.
inline BLOCK* GetCurBrick ();
- It gives the set of four blocks of the current falling brick.
- The return value is the array which has four elements of
struct BLOCK
. the struct BLOCK
is as follows:
typedef LOCATION BLOCK;
inline BLOCK* GetNextBrick ();
- It gives the set of four blocks of the next waiting brick.
- The return value is the array which has four elements of
struct BLOCK
.
void InitGame (void);
- It initializes all the variables and initiates the Quadris game.
bool RotateBrick (bool bClockwise = true);
- It rotate the current brick.
- The parameter
bClockwise
determines the rotation direction. If bClockwise
is true, it rotates clockwise. If bClockwise
is false, it rotates counterclockwise.
- The return value is true if the brick rotated while the return value is false if the brick did not rotate.
bool ShiftLeft (void);
- It moves the brick left.
- The return value is true if the brick moved left while the return value is false if the brick did not move left.
bool ShiftRight (void);
- It moves the brick right.
- The return value is true if the brick moved right while the return value is false if the brick did not move right.
bool ShiftDown (void);
- It moves the brick right.
- The return value is true if the brick moved down while the return value is false if the brick did not move down. If the return value is false, it means that the brick landed.
void PullDown (void);
- It drop the brick down quickly.
bool Shuffle (void);
- It moves the stacked bricks left or right.
- The return value is true if it moved. The return value is false if it did not move.
int Loop ();
- It makes the Quadris go by one step.
- The return value is the next step status. It is one of
QUADRIS_LOOPNEW
, QUADRIS_LOOPFALL
, QUADRIS_LOOPUPDATE
, QUADRIS_LOOPCLEAR
, QUADRIS_LOOPPURGE
, and QUADRIS_LOOPEND
.
If this project is compiled with the setting of UNICODE characterset, it will not work under Win95, Win98, Win98SE and WinME. For future expandability, however, it is better compiled with the setting of a UNICODE characterset. Then, how can we get the benefit of UNICODE and support old versions of Windows? We can use Microsoft Layer for Unicode on Windows 95/98/Me Systems. You can download MSLU from here if the site is not changed. To use MSLU, you need to link unicows.lib to your project by clicking project > properties > configuration properties > linker > input > additional dependencies and writing "unicows.lib". Of course, unicows.dll should be in the same folder of NuraQuadris.exe when NuraQuadris.exe is executed under an old version of windows. Finally, you need also to include ForWin98.c in your project or just insert the following statement in stdafx.cpp.
#include "ForWin98.c"
I used HTML help. You can download the HTML help 1.4 SDK here if the site is not changed. You need to link htmlhelp.lib to your project by by clicking project > properties > configuration properties > linker > input > additional dependencies and writing "htmlhelp.lib". Of course, you need to make compiled HTML help file such as Quadris.chm beforehand and put it in the same folder of NuraQuadris.exe. I would not explain how to make compiled HTML help file here but you can learn it from htmlhelp.chm which will be included in the file you will download here if the site is not changed. The following source shows how to use function HtmlHelp(...)
as an example. Don't forget include htmlhelp.h as follows.
#include <htmlhelp.h>
...
LRESULT CQuadrisWTLView::OnHelp (UINT , WPARAM , LPARAM )
{
HWND help = HtmlHelp(m_hWnd, m_strHelp, HH_DISPLAY_TOPIC, NULL);
if (!help)
help = HtmlHelp(m_hWnd, m_strHelpDef, HH_DISPLAY_TOPIC, NULL);
if (help)
CWindow(help).CenterWindow(m_hWnd);
else
OnAppAbout();
return TRUE;
}
VC++ 8.0X and VC++ 9.0X use ATL 3.0, while VC++ 7.1 uses ATL 7.1. Although both use the same WTL 8.0, the source for VC++ 7.1 is not compatible with VC++ 8.0X. So, in order to make it able to be compiled with VC++ 8.0X or VC++ 9.0X, though it was developed with VC++ 7.1 (ATL 7.1), I made ATLVersion.h and included it in stdafx.h. ATLVersion.h is the same file as that of Nura Tritris. In this project, ATLVersion.h works very well, but I do not think that it works for all the projects written for VC++ 7.1 to be able to be compiled with VC++ 8.0X and VC++ 9.0X very well. If there is anyone who is interested in downward compatibility of ATL, I want to encourage him or her to improve ATLVersion.h.
I also made ATLWinPlus.hpp and ATLCrackPlus.hpp to improve the effeciency of message map. If you have a look at the sources of ATLWinPlus.hpp and ATLCrackPlus.hpp, you can easily understand them. If you can't trust ATLWinPlus.hpp and ATLCrackPlus.hpp, comment the statements of line 54 in stdafx.h in the folder QuadrisWTL, as follows:
I would not explain the source code of this QuadrisCustomizer. Instead, I would introduce how to use this utility program. If you run this program and translate all the messages into your language in the corresponding edit windows and save it, you can get a NuraQuadris.ini. If you put it in the same folder in which NuraQuadris.exe exists, NuraQuadris.exe will use NuraQuadris.ini to make all messages in your language. Also, you can save as a different name such as NuraQuadrisRussian.ini. It would not work as itself for NuraQuadris.exe but you can keep it as a specific language pack for NuraQuadris.
I want to thank Michael Dunn for his excellent articles on WTL for MFC programmers. I learned a lot about WTL from his article. His articles can be found here. I want to also thank Sergey Solozhentsev for his great work on the WTL Helper and the WTL Wizards. You can get his WTL Helper here and here, and its manual here and here. Do not be confused. His WTL Wizards are different from the normal WTL App Wizard which can be installed with setup71.js, for instance. His WTL Wizards support a split window framework as well. You can also get his WTL Wizards here and its manual here. It provides me with a lot of convenience when I code using WTL. Most of all, I really appreciate God and my wife Nura. He gave me her, and she is always on my side and is my firm supporter.