Powerbasic Museum 2020-B

IT-Consultant: Patrice Terrier => C++ programming (SDK style) => Topic started by: Patrice Terrier on May 06, 2013, 05:50:36 PM

Title: zTrace 2.02 (C/C++ version 32/64-bit)
Post by: Patrice Terrier on May 06, 2013, 05:50:36 PM
Here is the full translation of my zTrace utility to C/C++, it works in 32 and 64-bit

Note: This version is, UNICODE only, see the new SendUnicodeToClipboard procedure that is using the CF_UNICODETEXT parameter.

The 32-bit DLL is within the \Release subfolder.
The 64-bit DLL is within the \x64\Release subfolder.

The project must be compiled with the /Gz option (stdcall) for WINAPI compatibility.

And here is the full source code of the project:

//+--------------------------------------------------------------------------+
//|                                                                          |
//|                               zTrace 2.02                                |
//|                                                                          |
//|                      Win32 SDK debugging window DLL                      |
//|                                                                          |
//+--------------------------------------------------------------------------+
//|                                                                          |
//|                         Author Patrice TERRIER                           |
//|                                                                          |
//|                         copyright(c) 2009-2013                           |
//|                                                                          |
//|                Patrice Terrier http://www.zapsolution.com                |
//|                                                                          |
//+--------------------------------------------------------------------------+
//|                  Project started on : 04-04-2009 (MM-DD-YYYY)            |
//|                        Last revised : 12-13-2014 (MM-DD-YYYY)            |
//+--------------------------------------------------------------------------+

#include <windows.h>
#include <iostream>
using namespace std;
#include <time.h>

#define ExportC extern "C" _declspec (dllexport)

#define LOWORD(l) ((WORD)(((DWORD_PTR)(l)) & 0xffff))
#define HIWORD(l) ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
#define UBOUND(T) (T.size())
#define MAKLNG(a, b) ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))

static wchar_t  *$NULL        = L"";
static wchar_t  *$ZTRACE      = L"zTrace 2.02 ";

const wchar_t   *$ANTI        = L"\\";

//----------------------------------------------------------------------

const DWORD dwStyle = WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME;
const DWORD dwExStyle = WS_EX_TOOLWINDOW;

const int HORIZONTAL_EXTENT   = 6000; // Maximum value for the horizontal scrollbar
const int MIN_WIDTH           = 300;  // default client width size
const int MIN_HEIGHT          = 65;   // default client height size

const int ID_LISTBOX          = 1;

const int IDM_About           = 101;  // menu popup
const int IDM_Hscroll         = 103;  // menu popup
const int IDM_Print           = 104;  // menu popup
const int IDM_CopyToClipboard = 105;  // menu popup
const int IDM_ClearContent    = 106;  // menu popup
const int IDM_TopMost         = 107;  // menu popup
const int IDM_Debug           = 108;  // menu popup
const int IDM_SaveCoordinates = 109;  // menu popup

struct PROP {
    HBRUSH backbrush;
    long   x;
    long   y;
    long   w;
    long   h;
    long   savecoordinates;
    long   topmost;
    long   debug;
    long   usescrollbar;
    WCHAR  caption[24];
};

PROP gP;

wstring DateTime() {
    time_t now = time(0);
    tm tstruct = { 0 };
    WCHAR buf[80] = { 0 };
    if (localtime_s(&tstruct, &now) == 0) {;
        wcsftime(buf, sizeof(buf), L"%Y%m%d,%X", &tstruct);
    }
    return buf;
}

wstring STRL$(IN long N) {
    WCHAR longstr[33] = {0};
    _ltow_s(N, longstr, 10);
    return (WCHAR*) longstr;
}

wstring LEFT$(IN wstring sBuf, IN long nLeft) {
    wstring sResult = $NULL;
    LONG_PTR nLength = max(min((long)sBuf.length(), nLeft), 0);
    if (nLength) {
        sResult = sBuf.substr(0, nLength);
    }
    return sResult;
}

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;
}

string rtrim$(IN string sBuf, IN string sChar) {
    string 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::string::npos != sChar.find(sBuf.substr(nLength - 1, 1))) {
                --nLength;
            } else {
                break;
            }
        }
        sResult = sBuf.substr(0, nLength);
    }
    return sResult;
}

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;
}

WCHAR* TEMPpath () {
    static WCHAR buf[MAX_PATH];
    DWORD nSize = GetTempPath(GetTempPath(NULL, NULL), &buf[0]);
    if (nSize) {
        if (FileSize(buf) == 0) { CreateDirectory(buf, NULL); }
    }
    return buf;
}

wstring zGetTextListbox(IN HWND hListBox, IN long nItem) {
    wstring sResult;
    long nLength = (long) SendMessage(hListBox, LB_GETTEXTLEN, nItem, 0);
    WCHAR* sItem = new WCHAR[(nLength + 1) * sizeof(WCHAR)];
    memset(&sItem[0], 0, (nLength + 1) * sizeof(WCHAR));
    nLength = (long) SendMessage(hListBox, LB_GETTEXT, (WPARAM) nItem, (LPARAM) &sItem[0]);
    sResult = (WCHAR*) sItem;
    delete [] sItem;
    return sResult;
}

string parse$(IN string sMain, IN long nIndex) {
    string sResult;
    string sDelim = ",";
    long nLength = (long) sDelim.length();
    sMain = rtrim$(sMain, sDelim); sMain += sDelim;
    if (sMain.length() && nLength) {
        size_t prev_pos = 0, pos = 0, nCount = 0;
        while( (pos = sMain.find(sDelim, pos)) != std::string::npos ) {
            string substring(sMain.substr(prev_pos, pos - prev_pos));
            ++nCount;
            if (nCount == nIndex) { sResult = substring; break; }
            prev_pos = ++pos;
        }
    }
    return sResult;
}

string str$(IN long N) {
    char longstr[33] = {0};
    _itoa_s(N, longstr, 10);
    return (char*) longstr;
}

long LongValA(IN string sNum) {
    return atol(sNum.c_str());
}

void zLoadSaveCoordinates (OUT long &x, OUT long &y, OUT long &w, OUT long &h, IN long RW) {
    HANDLE hFile;
    static string WasCoordinates;
    DWORD dwBytes = 0;
    wstring sFileName = TEMPpath();
    if (sizeof(LONG_PTR) > 4 ) {
        sFileName += L"zTrace64.cfg";
    } else {
        sFileName += L"zTrace32.cfg";
    }
    if (RW) {
        string sLim = ",";
        WasCoordinates =  str$(x);                  WasCoordinates += sLim;
        WasCoordinates += str$(y);                  WasCoordinates += sLim;
        WasCoordinates += str$(w);                  WasCoordinates += sLim;
        WasCoordinates += str$(h);                  WasCoordinates += sLim;
        WasCoordinates += str$(gP.topmost);         WasCoordinates += sLim;
        WasCoordinates += str$(gP.savecoordinates); WasCoordinates += sLim;
        WasCoordinates += str$(gP.usescrollbar);    WasCoordinates += sLim;
        WasCoordinates += str$(gP.debug);
        hFile = CreateFile((WCHAR*) sFileName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile != INVALID_HANDLE_VALUE) {
            WriteFile(hFile, (char*) WasCoordinates.c_str(), (DWORD) WasCoordinates.length(), &dwBytes, NULL);
            CloseHandle(hFile);
        }

    } else {
        if (WasCoordinates.length() == 0) {
            DWORD BufferSize = FileSize((WCHAR*) sFileName.c_str());
            if (BufferSize) {
                hFile = CreateFile((WCHAR*) sFileName.c_str(), GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
                if (hFile != INVALID_HANDLE_VALUE) {
                    WasCoordinates.assign(BufferSize, 32);
                    ReadFile(hFile, (char*) WasCoordinates.c_str(), BufferSize, &dwBytes, NULL);
                    CloseHandle(hFile);
                }
            }
            x = LongValA(parse$(WasCoordinates, 1));
            y = LongValA(parse$(WasCoordinates, 2));
            w = LongValA(parse$(WasCoordinates, 3));
            h = LongValA(parse$(WasCoordinates, 4));
            gP.topmost          = LongValA(parse$(WasCoordinates, 5));
            gP.savecoordinates  = LongValA(parse$(WasCoordinates, 6)); if (gP.savecoordinates == 0) { w = 0; }
            gP.usescrollbar     = LongValA(parse$(WasCoordinates, 7));
            gP.debug            = LongValA(parse$(WasCoordinates, 8));
        }
        if ((w == 0) || (h == 0)) { w = MIN_WIDTH; h = MIN_HEIGHT; x = 0; y = 0; }
    }
}

long WstringToChar(IN wstring sTxt, OUT char* szTxt) {
    size_t convertedChars = 0;
    wcstombs_s(&convertedChars, szTxt, sTxt.length() + 1, sTxt.c_str(), _TRUNCATE);
    return (long) max(convertedChars - 1, 0);
}

// Copy any debug string to a sequential ASCII file.
void zDebug (WCHAR* zMessage) {
    static HANDLE hDebug;
    static long NeverBeenThere;
    wstring sMessage;
    long nLen = (long) wcslen(zMessage);
    if (hDebug && (nLen == 0)) {
        CloseHandle(hDebug);
        NeverBeenThere = 0;
        return;
    }
    if (nLen) {
        if (NeverBeenThere == 0) {
            NeverBeenThere = -1;
            wstring sFileName = L"zDebug.txt";
            hDebug = CreateFile((WCHAR*) sFileName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        }
        if (hDebug) {
            sMessage = (WCHAR*) zMessage; sMessage += L"\r\n";
            DWORD BytesWritten = 0;
            DWORD BufferSize = (DWORD) sMessage.length() + 1;
            char* buffer = new char[BufferSize];
            WstringToChar(sMessage, buffer);
            WriteFile(hDebug, buffer, BufferSize, &BytesWritten, NULL);
            delete [] buffer;
        }
    }
}

void SendUnicodeToClipboard (IN HWND hWnd) {
    HWND hCtrl = GetDlgItem(hWnd, ID_LISTBOX);
    long nCount = (long) SendMessage(hCtrl, LB_GETCOUNT, 0, 0);
    if (nCount > 0) {
        long nSelItems = (long) SendMessage(hCtrl, LB_GETSELCOUNT, 0, 0);
        wstring sBuffer = $NULL;
        long K;
        if (nSelItems > 0) {
            long* SelItem = new long[nSelItems];
            nCount = (long) SendMessage(hCtrl, LB_GETSELITEMS, nSelItems, (LPARAM) &SelItem[0]);
            for (K = 0; K < nSelItems; ++K) {
                nCount = SelItem[K];
                sBuffer +=  zGetTextListbox(hCtrl, SelItem[K]); sBuffer += L"\r\n";
            }
            delete [] SelItem;
        } else {
            for (K = 0; K < nCount; ++K) {
                sBuffer += zGetTextListbox(hCtrl, K); sBuffer += L"\n";
            }
        }
        nCount = (long) sBuffer.length() + 1;
        WCHAR* buffer = new WCHAR[nCount];
        memset(&buffer[0], 0, nCount * sizeof(WCHAR)); // I like to clear the new memory buffer with NULLs
        MoveMemory(&buffer[0], (WCHAR*) sBuffer.c_str(), nCount * sizeof(WCHAR));
        HGLOBAL hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, nCount * sizeof(WCHAR));
        LPVOID hGlob = GlobalLock(hClipData);
        MoveMemory(hGlob, &buffer[0], nCount * sizeof(WCHAR));
        GlobalUnlock(hClipData);
        if (OpenClipboard(0)) {
            EmptyClipboard();
            SetClipboardData(CF_UNICODETEXT, hClipData);
            CloseClipboard();
        } else {
            GlobalFree(hClipData);
        }
        delete [] buffer;
    }
}

LRESULT CALLBACK ToolProc (IN HWND hWnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam) {

    RECT rc, rw;
    long K = 0, nCount = 0, nSelItems = 0;
    HWND hCtrl = 0;
    wstring sMessage;
    MINMAXINFO pMM = {0};
    PRINTDLG pd = {0};
    DOCINFO di = {0};
    TEXTMETRIC tm = {0};
    long yChar, nLinesPerPage, nCharsPerLine;

    long wP = LOWORD(wParam);

    switch (uMsg) {

    case WM_CREATE:
         if (gP.backbrush == 0) { gP.backbrush = CreateSolidBrush(0x00FFFF); }
         break;

    case WM_GETMINMAXINFO:
         MoveMemory(&pMM, (MINMAXINFO*) lParam, sizeof(pMM));
         SetRect(&rc, 0, 0, MIN_WIDTH, MIN_HEIGHT);
         AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);  // Adjust Window To True Requested Size
         pMM.ptMinTrackSize.x = rc.right;
         pMM.ptMinTrackSize.y = rc.bottom;
         break;

    case WM_COMMAND:

         switch (wP) {
         case IDCANCEL:
              if (HIWORD(wParam) == BN_CLICKED) {
                 SendMessage(hWnd, WM_CLOSE, 0, 0);
                 return 0;
              }
              break;

         case IDM_About:
              sMessage =  L"           Debugging window\n\nCopyright © ";
              sMessage += LEFT$(DateTime(), 4);
              sMessage += L" Patrice TERRIER  "
                          L"\n       pterrier@zapsolution.com"
                          L"\n\n          www.zapsolution.com";
              MessageBox(0, (WCHAR*) sMessage.c_str(), gP.caption, MB_OK);
              break;

         case IDM_Hscroll:
              hCtrl = GetDlgItem(hWnd, ID_LISTBOX);
              gP.usescrollbar = !gP.usescrollbar;
              if (gP.usescrollbar) {
                  ShowScrollBar(hCtrl, SB_HORZ, TRUE);
                  SendMessage(hCtrl, LB_SETHORIZONTALEXTENT, HORIZONTAL_EXTENT, 0);
              } else {
                  SendMessage(hCtrl, LB_SETHORIZONTALEXTENT, 1, 0);
                  ShowScrollBar(hCtrl, SB_HORZ, FALSE);
              }
              UpdateWindow(hCtrl);
              break;

         case IDM_Print:
              hCtrl = GetDlgItem(hWnd, ID_LISTBOX);
              nCount = (long) SendMessage(hCtrl, LB_GETCOUNT, 0, 0);
              if (nCount > 0) {
                  PRINTDLG pd = {0};
                  pd.lStructSize = sizeof(pd);
                  // get rid of PD_RETURNDEFAULT on the line below if you'd like to
                  // see the "Printer Settings" dialog!
                  pd.Flags = PD_RETURNDEFAULT | PD_RETURNDC;
                  if (PrintDlg(&pd)) {
                      HDC hPrinter = pd.hDC;
                      GetTextMetrics(pd.hDC, &tm);

                      yChar = tm.tmHeight + tm.tmExternalLeading;
                      nLinesPerPage = GetDeviceCaps(pd.hDC, VERTRES) / yChar;
                      nCharsPerLine = GetDeviceCaps(pd.hDC, HORZRES) / tm.tmAveCharWidth;

                      di.cbSize = sizeof(di);
                      StartDoc(hPrinter, &di);
                          StartPage(hPrinter);
                              nSelItems = (long) SendMessage(hCtrl, LB_GETSELCOUNT, 0, 0);
                              if (nSelItems > 0) {
                                  long* SelItem = new long[nSelItems];
                                  nCount = (long) SendMessage(hCtrl, LB_GETSELITEMS, nSelItems, (LPARAM) &SelItem[0]);
                                  for (K = 0; K < nSelItems; K++) {
                                       sMessage = zGetTextListbox(hCtrl, SelItem[K]);
                                       TextOut(pd.hDC, 0, (yChar * K), (WCHAR*) sMessage.c_str(), (long) sMessage.length());
                                  }
                              } else {
                                  for (K = 0; K < nCount; K++) {
                                       sMessage = zGetTextListbox(hCtrl, K);
                                       TextOut(pd.hDC, 0, (yChar * K), (WCHAR*) sMessage.c_str(), (long) sMessage.length());
                                  }
                              }
                          EndPage(hPrinter);
                      EndDoc(hPrinter);
                      DeleteDC(hPrinter);
                  }
              }
              break;

         case IDM_CopyToClipboard:
              SendUnicodeToClipboard(hWnd);
              break;

         case IDM_ClearContent:
              SendMessage(GetDlgItem(hWnd, ID_LISTBOX), LB_RESETCONTENT, 0, 0);
              break;

         case IDM_TopMost:
              gP.topmost = !gP.topmost;
              if (gP.topmost) {
                  SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
              } else {
                  SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
              }
              break;

         case IDM_Debug:
              gP.debug = !gP.debug ;
              if (gP.debug) {
                  hCtrl = GetDlgItem(hWnd, ID_LISTBOX);
                  nCount = (long) SendMessage(hCtrl, LB_GETCOUNT, 0, 0)   ;
                  if (nCount > 0) {
                      for (K = 0; K < nCount; ++K) {
                          zDebug((WCHAR*) zGetTextListbox(hCtrl, K).c_str());
                      }
                  }
              } else {
                  zDebug($NULL); // Close zDebug.txt if already open.
              }
              break;

         case IDM_SaveCoordinates:
              gP.savecoordinates = !gP.savecoordinates;
              break;
         }
         break;

    case WM_CTLCOLORDLG:
         SetBkColor((HDC) wParam, GetSysColor(COLOR_WINDOW));
         return (LRESULT) GetStockObject(NULL_BRUSH);

    case WM_CTLCOLORLISTBOX:
         // wParam is handle of control's display context (hDC)
         // lParam is handle of control
         //------------------------------------------------------
         if (lParam == (LPARAM) GetDlgItem(hWnd, ID_LISTBOX)) {
             SetBkColor((HDC) wParam, 0x00FFFF);
             return (LRESULT) gP.backbrush;
         }
         break;

    case WM_RBUTTONDOWN:
         HMENU hMenu; POINT p;
         long menuStyle, nChoice;
         hMenu = CreatePopupMenu();
         if (hMenu) {
             AppendMenu(hMenu, MF_STRING, IDM_About            , L"About");
             AppendMenu(hMenu, MF_SEPARATOR, 102               , L"");
             if (gP.usescrollbar) { menuStyle = MF_STRING | MF_CHECKED; } else { menuStyle = MF_STRING; }
             AppendMenu(hMenu, menuStyle,  IDM_Hscroll         , L"Use horizontal scrollbar");
             AppendMenu(hMenu, MF_STRING,  IDM_Print           , L"Send selection to printer");
             AppendMenu(hMenu, MF_STRING,  IDM_CopyToClipboard , L"Copy selection to clipboard");
             AppendMenu(hMenu, MF_STRING,  IDM_ClearContent    , L"Clear content");
             if (gP.topmost) { menuStyle = MF_STRING | MF_CHECKED; } else { menuStyle = MF_STRING; }
             AppendMenu(hMenu, menuStyle,  IDM_TopMost         , L"Set window TopMost");
             if (gP.debug) { menuStyle = MF_STRING | MF_CHECKED; } else { menuStyle = MF_STRING; }
             AppendMenu(hMenu, menuStyle,  IDM_Debug           , L"Create zDebug.txt report");
             if (gP.savecoordinates) { menuStyle = MF_STRING | MF_CHECKED; } else { menuStyle = MF_STRING; }
             AppendMenu(hMenu, menuStyle,  IDM_SaveCoordinates , L"Save window coordinates");

             GetCursorPos(&p);
             nChoice = TrackPopupMenuEx(hMenu, TPM_RETURNCMD, p.x, p.y, hWnd, NULL);
             DestroyMenu(hMenu);
             if (nChoice) { SendMessage(hWnd, WM_COMMAND, MAKLNG(nChoice, 0), 0); }
         }
         break;

    case WM_MOVE:
         GetWindowRect(hWnd, &rw); gP.x = rw.left; gP.y = rw.top;
         break;

    case WM_SIZE:
         if (wParam != SIZE_MINIMIZED) {
             gP.w = LOWORD(lParam); gP.h = HIWORD(lParam);
             MoveWindow(GetDlgItem(hWnd, ID_LISTBOX), 0, 0, gP.w, gP.h, TRUE);
             UpdateWindow(hWnd);

             GetWindowRect(hWnd, &rw); gP.x = rw.left; gP.y = rw.top;

         }
         break;

    case WM_DESTROY:
         if (gP.backbrush) {
             DeleteObject(gP.backbrush); gP.backbrush = 0;
             zLoadSaveCoordinates (gP.x, gP.y, gP.w, gP.h, 1);
         }
         zDebug($NULL);
         PostQuitMessage(0);
         return 0;

    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

long AddString(IN HWND hCtrl, WCHAR* zPtr) {
    long nRet;
    if (gP.debug) {
        if (zPtr) { zDebug(zPtr); }
    }
    nRet = (long) SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM) zPtr);

    SendMessage(hCtrl, LB_SETTOPINDEX, (WPARAM) nRet, 0);

    return nRet;
}

DWORD WINAPI ShowPopup (IN WCHAR* zPtr) {
    DWORD nRet = 0;
    MSG msg;
    long IsInitialized = 0;
    HWND hWnd, hCtrl;
    HINSTANCE hInstance = GetModuleHandle(NULL);

    WNDCLASSEX wcx = { 0 };
    RECT rc = { 0 };

    wstring sCaption = $ZTRACE; sCaption += STRL$(sizeof(LONG_PTR) * 8); sCaption += L"-bit";
    MoveMemory(&gP.caption[0], (WCHAR*) sCaption.c_str(), sCaption.length() * 2);

    wcx.cbSize = sizeof(wcx);
    IsInitialized = GetClassInfoEx(hInstance, gP.caption, &wcx);
    if (IsInitialized    == 0) {
        wcx.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
        wcx.lpfnWndProc   = &ToolProc;
        wcx.cbClsExtra    = 0;
        wcx.cbWndExtra    = 0;
        wcx.hInstance     = hInstance;
        wcx.hIcon         = 0;
        wcx.hCursor       = LoadCursor(NULL, IDC_ARROW);
        wcx.hbrBackground = (HBRUSH) COLOR_BTNSHADOW;
        wcx.lpszMenuName  = NULL;
        wcx.lpszClassName = gP.caption;
        wcx.hIconSm       = wcx.hIcon;
        if (RegisterClassEx(&wcx)) { IsInitialized = TRUE; }
    }

    if (IsInitialized) {
        long UseX = 0, UseY = 0, UseW = 0, UseH = 0;
        zLoadSaveCoordinates (UseX, UseY, UseW, UseH, 0);

        SetRect(&rc, 0, 0, UseW, UseH);
        AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);  // Adjust Window To True Requested Size

        hWnd = CreateWindowEx(dwExStyle, gP.caption, gP.caption,
                              dwStyle,
                              UseX, UseY,
                              rc.right - rc.left,  // Calculate Window Width
                              rc.bottom - rc.top,  // Calculate Window Height
                              0, 0, hInstance, NULL);
        if (hWnd) {
            DWORD nStyle = WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | LBS_MULTIPLESEL | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | LBS_DISABLENOSCROLL;
            hCtrl = CreateWindowEx(0, L"ListBox", NULL, nStyle, 0, 0, UseW, UseH, hWnd, (HMENU) ID_LISTBOX, hInstance, NULL);
            SendMessage(hCtrl, WM_SETFONT, (WPARAM) GetStockObject(ANSI_FIXED_FONT), 0);
            AddString(hCtrl, zPtr);
            if (gP.usescrollbar) {
                SendMessage(hCtrl, LB_SETHORIZONTALEXTENT, HORIZONTAL_EXTENT, 0);
                ShowScrollBar(hCtrl, SB_HORZ, TRUE);
            } else {
                ShowScrollBar(hCtrl, SB_HORZ, FALSE);
            }
       
            if (gP.topmost) {
                SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
            } else {
                ShowWindow(hWnd, SW_SHOW);
            }
            UpdateWindow(hWnd);
       
            while (GetMessage(&msg, NULL, 0, 0)) {
                // Easier to detect the right mouse button click on the listBox from the message pump
                if ((msg.hwnd == hCtrl) && (msg.message == WM_RBUTTONDOWN)) {
                    ToolProc(hWnd, WM_RBUTTONDOWN, 0, 0);
                } else {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }
            nRet = (DWORD) msg.wParam;
        }
    }
    return nRet;
}

ExportC long zTrace (IN WCHAR* zPtr) {
    long nRet = 0;
    HWND hWnd = FindWindow(gP.caption, gP.caption);
    if (hWnd == 0) {
        nRet = LB_ERR;
        DWORD dwThreadId = 0;
        HANDLE hThread = CreateThread(NULL,                                  // default security attributes
                                      0,                                     // use default stack size
                                      (LPTHREAD_START_ROUTINE ) ShowPopup,   // thread function name
                                      zPtr,                                  // argument to thread function
                                      0,                                     // use default creation flags
                                      &dwThreadId);                          // returns the thread identifier
        if (hThread) {
            nRet = 0; Sleep(100);
        }
        CloseHandle(hThread);

    } else {
        if (wcslen(zPtr)) { nRet = AddString(GetDlgItem(hWnd, ID_LISTBOX), zPtr); }
    }
    return nRet;
}

BOOL WINAPI DllMain(IN HINSTANCE hDllHandle, IN DWORD nReason, IN LPVOID Reserved) {
    BOOL bRet = TRUE;
    if (nReason == DLL_PROCESS_DETACH) {
        if (gP.backbrush) {
            DeleteObject(gP.backbrush); gP.backbrush = 0;
            zLoadSaveCoordinates (gP.x, gP.y, gP.w, gP.h, 1);
        }
        zDebug($NULL);
    }
    return bRet;
}


The attached ZIP file comprise the C++ source code for the 32-bit and/or the 64-bit version, each one using a different name (zTrace32.dll and zTrace64.dll).

I couldn't work any more without it...   8)
Title: zTrace updated to version 2.01
Post by: Patrice Terrier on December 05, 2013, 04:56:07 PM
James--

Be happy, i have added printing support to zTrace:
Quotecase IDM_Print:
              hCtrl = GetDlgItem(hWnd, ID_LISTBOX);
              nCount = (long) SendMessage(hCtrl, LB_GETCOUNT, 0, 0);
              if (nCount > 0) {
                  PRINTDLG pd = {0};
                  pd.lStructSize = sizeof(pd);
                  // get rid of PD_RETURNDEFAULT on the line below if you'd like to
                  // see the "Printer Settings" dialog!
                  pd.Flags = PD_RETURNDEFAULT | PD_RETURNDC;
                  if (PrintDlg(&pd)) {
                      HDC hPrinter = pd.hDC;
                      GetTextMetrics(pd.hDC, &tm);

                      yChar = tm.tmHeight + tm.tmExternalLeading;
                      nLinesPerPage = GetDeviceCaps(pd.hDC, VERTRES) / yChar;
                      nCharsPerLine = GetDeviceCaps(pd.hDC, HORZRES) / tm.tmAveCharWidth;
                 
                      di.cbSize = sizeof(di);
                      StartDoc(hPrinter, &di);
                          StartPage(hPrinter);
                              nSelItems = (long) SendMessage(hCtrl, LB_GETSELCOUNT, 0, 0);
                              if (nSelItems > 0) {
                                  long* SelItem = new long[nSelItems];
                                  nCount = (long) SendMessage(hCtrl, LB_GETSELITEMS, nSelItems, (LPARAM) &SelItem[0]);
                                  for (K = 0; K < nSelItems; K++) {
                                       sMessage = zGetTextListbox(hCtrl, SelItem[K]);
                                       TextOut(pd.hDC, 0, (yChar * K), (WCHAR*) sMessage.c_str(), (long) sMessage.length());
                                  } }
                              else {
                                  for (K = 0; K < nCount; K++) {
                                       sMessage = zGetTextListbox(hCtrl, K);
                                       TextOut(pd.hDC, 0, (yChar * K), (WCHAR*) sMessage.c_str(), (long) sMessage.length());
                                  }
                              }
                          EndPage(hPrinter);
                      EndDoc(hPrinter);
                      DeleteDC(hPrinter);
                  }
              }
              break;



And here is the helper function to use zTrace from inside your code:

#define long_proc typedef long (__stdcall *zProc)
Quotelong zTrace (IN wstring 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*);
        zProc hProc = (zProc) GetProcAddress(hDll, "zTrace");
        if (hProc) { nRet = hProc((WCHAR*) sPtr.c_str()); }
    }
    return nRet;
}

The full VS2010 project is attached to the first post of this thread.
Title: zTrace 2.01 on CodeProject
Post by: Patrice Terrier on December 07, 2013, 05:27:52 PM
I did put a copy of the zTrace C++ project on CodeProject. (http://www.codeproject.com/Articles/693260/zTrace-debugging-utility)

Now let us see how they will rate this piece of SDK code  :)
Title: Re: zTrace 2.01 (C/C++ version 32/64-bit)
Post by: James C. Fuller on December 12, 2014, 05:58:40 PM
Patrice,
  Has there been an update. I notice it is a year old and you are always tinkering :)

James
Title: Re: zTrace 2.01 (C/C++ version 32/64-bit)
Post by: Patrice Terrier on December 13, 2014, 05:53:20 PM
The latest PowerBASIC version has been posted there. (http://www.powerbasic.com/support/pbforums/showthread.php?t=58637)

Switching to plain SDK flat API results in a {massive} size reduction from 49664 bytes down to 27648 bytes.  ;)

The most significant saving was to replace the XPRINT encapsulation with direct API call.

...
Title: Re: zTrace 2.02 (C/C++ version 32/64-bit)
Post by: Patrice Terrier on December 14, 2014, 11:36:40 AM
The first post of this thread has been updated to zTrace version 2.02.
both C++ 32-bit and 64-bit are inside of the zip file, under the name zTrace32.dll and zTrace64.dll.

There was a wrong "{" "}" combination in version 2.01 that was not detected by the compiler, and the C++ code has been rewritten to match as close as possible the one used in the PowerBASIC version.

...
Title: Re: zTrace 2.02 (C/C++ version 32/64-bit)
Post by: James C. Fuller on December 14, 2014, 03:19:08 PM
Patrice,
  Thank you for the update of the most used tool in my toolbox.

James
Title: Re: zTrace 2.02 (C/C++ version 32/64-bit)
Post by: Patrice Terrier on December 14, 2014, 07:47:52 PM
QuoteThank you for the update of the most used tool in my toolbox.
cool 8)

...
Title: Re: zTrace 2.02 (C/C++ version 32/64-bit)
Post by: James C. Fuller on June 22, 2016, 11:19:57 PM
Patrice,
  The debug.txt file is not an ascii text file on Windows 10.

James
Title: Re: zTrace 2.02 (C/C++ version 32/64-bit)
Post by: James C. Fuller on June 24, 2016, 05:06:59 PM
Patrice,
  I fixed it for 64bit. I don't do 32bit anymore .
The debug.txt file had a zero as the first character of every line after the first line.

In void zDebug(WCHAR* zMessage)
I changed
DWORD BufferSize = (DWORD) sMessage.length() + 1;
To
DWORD BufferSize = (DWORD)sMessage.length();

James

Title: Re: zTrace 2.02 (C/C++ version 32/64-bit)
Post by: Patrice Terrier on June 26, 2016, 02:25:56 PM
James

Thanks for the feedback, i have fixed it.

The other solution would be to use only WCHAR rather than a mix of WCHAR/WSTRING,
and a combination of wcscpy_s plus wcsncat_s altogether with the _TRUNCATE constant.

...
Title: zTrace version 3.00 64-bit
Post by: Patrice Terrier on April 18, 2017, 08:26:40 PM
Version 3.00

has been released here. (http://www.objreader.com/index.php?topic=91.0)

The whole code has been reworked to produce an amazing code size reduction from 91 down to 14 KB !!!

Credit given to Fred and James  8)
Title: Re: zTrace 2.02 (C/C++ version 32/64-bit)
Post by: Carlo Pagani on April 20, 2017, 12:10:51 PM
Hey Patrice

How do you register on the ObjReader site?
Title: Re: zTrace 2.02 (C/C++ version 32/64-bit)
Post by: Patrice Terrier on April 20, 2017, 12:53:55 PM
Carlo

Read this.
http://www.objreader.com/index.php?topic=5.0

Or send me your current email, via private message from this forum.
Title: zTrace 3.00 64-bit is also on codeproject
Post by: Patrice Terrier on April 21, 2017, 12:07:11 PM
If you want to download zTrace 3.00 64-bit, without registering onto my private forum (www.objreader.com)
then you can download the full VS 2017 community version from codeproject here:
https://www.codeproject.com/Articles/1183063/zTrace-for-bit-only

By the way with only 14Kb, it could be used to debug any unicode 64-bit application, whatever the language being used, with EXPLICIT linking.

...
Title: Re: zTrace 3.00 64-bit is also on codeproject
Post by: Andrey Unis on April 26, 2017, 01:40:46 AM
Quote from: Patrice Terrier on April 21, 2017, 12:07:11 PM
By the way with only 14Kb, it could be used to debug any unicode 64-bit application...
Can make 11kb...
By the way, there are few mistakes...
function zDebug() includes NUL characters to log file
WideCharToMultiByte(CP_ACP, 0, sMessage, -1, buffer, BufferSize - 1, 0, 0);
(but better remake this function to support unicode chars (for example chinese language))

function ToolProc()
    case WM_GETMINMAXINFO:
         MoveMemory(&pMM, (MINMAXINFO*) lParam, sizeof(pMM));
         SetRect(&rc, 0, 0, MIN_WIDTH, MIN_HEIGHT);
         AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);  // Adjust Window To True Requested Size
         pMM.ptMinTrackSize.x = rc.right;
         pMM.ptMinTrackSize.y = rc.bottom;
         break;

fix
case WM_GETMINMAXINFO:
SetRect(&rc, 0, 0, MIN_WIDTH, MIN_HEIGHT);
AdjustWindowRectEx(&rc, WND_Style, FALSE, WND_ExStyle);  // Adjust Window To True Requested Size
((LPMINMAXINFO)lParam)->ptMinTrackSize.x = rc.right;
((LPMINMAXINFO)lParam)->ptMinTrackSize.y = rc.bottom;
break;


case IDM_Print:
  ...
  long* SelItem = new long[nSelItems];
memory leak, missed: delete [] SelItem ;

my variant (11kb) attached
Title: Re: zTrace 2.02 (C/C++ version 32/64-bit)
Post by: Patrice Terrier on April 26, 2017, 09:47:39 AM
Andrey

Thank you very much for the fix.

Most are residuals of my first PowerBASIC translation at the time i was Learning C++,
zTrace was the first on my list to help me to debug my other tools.

I should have loocked more closely at my first translation.
Quote
WideCharToMultiByte(CP_ACP, 0, sMessage, -1, buffer, BufferSize - 1, 0, 0);
(but better remake this function to support unicode chars (for example chinese language))
For the debug text file, i prefer to keep using ANSI to be compatible with my old text editor,
however i shall put a new option to select between ansi or unicode.

I shall update the code with your zip file, thank you again!  8)
Title: Re: zTrace 2.02 (C/C++ version 32/64-bit)
Post by: Patrice Terrier on April 26, 2017, 04:49:18 PM
Ok, the fixes have been done
http://www.objreader.com/index.php?topic=91.msg623#new

I have also updated the codeproject submission.


Title: Re: zTrace 2.02 (C/C++ version 32/64-bit)
Post by: Patrice Terrier on April 27, 2017, 07:23:21 PM
I have merged Andrei changes into a new version, with:
further code clean up,
new font set for both the listbox window and the printer,
switched back to XP compatibility,
no more TCLib linking that has been removed.

With more features, and further code optimization, we have been able to keep the size of the 64-bit Unicode DLL at only 11 Kb.

The latest zip file is available here
http://www.objreader.com/index.php?topic=91.msg618#msg618