Reason for using malloc() stuff is that I want to be pure in C.
What I am doing?
1.... I want to write a pure C control to teach myself internals of Win32 Message Architecture.
2... When done with this, I will burry that control (a simple button control yet...) into a DLL.
3... When done with the DLL, I will try to write a COM wrapper around it that too in pure C to check whether it can be used with VB, and .NET.
Friends one more thing... my every malloc() is having a free() but still facing problem. And one of our felllows is very much right, the problem only occurs in Debug sessions.
Here is the source code.
Please consider the following functions specially.... Are they correct?
a) AllocateButtonInfoFor()
b) DeleteButtonInfo()
c) OnNCCreate()
d) OnSetText()
First is the ButtonControl.h
============================
#ifndef __BUTTON_CONTROL_H__<br />
#define __BUTTON_CONTROL_H__<br />
#include "stdafx.h"<br />
<br />
#define BUTTON_CONTROL_CLASS TEXT("BUTTON_CONTROL_safsf")<br />
<br />
<br />
#ifdef __INCLUDE_BUTTONCONTROL_PRIVATES__<br />
<br />
<br />
typedef enum tagBUTTONSTATE<br />
{<br />
NORMAL = 2,<br />
HOVER,<br />
PRESSED,<br />
DISABLED<br />
<br />
} BUTTONSTATE;<br />
<br />
<br />
typedef struct tagBUTTONINFO<br />
{<br />
TCHAR * szText; <br />
int nTextLength; <br />
HPEN borderColor; <br />
COLORREF textColor; <br />
HBRUSH backColor; <br />
HFONT font; <br />
HPEN borderColorPressed; <br />
COLORREF textColorPressed; <br />
HBRUSH backColorPressed; <br />
HFONT fontPressed; <br />
HPEN borderColorHover; <br />
COLORREF textColorHover; <br />
HBRUSH backColorHover; <br />
HFONT fontHover; <br />
<br />
BUTTONSTATE state; <br />
<br />
} BUTTONINFO, * PBUTTONINFO;<br />
<br />
<br />
<br />
PBUTTONINFO AllocateButtonInfoFor(HWND hWnd);<br />
PBUTTONINFO PickButtonInfo(HWND hWnd);<br />
BOOL DropButtonInfo(HWND hWnd);<br />
void DeleteButtonInfo(HWND hWnd);<br />
void SetButtonDefaults(HWND hWnd, PBUTTONINFO pButtonInfo);<br />
<br />
void DrawButton(HWND hWnd, PBUTTONINFO pButtonInfo, HDC hdc);<br />
<br />
<br />
LRESULT CALLBACK ButtonProc(HWND, UINT, WPARAM, LPARAM);<br />
<br />
<br />
<br />
<br />
BOOL OnNCCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct);<br />
void OnNCDestroy(HWND);<br />
void OnPaint(HWND);<br />
void OnInitButton(HWND hWnd);<br />
void OnMouseButtonDown(HWND hWnd, int x, int y);<br />
void OnMouseButtonUp(HWND hWnd, int x, int y);<br />
INT OnGetText(HWND, int, LPTSTR);<br />
INT OnGetTextLength(HWND);<br />
BOOL OnSetText(HWND hWnd, LPCTSTR);<br />
<br />
<br />
#endif /* __INCLUDE_BUTTONCONTROL_PRIVATES__ */<br />
<br />
<br />
#define BCM_SETBORDERPEN WM_USER + 10 /* WPARAM = HPEN */<br />
#define BCM_GETBORDERPEN WM_USER + 11 /* Return = HPEN */<br />
#define BCM_SETCAPTIONCOLOR WM_USER + 12 /* WPARAM = COLORREF */<br />
#define BCM_GETCAPTIONCOLOR WM_USER + 13 /* Return = COLORREF */<br />
#define BCM_SETBACKGNDBRUSH WM_USER + 14 /* WPARAM = HBRUSH */<br />
#define BCM_GETBACKGNDBRUSH WM_USER + 15 /* Return = HBRUSH */<br />
#define BCM_SETBUTTONSTATE WM_USER + 16 /* WPARAM = BUTTONSTATE */<br />
#define BCM_GETBUTTONSTATE WM_USER + 17 /* Return = BUTTONSTATE */<br />
#define BCM_INITBUTTON WM_USER + 18 /* NULL */<br />
<br />
HRESULT InitButtonControl(HINSTANCE hInstance);<br />
#endif /*__BUTTON_CONTROL_H__*/
Second is ButtonControl.cpp
===========================
#include "stdafx.h"<br />
#define __INCLUDE_BUTTONCONTROL_PRIVATES__ /* So that we may have private functions. */<br />
#include "ButtonControl.h"<br />
<br />
<br />
<br />
HRESULT InitButtonControl(HINSTANCE hInstance)<br />
{<br />
WNDCLASSEX wc;<br />
<br />
wc.cbClsExtra = 0;<br />
wc.cbSize = sizeof(WNDCLASSEX);<br />
wc.cbWndExtra = 0;<br />
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);<br />
wc.hCursor = LoadCursor(NULL, IDC_ARROW);<br />
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);<br />
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);<br />
wc.hInstance = hInstance;<br />
wc.lpfnWndProc = ButtonProc;<br />
wc.lpszClassName = BUTTON_CONTROL_CLASS;<br />
wc.lpszMenuName = NULL;<br />
wc.style = CS_HREDRAW | CS_VREDRAW |<br />
CS_GLOBALCLASS;<br />
<br />
<br />
return RegisterClassEx(&wc);<br />
}<br />
<br />
<br />
<br />
<br />
PBUTTONINFO AllocateButtonInfoFor(HWND hWnd)<br />
{<br />
if(!hWnd)<br />
return NULL;<br />
<br />
PBUTTONINFO hMem = (PBUTTONINFO) malloc(sizeof(BUTTONINFO));<br />
<br />
if(!hMem)<br />
return NULL;<br />
<br />
SetWindowLong(hWnd, GWL_USERDATA, (LONG)hMem);<br />
<br />
SetButtonDefaults(hWnd, hMem);<br />
<br />
return hMem;<br />
<br />
<br />
}<br />
<br />
<br />
<br />
PBUTTONINFO PickButtonInfo(HWND hWnd)<br />
{<br />
if(!hWnd)<br />
return NULL;<br />
<br />
PBUTTONINFO hMem = (PBUTTONINFO) GetWindowLong(hWnd, GWL_USERDATA);<br />
<br />
if(!hMem)<br />
return NULL;<br />
<br />
<br />
DWORD dw = GetLastError();<br />
<br />
return hMem;<br />
<br />
<br />
}<br />
<br />
<br />
BOOL DropButtonInfo(HWND hWnd)<br />
{<br />
if(!hWnd)<br />
return FALSE;<br />
<br />
PBUTTONINFO hMem = (PBUTTONINFO)GetWindowLong(hWnd, GWL_USERDATA);<br />
<br />
if(!hMem)<br />
return FALSE;<br />
<br />
return TRUE;<br />
<br />
<br />
}<br />
<br />
<br />
void DeleteButtonInfo(HWND hWnd)<br />
{<br />
if(!hWnd)<br />
return;<br />
<br />
PBUTTONINFO pButtonInfo = PickButtonInfo(hWnd);<br />
<br />
if(!pButtonInfo)<br />
return;<br />
<br />
DeleteObject((HGDIOBJ)pButtonInfo->backColor);<br />
DeleteObject((HGDIOBJ)pButtonInfo->borderColor);<br />
DeleteObject((HGDIOBJ)pButtonInfo->font);<br />
<br />
if(pButtonInfo->szText != NULL)<br />
free((void *)pButtonInfo->szText);<br />
<br />
<br />
DeleteObject((HGDIOBJ)pButtonInfo->backColorPressed);<br />
DeleteObject((HGDIOBJ)pButtonInfo->borderColorPressed);<br />
DeleteObject((HGDIOBJ)pButtonInfo->fontPressed);<br />
<br />
<br />
void * hMem = (void *) GetWindowLong(hWnd, GWL_USERDATA);<br />
<br />
if(hMem != NULL)<br />
free((void *)GetWindowLong(hWnd, GWL_USERDATA));<br />
}<br />
<br />
<br />
void SetButtonDefaults(HWND hWnd, PBUTTONINFO pButtonInfo)<br />
{<br />
<br />
if(!pButtonInfo)<br />
return;<br />
<br />
<br />
ZeroMemory((PVOID)pButtonInfo, sizeof(BUTTONINFO));<br />
<br />
pButtonInfo->backColor = (HBRUSH) CreateSolidBrush(RGB(123,123,123));<br />
pButtonInfo->borderColor = (HPEN) CreatePen(PS_SOLID, 1, RGB(200,10,19));<br />
pButtonInfo->font = (HFONT) GetStockFont(ANSI_VAR_FONT);<br />
pButtonInfo->textColor = RGB(255, 255, 255);<br />
pButtonInfo->state = NORMAL;<br />
pButtonInfo->szText = NULL;<br />
pButtonInfo->nTextLength = 0;<br />
<br />
pButtonInfo->backColorPressed = CreateSolidBrush(RGB(200,180,150));<br />
pButtonInfo->borderColorPressed = (HPEN) GetStockObject(BLACK_PEN);<br />
pButtonInfo->fontPressed = (HFONT)GetStockObject(ANSI_VAR_FONT);<br />
pButtonInfo->textColorPressed = RGB(0,0,0);<br />
<br />
<br />
<br />
<br />
}<br />
<br />
<br />
void DrawButton(HWND hWnd, PBUTTONINFO pButtonInfo, HDC hdc)<br />
{<br />
static TCHAR szBuffer[256];<br />
<br />
if(!pButtonInfo)<br />
return;<br />
<br />
<br />
if(!IsWindow(hWnd))<br />
return;<br />
<br />
<br />
HDC hDC = NULL;<br />
<br />
if(hdc == NULL)<br />
hDC = GetDC(hWnd);<br />
else<br />
hDC = hdc;<br />
<br />
<br />
RECT rect;<br />
<br />
GetClientRect(hWnd, &rect);<br />
<br />
if(pButtonInfo->state == NORMAL)<br />
{<br />
<br />
<br />
<br />
SelectObject(hDC, (HGDIOBJ)pButtonInfo->backColor);<br />
SelectObject(hDC, (HGDIOBJ)pButtonInfo->borderColor);<br />
SetTextColor(hDC, pButtonInfo->textColor);<br />
SetBkMode(hDC, TRANSPARENT);<br />
<br />
<br />
FillRect(hDC, &rect, pButtonInfo->backColor);<br />
<br />
<br />
}<br />
<br />
if(pButtonInfo->state == HOVER)<br />
{<br />
<br />
}<br />
<br />
if(pButtonInfo->state == PRESSED)<br />
{<br />
SelectObject(hDC, (HGDIOBJ)pButtonInfo->backColorPressed);<br />
SelectObject(hDC, (HGDIOBJ)pButtonInfo->borderColorPressed);<br />
SetTextColor(hDC, pButtonInfo->textColorPressed);<br />
SetBkMode(hDC, TRANSPARENT);<br />
<br />
FillRect(hDC, &rect, pButtonInfo->backColorPressed);<br />
}<br />
<br />
if(pButtonInfo->state == DISABLED)<br />
{<br />
}<br />
<br />
<br />
<br />
Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);<br />
<br />
<br />
<br />
<br />
DrawText(hDC, pButtonInfo->szText,<br />
pButtonInfo->nTextLength,<br />
&rect,<br />
DT_SINGLELINE | DT_VCENTER | DT_CENTER);<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
if(hdc == NULL)<br />
ReleaseDC(hWnd, hDC);<br />
<br />
}<br />
<br />
<br />
LRESULT CALLBACK ButtonProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)<br />
{<br />
switch(msg)<br />
{<br />
<br />
case WM_NCCREATE:<br />
{<br />
return (LRESULT) OnNCCreate(hWnd, (LPCREATESTRUCT)lParam);<br />
}<br />
<br />
case WM_CREATE:<br />
{<br />
PostMessage(hWnd, BCM_INITBUTTON, 0, 0);<br />
return TRUE;<br />
}<br />
<br />
case BCM_INITBUTTON:<br />
{<br />
return 0;<br />
}<br />
<br />
case WM_DESTROY:<br />
{<br />
OnNCDestroy(hWnd);<br />
return 0;<br />
}<br />
<br />
<br />
case WM_PAINT:<br />
{<br />
OnPaint(hWnd);<br />
<br />
return 0;<br />
}<br />
<br />
<br />
case WM_LBUTTONDOWN:<br />
case WM_RBUTTONDOWN:<br />
{<br />
OnMouseButtonDown(hWnd, LOWORD(lParam), HIWORD(lParam));<br />
return 0;<br />
}<br />
<br />
<br />
case WM_LBUTTONUP:<br />
case WM_RBUTTONUP:<br />
{<br />
OnMouseButtonUp(hWnd, LOWORD(lParam), HIWORD(lParam));<br />
return 0;<br />
}<br />
<br />
<br />
case WM_GETTEXT:<br />
{<br />
return OnGetText(hWnd, (int)wParam, (LPTSTR)lParam);<br />
}<br />
<br />
<br />
case WM_GETTEXTLENGTH:<br />
{<br />
return OnGetTextLength(hWnd);<br />
}<br />
<br />
<br />
case WM_SETTEXT:<br />
{<br />
return OnSetText(hWnd, (LPCTSTR)lParam);<br />
}<br />
<br />
<br />
<br />
<br />
}<br />
<br />
return DefWindowProc(hWnd, msg, wParam, lParam);<br />
}<br />
<br />
<br />
<br />
BOOL OnNCCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)<br />
{<br />
PBUTTONINFO pButtonInfo = AllocateButtonInfoFor(hWnd);<br />
<br />
if(!pButtonInfo)<br />
return FALSE;<br />
<br />
int iLen = lstrlen(lpCreateStruct->lpszName);<br />
<br />
if(iLen > pButtonInfo->nTextLength)<br />
{<br />
if(pButtonInfo->szText != NULL)<br />
free((void *)pButtonInfo->szText);<br />
pButtonInfo->szText = (TCHAR *) malloc(iLen + 2);<br />
<br />
if(pButtonInfo->szText == NULL)<br />
return FALSE;<br />
}<br />
<br />
pButtonInfo->nTextLength = iLen;<br />
ZeroMemory((LPVOID)pButtonInfo->szText, pButtonInfo->nTextLength);<br />
lstrcpy(pButtonInfo->szText, lpCreateStruct->lpszName);<br />
<br />
<br />
<br />
return TRUE;<br />
}<br />
<br />
<br />
<br />
void OnNCDestroy(HWND hWnd)<br />
{<br />
DeleteButtonInfo(hWnd);<br />
}<br />
<br />
<br />
<br />
void OnPaint(HWND hWnd)<br />
{<br />
PAINTSTRUCT ps;<br />
<br />
PBUTTONINFO pButtonInfo = PickButtonInfo(hWnd);<br />
HDC hdc = BeginPaint(hWnd, &ps);<br />
<br />
DrawButton(hWnd, pButtonInfo, hdc);<br />
EndPaint(hWnd, &ps);<br />
<br />
<br />
}<br />
<br />
<br />
<br />
<br />
void OnMouseButtonDown(HWND hWnd, int x, int y)<br />
{<br />
PBUTTONINFO pButtonInfo = PickButtonInfo(hWnd);<br />
<br />
if(!pButtonInfo)<br />
return;<br />
<br />
pButtonInfo->state = PRESSED;<br />
<br />
InvalidateRect(hWnd, NULL, TRUE);<br />
}<br />
<br />
<br />
<br />
void OnMouseButtonUp(HWND hWnd, int x, int y)<br />
{<br />
PBUTTONINFO pButtonInfo = PickButtonInfo(hWnd);<br />
<br />
if(!pButtonInfo)<br />
return;<br />
<br />
pButtonInfo->state = NORMAL;<br />
InvalidateRect(hWnd, NULL, TRUE);<br />
<br />
HWND hParent = GetParent(hWnd);<br />
<br />
if(!hParent)<br />
return;<br />
<br />
UINT nID = GetWindowLong(hWnd, GWL_ID);<br />
<br />
SendMessage(hParent, WM_COMMAND, MAKEWPARAM(nID, BN_CLICKED), (LONG)hWnd);<br />
}<br />
<br />
<br />
<br />
INT OnGetText(HWND hWnd, int nMaxLen, LPTSTR lpszBuffer)<br />
{<br />
PBUTTONINFO pButtonInfo = PickButtonInfo(hWnd);<br />
<br />
if(!pButtonInfo)<br />
return -1;<br />
<br />
<br />
int i = 0;<br />
<br />
<br />
lstrcpy(lpszBuffer, pButtonInfo->szText);<br />
<br />
return i;<br />
}<br />
<br />
<br />
<br />
INT OnGetTextLength(HWND hWnd)<br />
{<br />
PBUTTONINFO pButtonInfo = PickButtonInfo(hWnd);<br />
<br />
if(!pButtonInfo)<br />
return -1;<br />
<br />
return pButtonInfo->nTextLength;<br />
}<br />
<br />
<br />
<br />
BOOL OnSetText(HWND hWnd, LPCTSTR lpszText)<br />
{<br />
PBUTTONINFO pButtonInfo = PickButtonInfo(hWnd);<br />
<br />
int iLen = lstrlen(lpszText);<br />
<br />
if(iLen > pButtonInfo->nTextLength)<br />
{<br />
if(pButtonInfo->szText != NULL)<br />
free((void *)pButtonInfo->szText);<br />
<br />
pButtonInfo->szText = (TCHAR *) malloc(iLen + 2);<br />
<br />
<br />
if(pButtonInfo->szText == NULL)<br />
return FALSE;<br />
}<br />
<br />
pButtonInfo->nTextLength = iLen;<br />
ZeroMemory((LPVOID)pButtonInfo->szText, pButtonInfo->nTextLength);<br />
lstrcpy(pButtonInfo->szText, lpszText);<br />
<br />
InvalidateRect(hWnd, NULL, TRUE);<br />
return TRUE;<br />
<br />
}
Polite Programmer
More Object Oriented then C#
|