Wednesday, August 6, 2008

Perl CGI cached parameters.

An intern at work today ran into a problem modifying a perl cgi script. It looked something like this


my $cgi = new CGI;
$cgi->param('foo');


The problem was this value appeared to be cached. Once I accesed the page with http://server/page?foo=bar it would remember bar no matter what I changed the value to.

First I thought it was a cache issue. So we changed the code to output a timestamp. On each page load we would see the time increment but the variable was still cached somehow.

We finally found out that putting the new CGI call inside a function made sure we got a new one each time.

So what happened? I'm not really sure, I'm guessing scope of the perl code is global per apache process? Is this configurable somehow?

Well if anyone knows please add a comment because i this point I'm still baffled by it.

Saturday, August 2, 2008

c++ Windows Programing - Creating a window

This tutorial will cover how to create a window. If you haven't already you should read the Hello World tutorial for Windows Programming first.

In the last tutorial I described how to create a windows program that displays a message box. We are going to extend on that tutorial and create a window this time.

This will consists of 4 parts.

1. Register a new windows class (not to be confused with a c++ class)
2. Create the window
3. Display the window
4. Process Events.

Part 1. Registering a new window class

The first step is to fill in a windows structure that describes how your new window will look like. We'll use the WNDCLASSEX structure.


WNDCLASSEX wc;

// clear out the window class for use
ZeroMemory(&wc, sizeof(WNDCLASSEX));

// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"MyClass";

RegisterClassEx(&wc);

We first declare a new instance and zero out the memory of the instance. We then set appropriate parameters to define how the window will look. For full details on the paremeters you should consult msdn.

The lpfnWndProc is an important property. This defines a function that will be called back whenever this window needs to handle a message. We'll discuss more abot this in Part 4.

Part 2. Creating the window.

Now that we've defined the style of how our new window should look, we want to actually create the window. We'll use the CreateWindowEx function which has the following prototype:


HWND CreateWindowEx(
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);


Part 3: Display the Window

Displaying the window is accomplished by calling ShowWindow which has the prototype:


BOOL ShowWindow(
HWND hWnd,
int nCmdShow
);


Part 4: Processing Events

We now have the parts to describe the style of a window, register it, create it, and display it. But if we don't process the windows events nothing will happen. Remember lpfnWndProc from Part 1?

We must define that call back method. Anytime a message is received it will need to run through that method.

So first we need to get message off the messaging queue than define our callback.


// this struct holds Windows event messages
MSG msg;

// wait for the next message in the queue, store the result in 'msg'
while(GetMessage(&msg, NULL, 0, 0))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);

// send the message to the WindowProc function
DispatchMessage(&msg);
}




// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch(message)
{
// this message is read when the window is closed
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
} break;
}

// Handle any messages the switch statement didn't
return DefWindowProc (hWnd, message, wParam, lParam);
}



Conclusion:

Putting it all together we have a program that looks like this:


#include
#include

LRESULT CALLBACK WindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
//Our window structure.
WNDCLASSEX wc;
ZeroMemory(&wc,sizeof(WNDCLASSEX));

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_3DSHADOW;
wc.lpszClassName = L"WindowClass1";

RegisterClassEx(&wc);

// create the window and use the result as the handle
HWND hWnd = CreateWindowEx(NULL,
L"WindowClass1", // name of the window class
L"Our First Windowed Program", // title of the window
WS_OVERLAPPEDWINDOW, // window style
300, // x-position of the window
300, // y-position of the window
500, // width of the window
400, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL

ShowWindow(hWnd,nCmdShow);

MSG msg;
while(GetMessage (&msg,NULL,0,0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch(message) {
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}

Hello World - c++ Windows Application

In this post I'm going to explain the details of writing a hello world program for windows. To start we should look at the version for a console application:


#include <iostream&rt;
using namespace std;
void main() {
cout << "Hello World" << endl;
}


For windows it isn't much different. But instead of declaring a main we need to instead declare a WinMain.


#include <windows.h&rt;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShowCmd) {
MessageBox(NULL,L"Hello World",L"MyCaption",MB_ICONINFORMATION | MB_OK);
}


1. We include windows.h to give us access to the windows library functions.

2. The keyword WINAPI instructs the program to reverse the argument list. For our purposes this doesn't matter but under the hood windows needs this.

3. HINSTANCE is a handle to an instance. The main program receives a instance to itself (hinstance) and a handle to a previous instance of the same program. The previous instance is legacy and is NULL for modern applications. But is still provided for legacy code.

4. lpCmdLine is the entire command string that was used to execute the program.

5. nCmdShowCmd are options indicating how the window should open.

6. Once our method is called we can then call MessageBox to display the message.

We can now look into the MessaegBox command in more detail. The signature for the command is:


int MessageBox(HWND hWnd,
LPCTSTR lptext,
LPCTSTR lpcaption,
UINT utype);


The first argument HWND, is a handle to the window the created this message box. In our case we haven't created a window, so we supply NULL which instructs Windows to have the message box originate from the desktop.

lpText is a pointer to the text to display

lpcaption is a pointer to the caption of the message box.

uType is a parameter that specifies what type of message box, exclamation, information, etc. These are set by 'ORing' constant flags together.