Here is the DDT Address project converted to plain low level flat API using the SDK syntax style.
The PowerBASIC version is 32-bit ANSI,
and it has been compiled with PB 9.05 and a specific include file to produce a final EXE size of 40 Kb.
The C++ version is 64-bit UNICODE,
and it has been compiled with VS 2010 to produce a final EXE size of 97 Kb.
The size of the original DDT code was 102 Kb.
The C++ is the exact transcription, line by line, of the PowerBASIC SDK version.
Added
"DPI aware version" have been added (32-bit and 64-bit).
...
Here is the C++ DPI aware 64-bit version
Tools.h
#include <windows.h>
#include <iostream>
#include <Commctrl.h>
using namespace std;
#define $NULL L""
#define $COMMA L","
#define $SPACE L" "
#define long_proc typedef long (__stdcall *zProc)
#define LOINT(a) ((SHORT)(a))
#define HIINT(a) ((SHORT)(((DWORD)(a) >> 16) & 0xFFFF))
#define MAKLNG(a, b) ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))
#define UBOUND(T) ((LONG) T.size())
long zTrace(IN WCHAR* sPtr) {
long nRet = 0;
static HMODULE hDll;
if (hDll == 0) {
if (sizeof(LONG_PTR) == 8) {
hDll = LoadLibrary(L"zTrace64");
}
else {
hDll = LoadLibrary(L"zTrace32");
}
}
if (hDll) {
long_proc(WCHAR*);
static zProc hProc;
if (hProc == 0) { hProc = (zProc)GetProcAddress(hDll, "zTrace"); }
if (hProc) { nRet = hProc(sPtr); }
}
return nRet;
}
WCHAR* STRL(IN long N) {
static WCHAR longstr[33] = {0};
_ltow_s(N, longstr, 10);
return (WCHAR*)longstr;
}
wstring RTRIM$(IN wstring sBuf, IN wstring sChar) {
wstring sResult = sBuf;
LONG_PTR nLength = sBuf.length();
if (nLength && (sChar.length())) {
//sChar = sChar.substr(0, 1);
while (nLength > 0) {
// if (*sBuf.substr(nLength - 1, 1).c_str() == *sChar.c_str()) {
// This is the sChar ANY search version
if (std::wstring::npos != sChar.find(sBuf.substr(nLength - 1, 1))) {
--nLength; }
else {
break;
}
}
sResult = sBuf.substr(0, nLength);
}
return sResult;
}
wstring LTRIM$(IN wstring sBuf, IN wstring sChar) {
wstring sResult = sBuf;
LONG_PTR nLength = sBuf.length();
if (nLength && (sChar.length())) {
//sChar = sChar.substr(0, 1);
long K = 0;
while (K < nLength) {
// if (*sBuf.substr(K, 1).c_str() == *sChar.c_str()) {
// This is the sChar ANY search version
if (std::wstring::npos != sChar.find(sBuf.substr(K, 1))) {
++K; }
else {
break;
}
}
sResult = sBuf.substr(K, nLength);
}
return sResult;
}
wstring TRIM$(IN wstring sBuf, IN wstring sChar) {
return LTRIM$(RTRIM$(sBuf, sChar), sChar);
}
long INSTR(IN long nIndex, IN wstring sMain, IN wstring sSearch) {
long nRet = -1; // Not found
long nLength = (long) (sMain.length());
if (nLength && (sSearch.length())) {
if (nIndex < 0) {
nRet = (long) (sMain.rfind(sSearch, nLength + nIndex + 1)); }
else {
nRet = (long) (sMain.find(sSearch, nIndex));
}
}
return nRet + 1;
}
long PARSECOUNT(IN wstring MainString, IN wstring MatchString) {
long count = 0;
size_t pos = 0;
while((pos = MainString.find(MatchString, pos)) != std::string::npos) {
++count; ++pos;
}
return count;
}
wstring PARSE$(IN wstring sMain, IN wstring sDelim, IN long nIndex) {
wstring sResult = $NULL;
long nLength = (long) sDelim.length();
if (nLength == 0) { sDelim = L","; ++nLength; } // Use comma "," as default delimiter
sMain = RTRIM$(sMain, sDelim); sMain += sDelim;
if (sMain.length() && nLength) {
LONG_PTR prev_pos = 0, pos = 0, nCount = 0;
while( (pos = sMain.find(sDelim, pos)) != std::wstring::npos ) {
wstring substring(sMain.substr(prev_pos, pos - prev_pos));
++nCount;
if (nCount == nIndex) { sResult = substring; break; }
prev_pos = ++pos;
}
}
return sResult;
}
long dpi(IN long nPix) {
static float ratio;
if (ratio == 0) {
HDC hDC = GetDC(0); ratio = (GetDeviceCaps(hDC, LOGPIXELSX) / 96.0f); ReleaseDC(0, hDC);
}
return (long)(nPix * ratio);
}
Address.cpp
#include <windows.h>
#include <WinBase.h>
#include <Shlwapi.h>
#include <vector>
#include "Tools.h"
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#define ID_INDEX 100
#define ID_COMPANY 101
#define ID_LASTNAME 102
#define ID_FIRSTNAME 103
#define ID_ADDRESS1 104
#define ID_ADDRESS2 105
#define ID_ADDRESS3 106
#define ID_CITYNAME 107
#define ID_STATENAME 108
#define ID_ZIPCODE 109
#define ID_COUNTRY 110
#define ID_PHONE 111
#define ID_FAX 112
#define ID_EMAIL 113
#define ID_URL 114
#define ID_COMMENTS 115
#define ID_PRIOR 121
#define ID_NEXT 122
#define ID_ADD 123
#define ID_UPDATE 124
#define ID_FIND 125
#define ID_DELETE 126
#define ID_PRINT 127
#define ID_MENU_CLOSE IDCANCEL
#define ID_MENU_CUT 201
#define ID_MENU_COPY 202
#define ID_MENU_PASTE 203
#define ID_MENU_HELP 204
#define ID_MENU_ABOUT 205
#define WM_APPLYFOCUS WM_USER + 999
struct AddressType {
WCHAR Company[64];
WCHAR LastName[32];
WCHAR FirstName[32];
WCHAR Address1[64];
WCHAR Address2[64];
WCHAR Address3[64];
WCHAR CityName[24];
WCHAR StateName[4];
WCHAR ZipCode[12];
long Country;
WCHAR Phone[24];
WCHAR Fax[24];
WCHAR Email[64];
WCHAR Url[64];
WCHAR Comments[1024];
};
struct PROP {
HFONT usefont;
HINSTANCE hinstance;
long isrecmodified;
long isfilemodified;
long currententry;
long maxentries;
WCHAR findtext[MAX_PATH];
};
vector<AddressType> gAddressBook;
PROP gP;
HWND addLabel(IN HWND hParent, IN long nID, IN WCHAR* zCaption, IN long x, IN long y, IN long w, IN long h, IN DWORD dwStyle) {
HWND hCtrl = 0;
hCtrl = CreateWindowEx(0, L"Static", zCaption, dwStyle, dpi(x), dpi(y), dpi(w), dpi(h), hParent, (HMENU) nID, gP.hinstance, NULL);
if (hCtrl) { SendMessage(hCtrl, WM_SETFONT, (WPARAM) gP.usefont, 0); }
return hCtrl;
}
HWND addTextBox(IN HWND hParent, IN long nID, IN WCHAR* zCaption, IN long x, IN long y, IN long w, IN long h, IN DWORD dwStyle) {
HWND hCtrl = 0;
hCtrl = CreateWindowEx(WS_EX_CLIENTEDGE, L"Edit", zCaption, dwStyle, dpi(x), dpi(y), dpi(w), dpi(h), hParent, (HMENU) nID, gP.hinstance, NULL);
if (hCtrl) { SendMessage(hCtrl, WM_SETFONT, (WPARAM) gP.usefont, 0); }
return hCtrl;
}
HWND addComboBox(IN HWND hParent, IN long nID, IN WCHAR* zCaption, IN long x, IN long y, IN long w, IN long h, IN DWORD dwStyle) {
HWND hCtrl = 0;
hCtrl = CreateWindowEx(0, L"ComboBox", zCaption, dwStyle, dpi(x), dpi(y), dpi(w), dpi(h), hParent, (HMENU) nID, gP.hinstance, NULL);
if (hCtrl) { SendMessage(hCtrl, WM_SETFONT, (WPARAM) gP.usefont, 0); }
return hCtrl;
}
HWND addButton(IN HWND hParent, IN long nID, IN WCHAR* zCaption, IN long x, IN long y, IN long w, IN long h, IN DWORD dwStyle) {
HWND hCtrl = 0;
hCtrl = CreateWindowEx(0, L"Button", zCaption, dwStyle, dpi(x), dpi(y), dpi(w), dpi(h), hParent, (HMENU) nID, gP.hinstance, NULL);
if (hCtrl) { SendMessage(hCtrl, WM_SETFONT, (WPARAM) gP.usefont, 0); }
return hCtrl;
}
void addCountries(IN HWND hCtrl) {
WCHAR zItem[32] = { 0 };
WCHAR* sCountry = L"United States,Afghanistan,Albania,Algeria,Andorra,Angola,Anguilla,Antarctica,Argentina,Armenia,Aruba,Australia,Austria,Azerbaijan,Bahamas,Bahrain,Bangladesh,Barbados,Belarus,Belgium,Belize,Benin,Bermuda,Bhutan,Bolivia,Botswana,Bouvet Island,BosniaHerzogovina,Brazil,Brunei,Bulgaria,Burkina Faso,Cambodia,Cameroon,Canada,Cape Verde,Cayman Islands,Central African Rep,Chad,Chile,China,Christmas Island,Colombia,Comoros,Congo,Cook Islands,Costa Rica,Croatia,Cuba,Cyprus,Czech Republic,Denmark,Djibouti,Dominica,Dominican Republic,East Timor,Ecuador,Egypt,El Salvador,Equatorial Guinea,Eritrea,Estonia,Ethiopia,Falkland Islands,Faroe Islands,Fiji,Finland,France,France Metropolitan,French Guiana,French Polynesia,French S. Territories,Gabon,Gambia,Georgia,Germany,Ghana,Gibraltar,Greece,Greenland,Grenada,Guadeloupe,Guam,Guatemala,Guinea,Guinea-Bissau,Guyana,Haiti,Honduras,Hong Kong,Hungary,Iceland,IN India,Indonesia,Iran,Iraq,Ireland,Israel,Italy,Ivory Coast,Jamaica,Japan,Jordan,Kazakhstan,Kenya,Kiribati,Korea (North),Korea (South),Kuwait,Kyrgyzstan,Laos,Latvia,Lebanon,Lesotho,Liberia,Libya,Liechtenstein,Lithuania,Luxembourg,Macau,Macedonia,Madagascar,Malawi,Malaysia,Maldives,Mali,Malta,Marshall Islands,Martinique,Mauritania,Mauritius,Mayotte,Mexico,Micronesia,Miquelon,Moldova,Monaco,Mongolia,Montserrat,Morocco,Mozambique,Myanmar,Namibia,Nauru,Nepal,Netherlands,Nevis,New Caledonia,New Guinea,New Zealand,Nicaragua,Niger,Nigeria,Niue,Norfolk Island,Norway,Oman,Pakistan,Palau,Panama,Paraguay,Peru,Philippines,Pitcairn,Poland,Portugal,Principe,Puerto Rico,Qatar,Reunion,Romania,Russian Federation,Rwanda,Saint Kitts,Saint Lucia,Samoa,San Marino,Sao Tome,Saudi Arabia,Senegal,Seychelles,Sierra Leone,Singapore,Slovak Republic,Slovenia,Solomon Islands,Somalia,South Africa,Spain,Sri Lanka,St. Helena,St. Pierre,Sudan,Suriname,Swaziland,Sweden,Switzerland,Syria,Taiwan,Tajikistan,Tanzania,Thailand,Tobago,Togo,Tokelau,Tonga,Trinidad,Tunisia,Turkey,Turkmenistan,Tuvalu,Uganda,Ukraine,United Arab Emirates,United Kingdom,United States,Uruguay,Uzbekistan,Vanuatu ,Vatican City State,Venezuela,Viet Nam,Virgin Islands (BR),Virgin Islands (US),Western Sahara,Yemen,Yugoslavia,Zaire,Zambia,Zimbabwe,Other";
for (long K = 1; K <= PARSECOUNT(sCountry, L","); K++) {
wcscpy_s(zItem, PARSE$(sCountry, L",", K).c_str());
SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM) zItem);
}
}
DWORD FileSize(IN WCHAR* szFileSpec) {
WIN32_FIND_DATA fd = {0};
DWORD nRet = 0;
if (wcslen(szFileSpec)) {
HANDLE hFind;
hFind = FindFirstFile(szFileSpec, &fd);
if (hFind != INVALID_HANDLE_VALUE) {
FindClose(hFind);
nRet = fd.nFileSizeLow;
}
}
return nRet;
}
void SetButtonStatus(IN HWND hWnd) {
wstring sTxt;
// If any current text is modified, make the ADD & Update buttons active
if (gP.isrecmodified) {
EnableWindow(GetDlgItem(hWnd, ID_ADD), TRUE);
EnableWindow(GetDlgItem(hWnd, ID_UPDATE), TRUE);
} else {
EnableWindow(GetDlgItem(hWnd, ID_ADD), FALSE);
EnableWindow(GetDlgItem(hWnd, ID_UPDATE), FALSE);
}
// Update the Index control text
sTxt = STRL(gP.currententry); sTxt.append(L" / "); sTxt.append(STRL(gP.maxentries));
SetWindowText(GetDlgItem(hWnd, ID_INDEX), (WCHAR*) sTxt.c_str());
// Do we have any records? is not, disable the Prior/Next buttons, etc
if (gP.maxentries) {
// If there are records, allow the Find/Delete buttons
EnableWindow(GetDlgItem(hWnd, ID_FIND), TRUE);
EnableWindow(GetDlgItem(hWnd, ID_DELETE), TRUE);
// We have records, so set the Prior button status according to the current index position
if (gP.currententry < 2) {
EnableWindow(GetDlgItem(hWnd, ID_PRIOR), FALSE);
} else {
EnableWindow(GetDlgItem(hWnd, ID_PRIOR), TRUE);
}
// Update the } control button
if (gP.currententry >= gP.maxentries) {
EnableWindow(GetDlgItem(hWnd, ID_NEXT), FALSE);
} else {
EnableWindow(GetDlgItem(hWnd, ID_NEXT), TRUE);
}
} else {
EnableWindow(GetDlgItem(hWnd, ID_PRIOR), FALSE);
EnableWindow(GetDlgItem(hWnd, ID_NEXT), FALSE);
EnableWindow(GetDlgItem(hWnd, ID_FIND), FALSE);
EnableWindow(GetDlgItem(hWnd, ID_DELETE), FALSE);
}
}
void UdtToDialog(IN HWND hWnd, IN long Index) {
Index--; // C++ array is 0 based
AddressType Temp = { 0 };
long SaveState = 0;
if ((Index > -1) && (Index < UBOUND(gAddressBook))) {
RtlMoveMemory(&Temp, &gAddressBook[Index], sizeof(AddressType));
}
// When we change the edit control data, we generate EN_UPDATE messages...
// Due to the design of our GUI interface, we would end up with the ADD and UPDATE
// buttons becoming enabled just because we loaded a new UDT record into the dialog.
// to overcome this, we set the "modified" flag to TRUE, so the main callback
// function ingores the "update" notication messages.
SaveState = gP.isrecmodified;
gP.isrecmodified = TRUE;
SetWindowText(GetDlgItem(hWnd, ID_COMPANY), RTRIM$(Temp.Company, $SPACE).c_str());
SetWindowText(GetDlgItem(hWnd, ID_LASTNAME), RTRIM$(Temp.LastName, $SPACE).c_str());
SetWindowText(GetDlgItem(hWnd, ID_FIRSTNAME), RTRIM$(Temp.FirstName, $SPACE).c_str());
SetWindowText(GetDlgItem(hWnd, ID_ADDRESS1), RTRIM$(Temp.Address1, $SPACE).c_str());
SetWindowText(GetDlgItem(hWnd, ID_ADDRESS2), RTRIM$(Temp.Address2, $SPACE).c_str());
SetWindowText(GetDlgItem(hWnd, ID_ADDRESS3), RTRIM$(Temp.Address3, $SPACE).c_str());
SetWindowText(GetDlgItem(hWnd, ID_CITYNAME), RTRIM$(Temp.CityName, $SPACE).c_str());
SetWindowText(GetDlgItem(hWnd, ID_STATENAME), RTRIM$(Temp.StateName, $SPACE).c_str());
SetWindowText(GetDlgItem(hWnd, ID_ZIPCODE), RTRIM$(Temp.ZipCode, $SPACE).c_str());
SendMessage (GetDlgItem(hWnd, ID_COUNTRY), CB_SETCURSEL, Temp.Country - 1, 0);
SetWindowText(GetDlgItem(hWnd, ID_PHONE), RTRIM$(Temp.Phone, $SPACE).c_str());
SetWindowText(GetDlgItem(hWnd, ID_FAX), RTRIM$(Temp.Fax, $SPACE).c_str());
SetWindowText(GetDlgItem(hWnd, ID_EMAIL), RTRIM$(Temp.Email, $SPACE).c_str());
SetWindowText(GetDlgItem(hWnd, ID_URL), RTRIM$(Temp.Url, $SPACE).c_str());
SetWindowText(GetDlgItem(hWnd, ID_COMMENTS), RTRIM$(Temp.Comments, $SPACE).c_str());
// Restore the previous state
gP.isrecmodified = SaveState;
}
void DialogToUdt (IN HWND hWnd, IN long Index) {
Index--; // C++ array is 0 based
AddressType Temp = { 0 };
if ((Index > -1) && (Index < UBOUND(gAddressBook))) {
RtlMoveMemory(&Temp, &gAddressBook[Index], sizeof(AddressType));
GetWindowText(GetDlgItem(hWnd, ID_COMPANY), Temp.Company, sizeof(Temp.Company));
GetWindowText(GetDlgItem(hWnd, ID_LASTNAME), Temp.LastName, sizeof(Temp.LastName));
GetWindowText(GetDlgItem(hWnd, ID_FIRSTNAME), Temp.FirstName, sizeof(Temp.FirstName));
GetWindowText(GetDlgItem(hWnd, ID_ADDRESS1),Temp.Address1, sizeof(Temp.Address1));
GetWindowText(GetDlgItem(hWnd, ID_ADDRESS2), Temp.Address2, sizeof(Temp.Address2));
GetWindowText(GetDlgItem(hWnd, ID_ADDRESS3), Temp.Address3, sizeof(Temp.Address3));
GetWindowText(GetDlgItem(hWnd, ID_CITYNAME), Temp.CityName, sizeof(Temp.CityName));
GetWindowText(GetDlgItem(hWnd, ID_STATENAME), Temp.StateName, sizeof(Temp.StateName));
GetWindowText(GetDlgItem(hWnd, ID_ZIPCODE), Temp.ZipCode, sizeof(Temp.ZipCode));
Temp.Country = (long) SendMessage(GetDlgItem(hWnd, ID_COUNTRY), CB_GETCURSEL, 0, 0) + 1;
GetWindowText(GetDlgItem(hWnd, ID_PHONE), Temp.Phone, sizeof(Temp.Phone));
GetWindowText(GetDlgItem(hWnd, ID_FAX), Temp.Fax, sizeof(Temp.Fax));
GetWindowText(GetDlgItem(hWnd, ID_EMAIL), Temp.Email, sizeof(Temp.Email));
GetWindowText(GetDlgItem(hWnd, ID_URL), Temp.Url, sizeof(Temp.Url));
GetWindowText(GetDlgItem(hWnd, ID_COMMENTS), Temp.Comments, sizeof(Temp.Comments));
RtlMoveMemory(&gAddressBook[Index], &Temp, sizeof(AddressType));
}
}
void AddUpdateRecord (IN HWND hWnd, IN WPARAM wParam) {
// This function is only called if gP.isrecmodified is TRUE
WCHAR LastName[32] = { 0 };
AddressType Temp = { 0 };
// Get the Last Name field
GetWindowText(GetDlgItem(hWnd, ID_LASTNAME), LastName, sizeof(LastName));
// Check if Last Name entered; at this stage will not check for duplicate entries
if (wcslen(LastName) == 0) {
// Display error message dialog
MessageBox(hWnd, L"You must specify a Last Name!", $NULL, MB_ICONEXCLAMATION);
// Move focus to the offending control
SetFocus(GetDlgItem(hWnd, ID_LASTNAME));
return;
}
// Now determine if ADD or UPDATE buttons clicked
if ((LOINT(wParam) == ID_ADD) || (gP.maxentries < 1)) { // It's the Add button, or we have no existing entries
// Extend the UDT array and insert the new address data
gP.maxentries++;
gP.currententry = gP.maxentries;
gAddressBook.resize(gP.maxentries);
}
// Get the data from the dialog
DialogToUdt(hWnd, gP.currententry);
// Reset the modified flag
gP.isrecmodified = FALSE;
// Flag data as modified
gP.isfilemodified = TRUE;
// Update the dialog controls
SetButtonStatus(hWnd);
}
void DeleteRecord (IN HWND hWnd) {
// Only permit a deletion if the index is valid
if ((gP.currententry < 1) || (gP.currententry > gP.maxentries)) { return; }
// Confirm deletion
if (MessageBox(hWnd, L"Are you sure you want to delete this record?",
L"Delete Record", MB_ICONQUESTION | MB_OKCANCEL) == IDCANCEL) { return; }
// Now perform the removal of the record and update our index variables
//array delete gAddressBook[gP.currententry];
gAddressBook.erase(gAddressBook.begin() + gP.currententry -1);
gP.maxentries--;
gP.currententry = min(gP.currententry, gP.maxentries);
gAddressBook.resize(max(1, gP.maxentries));
// Update our status flags & refresh the window
gP.isrecmodified = FALSE;
gP.isfilemodified = TRUE;
SetButtonStatus(hWnd);
UdtToDialog(hWnd, gP.currententry);
}
LRESULT CALLBACK FindDialogProc (IN HWND hWnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam) {
long K = 0, wID = 0;
HWND hParent = 0;
wstring sFindText;
WCHAR szRecord[sizeof(AddressType)] = { 0 };
switch (uMsg) {
case WM_COMMAND:
wID = LOINT(wParam);
switch (wID) {
case IDCANCEL:
if (HIINT(wParam) == BN_CLICKED) {
SendMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
}
break;
case ID_FIND:
// Retrieve the search text if the edit control contents change.
// We save it in a global string variable so we can recreate the
// Find dialog with the same search text if it is relaunched again.
if (HIINT(wParam) == EN_UPDATE) { // The text was changed
// Get the text and trim away eventual leading/trailing spaces
GetWindowText(GetDlgItem(hWnd, ID_FIND), gP.findtext, sizeof(gP.findtext));
wcscpy_s(gP.findtext, TRIM$(gP.findtext, $SPACE).c_str());
}
return 0;
case IDOK: // Ok button
// Now initiate a search as long as the search text is available
if ((HIINT(wParam) == BN_CLICKED) && (wcslen(gP.findtext))) {
// Get main dialog handle
hParent = GetParent(hWnd);
// Start search from end record and loop from end to start
sFindText = CharUpper(gP.findtext);
for (K = gP.currententry; K < gP.maxentries; K++) {
RtlMoveMemory(&szRecord, &gAddressBook[K], sizeof(AddressType));
CharUpper(szRecord);
if (INSTR(0, szRecord, sFindText)) {
gP.isrecmodified = FALSE;
gP.currententry = K + 1;
UdtToDialog(hParent, gP.currententry);
SetButtonStatus(hParent);
return 0;
}
}
// No match between index and end, so restart from beginning of file
for (K = 0; K < gP.currententry; K++) {
RtlMoveMemory(&szRecord, &gAddressBook[K], sizeof(AddressType));
CharUpper(szRecord);
if (INSTR(0, szRecord, sFindText)) {
gP.isrecmodified = FALSE;
gP.currententry = K + 1;
UdtToDialog(hParent, gP.currententry);
SetButtonStatus(hParent);
return 0;
}
}
// Hmmm... no matches at all!
// By disabling the Modeless Find dialog while the MSGBOX is shown,
// we ensure the parent dialog keeps its zOrder and regains focus
// when the Find dialog is closed, else Windows may lose track of
// it and send it to the back..
EnableWindow(hWnd, FALSE);
MessageBox(hParent, L"Find record", L"No occurrences found.", MB_ICONERROR | MB_TASKMODAL);
EnableWindow(hWnd, TRUE);
}
return 0;
}
break;
case WM_DESTROY:
EnableWindow(GetParent(hWnd), 1);
// Close the main window
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
long FindDialog (IN HWND hParent) {
long nRet = 0;
long x = 0, y = 0, w = 0, h = 0, K = 0, nWidth = 0, nHeight = 0, IsInitialized = 0;
HWND hWnd = 0, hCtrl = 0;
WNDCLASSEX wcx = { 0 };
MSG msg = { 0 } ;
RECT rc = { 0 }, rw = { 0 };
DWORD dwStyle = 0, dwExStyle = 0;
WCHAR zClass[] = L"TOOLFIND";
wcx.cbSize = sizeof(wcx);
IsInitialized = GetClassInfoEx(gP.hinstance, zClass, &wcx);
if (!IsInitialized) {
wcx.style = 0;
wcx.lpfnWndProc = FindDialogProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = gP.hinstance;
wcx.hIcon = NULL;
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH) COLOR_BTNSHADOW;
wcx.lpszMenuName = NULL;
wcx.lpszClassName = zClass;
wcx.hIconSm = wcx.hIcon;
if (RegisterClassEx(&wcx)) { IsInitialized = TRUE; }
}
if (IsInitialized) {
SetRect(&rc, 0, 0, dpi(231), dpi(112));
// Note: indeed we don't need AdjustWindowRectEx, because we use do not use a non-client area
// but it won't hurt anything to keep it, in case we change our mind ;)
dwStyle = WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU;
dwExStyle = WS_EX_TOOLWINDOW;
AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);
w = rc.right - rc.left; h = rc.bottom - rc.top;
hWnd = CreateWindowEx(dwExStyle, zClass, L"Find Record", dwStyle, 0, 0, w, h, hParent, 0, gP.hinstance, NULL);
if (hWnd) {
// Add the controls
hCtrl = addLabel(hWnd, -1, L"Find &Text:", dpi(3), dpi(30), dpi(55), dpi(16), WS_CHILD | WS_VISIBLE | SS_RIGHT);
hCtrl = addTextBox(hWnd, ID_FIND, gP.findtext, dpi(61), dpi(26), dpi(154), dpi(22), WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL);
SetFocus(hCtrl);
dwStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
hCtrl = addButton(hWnd, IDOK, L"&Find Next", dpi(86), dpi(76), dpi(60), dpi(23), dwStyle);
hCtrl = addButton(hWnd, IDCANCEL, L"&Cancel", dpi(155), dpi(76), dpi(60), dpi(23), dwStyle);
// Center the child popup in the parent window.
GetWindowRect(hParent, &rw); nWidth = rw.right - rw.left; nHeight = rw.bottom - rw.top;
GetWindowRect(hWnd, &rc); w = rc.right - rc.left; h = rc.bottom - rc.top;
x = rw.left + ((nWidth - w) / 2);
y = rw.top + ((nHeight - h) / 2);
MoveWindow(hWnd, x, y, w, h, 0);
EnableWindow(hParent, 0); // Disable the parent to make it a modal tool window, see also WM_DESTROY
ShowWindow(hWnd, SW_SHOW);
while (GetMessage(&msg, NULL, 0, 0)) {
if (IsDialogMessage(hWnd, &msg) == 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
BringWindowToTop(hParent);
nRet = (long) msg.wParam;
}
}
return nRet;
}
void ShowButtons(IN HWND hWnd, IN long Visibility) {
for (long K = ID_PRIOR; K <= ID_PRINT; K++) {
ShowWindow(GetDlgItem(hWnd, K), Visibility);
}
ShowWindow(GetDlgItem(hWnd, IDCANCEL), Visibility);
}
long PrintThisWindow(IN HWND hWnd) {
WCHAR szBuffer[MAX_PATH] = { 0 };
HDC hDCprint = 0;
DWORD nBufferSize = MAX_PATH;
long nRet = 0;
if (GetDefaultPrinter(szBuffer, &nBufferSize)) {
hDCprint = CreateDC(NULL, szBuffer, NULL, NULL);
if (hDCprint) {
RECT rc = { 0 };
DOCINFO dinfo = { 0 };
long hRes = GetDeviceCaps(hDCprint, HORZRES);
long vRes = GetDeviceCaps(hDCprint, VERTRES);
long offsetX = 15;
long offsetY = 60;
GetClientRect(hWnd, &rc);
HDC hScreenDC = GetDC(0);
HDC hDC = CreateCompatibleDC(hScreenDC);
HBITMAP hBmp = CreateCompatibleBitmap(hScreenDC, rc.right, rc.bottom);
SelectObject(hDC, hBmp);
// Hide the buttons
ShowButtons(hWnd, SW_HIDE);
// Windows do the WM_PRINTCLIENT for us
PrintWindow(hWnd, hDC, PW_CLIENTONLY);
// Show the buttons
ShowButtons(hWnd, SW_SHOW);
float rCoef = min((hRes - (offsetX * 2)) / (float) rc.right, (vRes - (offsetY * 2)) / (float) rc.bottom);
long fxSize = (long) (rc.right * rCoef);
long fySize = (long) (rc.bottom * rCoef);
long xtop = (hRes - fxSize) / 2 + offsetX;
long ytop = (vRes - fySize) / 2 + offsetY;
dinfo.cbSize = sizeof(dinfo);
dinfo.lpszDocName = NULL;
dinfo.lpszOutput = NULL;
if (StartDoc(hDCprint, &dinfo) > 0) {
if (StartPage(hDCprint) > 0) {
// Paint the bitmap
if (hBmp) {
BITMAP bm = { 0 };
HDC dcBitmap = CreateCompatibleDC(0);
GetObject(hBmp, sizeof(bm), &bm);
BITMAPINFO bi = { 0 };
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = bm.bmWidth;
bi.bmiHeader.biHeight = bm.bmHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = bm.bmBitsPixel;
bi.bmiHeader.biCompression = BI_RGB;
// Calculate space needed for the dib bits
DWORD nBufSize = (bm.bmWidth + 1) * (bm.bmBitsPixel / 8);
nBufSize = ((nBufSize + 3) / 4) * 4;
nBufSize = nBufSize * bm.bmHeight;
HGLOBAL ghnd = GlobalAlloc(GMEM_MOVEABLE, nBufSize);
LPVOID gptr = GlobalLock(ghnd);
if (GetDIBits(dcBitmap, hBmp, 0, bm.bmHeight, gptr, &bi, 0)) {
nRet = StretchDIBits(hDCprint, xtop, ytop, fxSize, fySize, 0, 0,
bm.bmWidth, bm.bmHeight, gptr, &bi, 0, SRCCOPY);
}
GlobalUnlock(ghnd);
GlobalFree(ghnd);
DeleteDC(dcBitmap);
}
if (EndPage(hDCprint) > 0) {
EndDoc(hDCprint);
}
}
}
// Release
DeleteDC(hDC);
DeleteObject(hBmp);
ReleaseDC(0, hScreenDC);
DeleteDC(hDCprint);
}
}
return nRet;
}
LRESULT CALLBACK WndProc(IN HWND hWnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam) {
static HWND hFocus;
switch (uMsg) {
case WM_NCACTIVATE:
// Save the handle of the control that has the focus
if (wParam == 0) { hFocus = GetFocus(); }
break;
case WM_SETFOCUS:
// Post a message to set the focus later, since some
// Windows actions can steal it if we set it here
if (hFocus) {
PostMessage(hWnd, WM_APPLYFOCUS, (WPARAM) hFocus, 0);
hFocus = 0;
}
break;
case WM_APPLYFOCUS:
// Set the focus
if (wParam) { SetFocus((HWND) wParam); }
return 0;
case WM_COMMAND:
if ((HIINT(wParam) == EN_UPDATE) // Any edit control was changed
|| ((LOINT(wParam) == ID_COUNTRY) && (HIINT(wParam) == CBN_SELCHANGE))) { // The country combobox was changed
// if this is the first "change" message, we need to update the controls in the dialog box.
if (gP.isrecmodified == 0) {
gP.isrecmodified = TRUE;
SetButtonStatus(hWnd);
}
}
// Messages from controls and menu items are handled here.
switch (LOINT(wParam)) {
case IDCANCEL:
// if the Escape key has been pressed...
if (HIINT(wParam) == BN_CLICKED) {
// Shut down the application by sending a WM_CLOSE message
SendMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
}
case ID_PRIOR:
gP.currententry = max(gP.currententry - 1, 1);
// Disregard any existing editing if one of these button clicked
gP.isrecmodified = FALSE;
// Update the dialog
UdtToDialog(hWnd, gP.currententry);
// Update the Prior/} control button status
SetButtonStatus(hWnd);
return 0;
case ID_NEXT:
gP.currententry = min(gP.currententry + 1, gP.maxentries);
// Disregard any existing editing if one of these button clicked
gP.isrecmodified = FALSE;
// Update the dialog
UdtToDialog(hWnd, gP.currententry);
// Update the Prior/} control button status
SetButtonStatus(hWnd);
return 0;
case ID_FIND:
FindDialog(hWnd);
return 0;
case ID_ADD:
case ID_UPDATE:
AddUpdateRecord(hWnd, wParam);
return 0;
case ID_DELETE:
DeleteRecord(hWnd);
return 0;
case ID_PRINT:
if (PrintThisWindow(hWnd)) {
MessageBox(hWnd, L"\nAddress printed successfully.", L"Info", MB_ICONINFORMATION);
} else {
MessageBox(hWnd, L"\nUnable to print this address.", L"Printer error", MB_ICONEXCLAMATION);
}
return 0;
case ID_MENU_HELP:
MessageBox(hWnd, L"Help not implemented", L"Info", MB_ICONINFORMATION);
return 0;
case ID_MENU_ABOUT:
MessageBox(hWnd, L"\nAddress Book by PowerBASIC, Inc.\n\nSDK translation by Patrice Terrier.", L"Address Book", MB_ICONINFORMATION);
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
int WINAPI wWinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPTSTR lpCmdLine, IN int nCmdShow) {
long nRet = 0;
HWND hWnd = 0, hCtrl = 0;
WNDCLASSEX wcx = { 0 };
HANDLE hFile = 0;
DWORD ByttesReaded = 0, BytesWritten = 0;
MSG msg = { 0 };
gP.usefont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); // Tahoma
gP.hinstance = hInstance;
WCHAR szFilename[] = L"UADDRESS.DAT";
DWORD BufferSize = FileSize(szFilename);
if (BufferSize) {
gP.currententry = 1;
gP.maxentries = BufferSize / sizeof(AddressType);
gAddressBook.resize(gP.maxentries);
hFile = CreateFile(szFilename, GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
ReadFile(hFile, &gAddressBook[0], BufferSize, &ByttesReaded, NULL);
CloseHandle(hFile);
}
}
WCHAR szClassName[] = L"SDKADDRESS64";
wcx.cbSize = sizeof(wcx);
long IsInitialized = GetClassInfoEx(hInstance, szClassName, &wcx);
if (!IsInitialized) {
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = WndProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = hInstance;
wcx.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH) COLOR_BTNSHADOW;
wcx.lpszMenuName = NULL;
wcx.lpszClassName = szClassName;
wcx.hIconSm = wcx.hIcon;
if (RegisterClassEx(&wcx)) { IsInitialized = TRUE; }
}
if (IsInitialized) {
long w = dpi(606); long x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
long h = dpi(462); long y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
hWnd = CreateWindowEx(WS_EX_CONTROLPARENT | WS_EX_WINDOWEDGE, szClassName, L"Address Book - flat API SDK version",
WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU | DS_3DLOOK | DS_NOFAILCREATE | DS_SETFONT | DS_CENTER,
x, y, w, h, 0, 0, hInstance, NULL);
if (hWnd) {
DWORD dwLabelStyle = WS_CHILD | WS_VISIBLE | SS_RIGHT;
DWORD dwEditStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL;
hCtrl = addLabel(hWnd, - ID_INDEX, L"Record NÂș", 455, 8, 90, 13, dwLabelStyle);
hCtrl = addLabel(hWnd, ID_INDEX, L"0 / 0", 549, 7, 38, 16, WS_CHILD | WS_VISIBLE | SS_SUNKEN | SS_CENTER);
hCtrl = addLabel(hWnd, - ID_COMPANY, L"Company", 8, 31, 90, 13, dwLabelStyle);
hCtrl = addTextBox(hWnd, ID_COMPANY, $NULL, 102, 28, 485, 19, dwEditStyle);
hCtrl = addLabel(hWnd, - ID_LASTNAME, L"Last Name", 8, 54, 90, 13, dwLabelStyle);
hCtrl = addTextBox(hWnd, ID_LASTNAME, $NULL, 102, 51, 225, 19, dwEditStyle);
hCtrl = addLabel(hWnd, - ID_FIRSTNAME, L"First", 329, 54, 27, 13, dwLabelStyle);
hCtrl = addTextBox(hWnd, ID_FIRSTNAME, $NULL, 362, 51, 225, 19, dwEditStyle);
hCtrl = addLabel(hWnd, - ID_ADDRESS1, L"Address", 8, 78, 90, 13, dwLabelStyle);
hCtrl = addTextBox(hWnd, ID_ADDRESS1, $NULL, 102, 75, 485, 19, dwEditStyle);
hCtrl = addTextBox(hWnd, ID_ADDRESS2, $NULL, 102, 99, 485, 19, dwEditStyle);
hCtrl = addTextBox(hWnd, ID_ADDRESS3, $NULL, 102, 124, 485, 19, dwEditStyle);
hCtrl = addLabel(hWnd, - ID_CITYNAME, L"City", 8, 151, 90, 13, dwLabelStyle);
hCtrl = addTextBox(hWnd, ID_CITYNAME, $NULL, 102, 148, 174, 19, dwEditStyle);
hCtrl = addLabel(hWnd, - ID_STATENAME, L"State/Province", 282, 151, 75, 13, dwLabelStyle);
hCtrl = addTextBox(hWnd, ID_STATENAME, $NULL, 362, 148, 67, 19, dwEditStyle);
hCtrl = addLabel(hWnd, - ID_ZIPCODE, L"Zip or Postal Code", 8, 177, 90, 13, dwLabelStyle);
hCtrl = addTextBox(hWnd, ID_ZIPCODE, $NULL, 102, 174, 60, 19, dwEditStyle);
hCtrl = addLabel(hWnd, - ID_COUNTRY, L"Country", 193, 177, 38, 13, dwLabelStyle);
hCtrl = addComboBox(hWnd, ID_COUNTRY, $NULL, 235, 174, 194, 170, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST | CBS_HASSTRINGS | CBS_NOINTEGRALHEIGHT);
addCountries(hCtrl);
hCtrl = addLabel(hWnd, - ID_PHONE, L"Phone", 8, 206, 90, 13, dwLabelStyle);
hCtrl = addTextBox(hWnd, ID_PHONE, $NULL, 102, 203, 225, 20, dwEditStyle);
hCtrl = addLabel(hWnd, - ID_FAX, L"Fax", 329, 206, 27, 13, dwLabelStyle);
hCtrl = addTextBox(hWnd, ID_FAX, $NULL, 362, 203, 225, 20, dwEditStyle);
hCtrl = addLabel(hWnd, - ID_EMAIL, L"Email", 8, 234, 90, 13, dwLabelStyle);
hCtrl = addTextBox(hWnd, ID_EMAIL, $NULL, 102, 231, 225, 19, dwEditStyle);
hCtrl = addLabel(hWnd, - ID_URL, L"www", 331, 234, 27, 13, dwLabelStyle);
hCtrl = addTextBox(hWnd, ID_URL, $NULL, 362, 231, 225, 19, dwEditStyle);
hCtrl = addLabel(hWnd, - ID_COMMENTS, L"Comments", 8, 260, 90, 13, dwLabelStyle);
hCtrl = addTextBox(hWnd, ID_COMMENTS, $NULL, 102, 257, 485, 105, dwEditStyle | WS_VSCROLL | ES_MULTILINE | ES_WANTRETURN);
DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
hCtrl = addButton(hWnd, ID_PRIOR, L"<< Prior", 16, 379, 60, 22, dwStyle);
hCtrl = addButton(hWnd, ID_NEXT, L"Next >>", 89, 379, 60, 22, dwStyle);
hCtrl = addButton(hWnd, ID_FIND, L"Find", 162, 379, 60, 22, dwStyle);
hCtrl = addButton(hWnd, ID_ADD, L"Add", 235, 379, 60, 22, dwStyle);
hCtrl = addButton(hWnd, ID_UPDATE, L"Update", 308, 379, 60, 22, dwStyle);
hCtrl = addButton(hWnd, ID_DELETE, L"Delete", 381, 379, 60, 22, dwStyle);
hCtrl = addButton(hWnd, ID_PRINT, L"Print", 454, 379, 60, 22, dwStyle);
hCtrl = addButton(hWnd, IDCANCEL, L"Close", 527, 379, 60, 22, dwStyle);
SetButtonStatus(hWnd);
HMENU hMenu = CreateMenu();
HMENU hPopMenu = CreatePopupMenu();
AppendMenu(hMenu, MF_POPUP, (LONG_PTR) hPopMenu, L"File");
AppendMenu(hPopMenu, 0, 2, L"Close");
hPopMenu = CreatePopupMenu();
AppendMenu(hMenu, MF_POPUP, (LONG_PTR) hPopMenu, L"Help");
AppendMenu(hPopMenu, 0, ID_MENU_HELP, L"Help");
AppendMenu(hPopMenu, MF_SEPARATOR, 0, $NULL);
AppendMenu(hPopMenu, 0, ID_MENU_ABOUT, L"About");
SetMenu(hWnd, hMenu);
UdtToDialog(hWnd, gP.currententry);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Save our data file if any changes were made
if (gP.isfilemodified) {
//array sort gAddressBook[1] FOR gP.maxentries,
// from 1 to len(gAddressBook[1].Company + gAddressBook[1].LastName)
hFile = CreateFile(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
WriteFile(hFile, &gAddressBook[0], gP.maxentries * sizeof(AddressType), &BytesWritten, NULL);
CloseHandle(hFile);
}
}
nRet = (long) msg.wParam;
}
}
return nRet;
}
Note: When dealing with pixel display you can just rely on either GetDeviceCaps(hDC, LOGPIXELSX) or GetDeviceCaps(hDC, LOGPIXELSY), because they will ALWAYS return the same value.
I have never seen a display using non-square pixels. ???
...
Hutch--
The full DPI aware projects (32-bit and 64-bit) have been attached to the first post of this thread.
...