IT-Consultant: Frederick J. Harris > Time For 64 Bit COM!

Finished C++ Conversion Of PowerBASIC Grid Code. I'm Happy!

<< < (2/4) > >>

Frederick J. Harris:
2nd half WinCode.cpp


--- Code: ---long fnGridProc_OnKeyDown(lpWndEventArgs Wea)
{
 #if defined MYDEBUG
 _ftprintf(fp,_T("Entering fnGridProc_OnKeyDown()\n"));
 _ftprintf(fp,_T("  Wea->hWnd = %u\n"),Wea->hWnd);
 #endif
 if(Wea->wParam==VK_DELETE)
 {
    GridData* pGridData=(GridData*)GetWindowLongPtr(Wea->hWnd,0);
    if(pGridData->blnRowSelected)
    {
       #if defined MYDEBUG
       _ftprintf(fp,_T("  pGridData = %u\n"),pGridData);
       _ftprintf(fp,_T("  A Row Is Selected, Namely, Row #%d\n"),pGridData->iSelectedRow);
       #endif
       for(int i=0; i<MAX_CONNECTIONS; i++)
       {
           if(pGridData->pComObj->pISink[i])
              pGridData->pComObj->pISink[i]->Grid_OnDelete(pGridData->iSelectedRow);
       }
       pGridData->pComObj->Refresh();
    }
 }
 #if defined MYDEBUG
 _ftprintf(fp,_T("Leaving fnGridProc_OnKeyDown()\n\n"));
 #endif

 return 0;
}


long fnGridProc_OnCommand(lpWndEventArgs Wea)
{
 #if defined MYDEBUG
 _ftprintf(fp,_T("Entering fnGridProc_OnCommand()\n"));
 _ftprintf(fp,_T("  Wea->hWnd = %u\n"),Wea->hWnd);
 _ftprintf(fp,_T("  LOWORD(Wea->wParam) = %d\n"),LOWORD(Wea->wParam));
 #endif
 if(LOWORD(Wea->wParam)>20000)
 {
    GridData* pGridData=(GridData*)GetWindowLongPtr(Wea->hWnd,0);
    pGridData->pComObj->FlushData();
    SCROLLINFO si;
    ZeroMemory(&si, sizeof(SCROLLINFO));
    si.cbSize = sizeof(SCROLLINFO);
    si.fMask=SIF_POS;
    GetScrollInfo(pGridData->hGrid,SB_VERT,&si);
    int iCellRow=LOWORD(Wea->wParam)-20000;
    int iGridRow=si.nPos+iCellRow-1;
    #if defined MYDEBUG
    _ftprintf(fp,_T("  iCellRow = %d\n"),iCellRow);
    _ftprintf(fp,_T("  iGridRow = %d\n"),iGridRow);
    _ftprintf(fp,_T("  pGridData->blnRowSelected = %d\n"),pGridData->blnRowSelected);
    #endif
    if(pGridData->blnRowSelected)
    {
       if(iGridRow==pGridData->iSelectedRow)
       {
           #ifdef MYDEBUG
           _ftprintf(fp,_T("  We Got In Where iGridRow = @pGridData.iSelectedRow!\n"));
           #endif
           for(int i=1; i<=pGridData->iCols; i++)
               pGridData->pComObj->SetCellAttributes(pGridData->iSelectedRow,i,0x00FFFFFF,0);
           pGridData->iSelectedRow=0, pGridData->blnRowSelected=FALSE;
       }
       else
       {
           #ifdef MYDEBUG
           _ftprintf(fp,_T("  We Got In Where iGridRow != pGridData->iSelectedRow!\n"));
           #endif
           for(int i=1; i<=pGridData->iCols; i++)
               pGridData->pComObj->SetCellAttributes(pGridData->iSelectedRow,i,0x00FFFFFF,0);
           pGridData->iSelectedRow=iGridRow;
           for(int i=1; i<=pGridData->iCols; i++)
               pGridData->pComObj->SetCellAttributes(iGridRow,i,pGridData->iSelectionBackColor,pGridData->iSelectionTextColor);
       }
    }
    else
    {
       #ifdef MYDEBUG
       _ftprintf(fp,_T("  We Got In Where pGridData->blnSelected = FALSE!\n"));
       _ftprintf(fp,_T("  pGridData->iSelectionBackColor         = 0x%x\n"),pGridData->iSelectionBackColor);
       _ftprintf(fp,_T("  pGridData->iSelectionTextColor         = 0x%x\n"),pGridData->iSelectionTextColor);
       #endif
       for(int i=1; i<=pGridData->iCols; i++)
           pGridData->pComObj->SetCellAttributes(iGridRow,i,pGridData->iSelectionBackColor,pGridData->iSelectionTextColor);
       pGridData->blnRowSelected=TRUE;
       pGridData->iSelectedRow=iGridRow;
       #ifdef MYDEBUG
       _ftprintf(fp,_T("  pGridData.iSelectedRow    = %d\n"),pGridData->iSelectedRow);
       _ftprintf(fp,_T("  pGridData->blnRowSelected = %d\n"),pGridData->blnRowSelected);
       #endif
    }
    pGridData->pComObj->Refresh();
    for(int i=0; i<MAX_CONNECTIONS; i++)
    {
        if(pGridData->pComObj->pISink[i])
           pGridData->pComObj->pISink[i]->Grid_OnRowSelection(iGridRow,pGridData->blnRowSelected);
    }
    SetFocus(Wea->hWnd);
 }
 #if defined MYDEBUG
 _ftprintf(fp,_T("Leaving fnGridProc_OnCommand()\n\n"));
 #endif

 return 0;
}


long fnGridProc_OnDestroy(lpWndEventArgs Wea)
{
 GridData* pGridData=NULL;
 HANDLE hHeap=NULL;
 TCHAR* pMem=NULL;
 BOOL blnFree=0;
 int iCtr=0,i,j;

 #if defined MYDEBUG
 _ftprintf(fp,_T("Entering fnGridProc_OnDestroy()\n"));
 #endif
 pGridData=(GridData*)GetWindowLongPtr(Wea->hWnd,0);
 #if defined MYDEBUG
 _ftprintf(fp,_T("  Wea->hWnd                           = %u\n"),Wea->hWnd);
 _ftprintf(fp,_T("  pGridData                           = %u\n\n"),pGridData);
 #endif
 if(pGridData)
 {
    #if defined MYDEBUG
    _ftprintf(fp,_T("  i\tpGridData->pColWidths[i]\n"));
    _ftprintf(fp,_T("  =============================\n"));
    for(i=0; i<5; i++)
        _ftprintf(fp,_T("  %u\t%u\n"),i,pGridData->pColWidths[i]);
    _ftprintf(fp,_T("\n  pGridData->pColWidths[5]            = %u\n"),pGridData->pColWidths[5]);
    #endif

    hHeap=GetProcessHeap();
    if(hHeap)
    {
       #if defined MYDEBUG
       _ftprintf(fp,_T("  pGridData->pColWidths               = %u\n"),pGridData->pColWidths);
       #endif
       if(pGridData->pColWidths)
          blnFree=HeapFree(hHeap,0,pGridData->pColWidths);
       #if defined MYDEBUG
       _ftprintf(fp,_T("  blnFree(pGridData->pColWidths)      = %u\n"),blnFree);
       #endif
       if(pGridData->pCellCtrlTypes)
          blnFree=HeapFree(hHeap,0,pGridData->pCellCtrlTypes);
       #if defined MYDEBUG
       _ftprintf(fp,_T("  blnFree(pGridData->pCellCtrlTypes)  = %u\n"),blnFree);
       #endif
       if(pGridData->pCtrlHdls)
          blnFree=HeapFree(hHeap,0,pGridData->pCtrlHdls);
       #if defined MYDEBUG
       _ftprintf(fp,_T("  blnFree(pGridData->pCtrlHdls)       = %u\n"),blnFree);
       #endif
       if(pGridData->pVButtons)
       {
          blnFree=HeapFree(hHeap,0,pGridData->pVButtons);
          pGridData->pVButtons=NULL;
          #if defined MYDEBUG
          _ftprintf(fp,_T("  blnFree(pGridData->pVButtons)       = %u\n"),blnFree);
          #endif
       }

       if(pGridData->hFont)
       {
          blnFree=DeleteObject(pGridData->hFont);
          #if defined MYDEBUG
          _ftprintf(fp,_T("  blnFree(pGridData->hFont)           = %u\n"),blnFree);
          #endif
       }

       if(pGridData->pCellHandles)
       {
          blnFree=HeapFree(hHeap,0,pGridData->pCellHandles);
          #if defined MYDEBUG
          _ftprintf(fp,_T("  blnFree(pGridData->pCellHandles)    = %u\n"),blnFree);
          #endif
          blnFree=0;
       }

       #if defined MYDEBUG
       _ftprintf(fp,_T("\n"));
       _ftprintf(fp,_T("  i             j               iCtr            pMem            pMem            blnFree\n"));
       _ftprintf(fp,_T("  =====================================================================================\n"));
       #endif
       for(i=1; i<=pGridData->iRows; i++)
       {
         for(j=1; j<=pGridData->iCols; j++)
         {
           pMem=pGridData->pGridMemory[iCtr];
           if(pMem)
           {
              #if defined MYDEBUG
              _ftprintf(fp,_T("  %d\t\t%d\t\t%d\t\t%u\t\t%s\t\t"),i,j,iCtr,pMem,pMem);
              #endif
              blnFree=HeapFree(hHeap,0,pMem);
              pMem=NULL;
              #ifdef MYDEBUG
              _ftprintf(fp,_T("%d\n"),blnFree);
              #endif
              blnFree=0;
           }
           else
           {
              #if defined MYDEBUG
              _ftprintf(fp,_T("  %d\t\t%d\t\t%d\t\t%u\t\t%s\t\t%d\n"),i,j,iCtr,pMem,pMem,blnFree);
              #endif
           }
           iCtr++;
         }
       }

       if(pGridData->pGridMemory)
       {
          blnFree=HeapFree(hHeap,0,pGridData->pGridMemory);
          #if defined MYDEBUG
          _ftprintf(fp,_T("\n  blnFree(pGridData->pGridMemory)     = %u\n"),blnFree);
          #endif
       }
       if(pGridData->pTextColor)
       {
          blnFree=HeapFree(hHeap,0,pGridData->pTextColor);
          #if defined MYDEBUG
          _ftprintf(fp,_T("  blnFree(pGridData->pTextColor)      = %u\n"),blnFree);
          #endif
       }
       if(pGridData->pBackColor)
       {
          blnFree=HeapFree(hHeap,0,pGridData->pBackColor);
          #if defined MYDEBUG
          _ftprintf(fp,_T("  blnFree(pGridData->pBackColor)      = %u\n"),blnFree);
          #endif
       }

       #if defined MYDEBUG
       _ftprintf(fp,_T("  pGridData->pCreatedBrushes[0]       = %d\n"),pGridData->pCreatedBrushes[0]);
       _ftprintf(fp,_T("  pGridData->pCreatedColors[0]        = %d\n\n"),pGridData->pCreatedColors[0]);
       _ftprintf(fp,_T("  i\tDeleteObject(i)\n"));
       _ftprintf(fp,_T("  =====================\n"));
       #endif
       for(i=1; i<=(int)pGridData->pCreatedBrushes[0]; i++)
       {
           if(pGridData->pCreatedBrushes[i])
           {
              blnFree=DeleteObject(pGridData->pCreatedBrushes[i]);
              #if defined MYDEBUG
              _ftprintf(fp,_T("  %d\t%d\n"),i,blnFree);
              #endif
           }
       }
       if(pGridData->pCreatedColors)
       {
          blnFree=HeapFree(hHeap,0,pGridData->pCreatedColors);
          #if defined MYDEBUG
          _ftprintf(fp,_T("\n  blnFree(pGridData->pCreatedColors)  = %u\n"),blnFree);
          #endif
       }
       if(pGridData->pCreatedBrushes)
       {
          blnFree=HeapFree(hHeap,0,pGridData->pCreatedBrushes);
          #if defined MYDEBUG
          _ftprintf(fp,_T("  blnFree(pGridData->pCreatedBrushes) = %u\n"),blnFree);
          #endif
       }
       blnFree=HeapFree(hHeap,0,pGridData);
       #if defined MYDEBUG
       _ftprintf(fp,_T("  blnFree                             = %u\n"),blnFree);
       #endif
    }
 }
 #if defined MYDEBUG
 _ftprintf(fp,_T("Leaving fnGridProc_OnDestroy()\n\n"));
 #endif

 return 0;
}


LRESULT CALLBACK fnGridProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 WindowsEventArguments Wea;

 for(unsigned int i=0; i<7; i++)     // dim(EventHandler); i++)
 {
     if(EventHandler[i].iMsg==msg)
     {
        Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
        return (*EventHandler[i].fnPtr)(&Wea);
     }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


LRESULT CALLBACK fnPaneProc(HWND hPane, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 if(msg==WM_NOTIFY)
 {
    int iCols,iRange,index,iHt;
    GridData* pGridData=NULL;
    NMHEADER* pNotify=NULL;
    SCROLLINFO si;

    #if defined MYDEBUG
    _ftprintf(fp,_T("Entering fnPaneProc() -- WM_NOTIFY Case\n"));
    #endif
    pNotify=(NMHEADER*)lParam;
    pGridData=(GridData*)GetWindowLongPtr(hPane,0);
    iCols=pGridData->iCols;
    #ifdef MYDEBUG
    _ftprintf(fp,_T("  pGridData              = %u\n"),pGridData);
    _ftprintf(fp,_T("  pGridData->iCols       = %d\n"),pGridData->iCols);
    _ftprintf(fp,_T("  pGridData->pComObj     = %u\n"),pGridData->pComObj);
    _ftprintf(fp,_T("  pGridData->hCtrlInCell = %u\n"),pGridData->hCtrlInCell);
    #endif
    switch(pNotify->hdr.code)
    {
      case HDN_TRACK:
        {
           #ifdef MYDEBUG
           _ftprintf(fp,_T("  Got HDN_TRACK Notification\n"));
           #endif
           if(pGridData->hCtrlInCell)
           {
              pGridData->pComObj->FlushData();
              pGridData->pComObj->Refresh();
           }
           if(pGridData->pColWidths)
           {
              pGridData->pColWidths[pNotify->iItem]=pNotify->pitem->cxy;
              #ifdef MYDEBUG
              _ftprintf(fp,_T("  pNotify->iItem         = %d\n"),pNotify->iItem);
              _ftprintf(fp,_T("  pNotify->pitem->cxy    = %d\n"),pNotify->pitem->cxy);
              #endif
           }
           pGridData->pColWidths[iCols]=0;
           for(int i=0; i<iCols; i++)
               pGridData->pColWidths[iCols]=pGridData->pColWidths[iCols]+pGridData->pColWidths[i];

           si.cbSize = sizeof(SCROLLINFO);
           si.fMask  = SIF_RANGE|SIF_PAGE|SIF_DISABLENOSCROLL;
           si.nMin   = 0;
           si.nMax   = pGridData->pColWidths[iCols];
           si.nPage  = pGridData->cx-33;
           iRange    = si.nMax-si.nMin;
           SetScrollInfo(pGridData->hGrid,SB_HORZ,&si,TRUE);
           if(iRange>si.nPage)
              SetWindowPos(pGridData->hPane,HWND_TOP,0,0,pGridData->pColWidths[iCols],pGridData->cy,SWP_NOMOVE|SWP_SHOWWINDOW);
           else
              SetWindowPos(pGridData->hPane,HWND_TOP,0,0,pGridData->pColWidths[iCols],pGridData->cy,SWP_SHOWWINDOW);
           SetWindowPos(pGridData->hHeader,HWND_BOTTOM,0,0,pGridData->pColWidths[iCols],pGridData->iRowHeight,SWP_NOMOVE|SWP_SHOWWINDOW);
           #ifdef MYDEBUG
           _ftprintf(fp,_T("    si.nMin                       = %u\n"),si.nMin);
           _ftprintf(fp,_T("    si.nMax                       = %u\n"),si.nMax);
           _ftprintf(fp,_T("    si.nPage                      = %u\n"),si.nPage);
           _ftprintf(fp,_T("    iRange                        = %d\n"),iRange);
           _ftprintf(fp,_T("    pGridData->pColWidths[iCols]  = %d\n"),pGridData->pColWidths[iCols]);
           #endif

           HANDLE hHeap=GetProcessHeap();
           int* pPos=(int*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iCols*sizeof(int));
           if(!pPos)
              return 0;
           for(int i=1; i<iCols; i++)
               pPos[i]=pPos[i-1]+pGridData->pColWidths[i-1];
           if(pGridData->pCellHandles)
           {
              for(int i=0; i<pGridData->iVisibleRows; i++)
              {
                  for(int j=0; j<iCols; j++)
                  {
                      index=iCols*i+j;
                      iHt=pGridData->iRowHeight;
                      MoveWindow(pGridData->pCellHandles[index], pPos[j], iHt+(i*iHt), pGridData->pColWidths[j], iHt, FALSE);
                  }
              }
              InvalidateRect(pGridData->hGrid,NULL,TRUE);
           }
           HeapFree(hHeap,0,pPos);
           break;
        }
      case HDN_ENDTRACK:
        {
           #if defined MYDEBUG
           _ftprintf(fp,_T("  Got HDN_TRACK Notification\n"));
           #endif
           InvalidateRect(pGridData->hGrid,0,TRUE);
           break;
        }
    }
    #if defined MYDEBUG
    _ftprintf(fp,_T("Leaving fnPaneProc() -- WM_NOTIFY Case\n\n"));
    #endif
 }

 return (DefWindowProc(hPane, msg, wParam, lParam));
}


LRESULT CALLBACK fnBaseProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


LRESULT CALLBACK fnEditSubClass(HWND hEdit, UINT msg, WPARAM wParam, LPARAM lParam)
{
 int blnCancel=0;
 HWND hCell=GetParent(hEdit);
 HWND hPane=GetParent(hCell);
 HWND hBase=GetParent(hPane);
 HWND hGrid=GetParent(hBase);
 GridData* pGridData=(GridData*)GetWindowLongPtr(hGrid,0);
 switch(msg)
 {
   case WM_CHAR:
     {
        #ifdef MYDEBUG
        _ftprintf(fp,_T("Entering fnEditSubClass()  -- Case WM_CHAR\n"));
        _ftprintf(fp,_T("  hEdit     = %u\n"),hEdit);
        _ftprintf(fp,_T("  hCell     = %u\n"),hCell);
        _ftprintf(fp,_T("  hPane     = %u\n"),hPane);
        _ftprintf(fp,_T("  hBase     = %u\n"),hBase);
        _ftprintf(fp,_T("  hGrid     = %u\n"),hGrid);
        _ftprintf(fp,_T("  pGridData = %u\n"),pGridData);
        _ftprintf(fp,_T("  wParam    = %c\n"),wParam);
        #endif
        for(int i=0; i<MAX_CONNECTIONS; i++)
        {
            if(pGridData->pComObj->pISink[i])
            {
               pGridData->pComObj->pISink[i]->Grid_OnKeyPress((int)wParam, (int)lParam, pGridData->iEditedRow, pGridData->iEditedCol, &blnCancel);
               if(blnCancel)
                  return 0;
            }
        }
        if(wParam==VK_RETURN)
        {
           pGridData->pComObj->FlushData();
           pGridData->pComObj->Refresh();
           return 0;
        }
        else
           pGridData->hCtrlInCell=hEdit;
        #ifdef MYDEBUG
        _ftprintf(fp,_T("Leaving fnEditSubClass()\n"));
        #endif
        break;
     }
   case WM_KEYDOWN:
     {
        #ifdef MYDEBUG
        _ftprintf(fp,_T("Entering fnEditSubClass()  -- Case WM_KEYDOWN\n"));
        _ftprintf(fp,_T("  hEdit = %u\n"),hEdit);
        _ftprintf(fp,_T("  hCell = %u\n"),hCell);
        _ftprintf(fp,_T("  hPane = %u\n"),hPane);
        _ftprintf(fp,_T("  hBase = %u\n"),hBase);
        _ftprintf(fp,_T("  hGrid = %u\n"),hGrid);
        _ftprintf(fp,_T("  pGridData = %u\n"),pGridData);
        #endif
        for(int i=0; i<MAX_CONNECTIONS; i++)
        {
            if(pGridData->pComObj->pISink[i])
            {
               pGridData->pComObj->pISink[i]->Grid_OnKeyDown((int)wParam, (int)lParam, pGridData->iEditedCellRow, pGridData->iEditedRow, pGridData->iEditedCol, &blnCancel);
               if(blnCancel)
                  return 0;
            }
        }
        #ifdef MYDEBUG
        _ftprintf(fp,_T("Leaving fnEditSubClass()\n"));
        #endif
        break;
     }
   case WM_PASTE:
     {
        for(int i=0; i<MAX_CONNECTIONS; i++)
        {
            if(pGridData->pComObj->pISink[i])
            {
               pGridData->pComObj->pISink[i]->Grid_OnPaste(pGridData->iEditedCellRow, pGridData->iEditedRow, pGridData->iEditedCol);
               if(blnCancel)
                  return 0;
            }
        }
        break;
     }
   case WM_LBUTTONDBLCLK:
     {
        for(int i=0; i<MAX_CONNECTIONS; i++)
        {
            if(pGridData->pComObj->pISink[i])
            {
               pGridData->pComObj->pISink[i]->Grid_OnLButtonDblClk(pGridData->iEditedCellRow, pGridData->iEditedRow, pGridData->iEditedCol);
               if(blnCancel)
                  return 0;
            }
        }
        break;
     }

 }

 return CallWindowProc(fnEditWndProc,hEdit,msg,wParam,lParam);
}


BOOL CALLBACK EnumGridProc(HWND hWnd, LPARAM lParam)
{
 #ifdef MYDEBUG
 _ftprintf(fp,_T("  Called EnumGridProc() - %u\t%u\n"),hWnd,lParam);
 #endif
 if(GetClassLongPtr(hWnd,GCLP_WNDPROC)==lParam)
 {
    #ifdef MYDEBUG
    _ftprintf(fp,_T("\n  Made A Match! - %u\t%u\n\n"),hWnd,lParam);
    #endif
    GridData* pGridData=(GridData*)GetWindowLongPtr(hWnd,0);
    pGridData->pComObj->FlushData();
 }

 return TRUE;
}


/*
' Offset     What's Stored There in WNDCLASSEX::cbWndExtra Bytes
' ==============================================================
' 0  -  3    pZStr, i.e., pointer to string data (ZStr) for cell      0  -  7
' 4  -  7    hFont, i.e., this was created in fnWndProc_OnCreate      8  -  15
' 8  - 11    dwColor, i.e., text color, and an RGB value             16  -  23
' 12 - 15    HBrush, and this is a HANDLE                            24  -  31
*/

LRESULT CALLBACK fnCellProc(HWND hCell, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 switch(msg)
 {
   case WM_CREATE:
     {
        SetWindowLongPtr(hCell,0,NULL);
        return 0;
     }
   case WM_LBUTTONDOWN:
     {
        int iCellBufferPos=0,blnFound=0,iGridMemOffset=0,iRow,iCol,i,j;
        HWND hGrid=NULL,hBase=NULL,hPane=NULL;
        GridData* pGridData=NULL;
        TCHAR* pZStr=NULL;
        SCROLLINFO si;
        HRESULT hr;
        #ifdef MYDEBUG
        _ftprintf(fp,_T("\nEntering fnCellProc()  --  case WM_LBUTTONDOWN\n"));
        #endif
        hPane=GetParent(hCell);
        hBase=GetParent(hPane);
        hGrid=GetParent(hBase);
        pGridData=(GridData*)GetWindowLongPtr(hPane,0);
        #ifdef MYDEBUG
        _ftprintf(fp,_T("  hCell              = %u\n"),hCell);
        _ftprintf(fp,_T("  hPane              = %u\n"),hPane);
        _ftprintf(fp,_T("  hBase              = %u\n"),hBase);
        _ftprintf(fp,_T("  hGrid              = %u\n"),hGrid);
        _ftprintf(fp,_T("  pGridData->hParent = %u\n"),pGridData->hParent);
        #endif
        EnumChildWindows(pGridData->hParent,EnumGridProc,(LPARAM)fnGridProc);
        ZeroMemory(&si, sizeof(SCROLLINFO));
        si.cbSize = sizeof(SCROLLINFO), si.fMask=SIF_POS;
        GetScrollInfo(hGrid,SB_VERT,&si);
        for(i=1; i<=pGridData->iVisibleRows; i++)
        {
            for(j=1; j<=pGridData->iCols; j++)
            {
                iCellBufferPos = dwIdx(i,j);
                if(pGridData->pCellHandles[iCellBufferPos]==hCell)
                {
                   iGridMemOffset = pGridData->iCols * (si.nPos -1) + iCellBufferPos;
                   pZStr=pGridData->pGridMemory[iGridMemOffset];
                   iRow=i, iCol=j;
                   pGridData->iEditedCellRow=iRow;
                   pGridData->iEditedRow=iRow+si.nPos-1;
                   pGridData->iEditedCol=iCol;
                   blnFound=TRUE;
                   goto Finished;
                }
          }
        }
        Finished:
        if(blnFound)
        {
           #ifdef MYDEBUG
           _ftprintf(fp,_T("  Found ZStr at %d\t%d\n"),i,j);
           _ftprintf(fp,_T("  si.nPos                = %u\n"),si.nPos);
           _ftprintf(fp,_T("  pZStr                  = %u\n"),pZStr);
           _ftprintf(fp,_T("  pZStr                  = %s\n"),pZStr);
           _ftprintf(fp,_T("  pGridData->hCtrlInCell = %u\n"),pGridData->hCtrlInCell);
           #endif
           pGridData->hCtrlInCell=pGridData->pCtrlHdls[iCol-1];
           SetParent(pGridData->hCtrlInCell,hCell);
           fnEditWndProc=(WNDPROC)SetWindowLongPtr(pGridData->hCtrlInCell,GWLP_WNDPROC,(LONG_PTR)fnEditSubClass);
           if(pGridData->hFont)
              SendMessage(pGridData->hCtrlInCell,WM_SETFONT,(WPARAM)pGridData->hFont,(LPARAM)TRUE);
           if(pGridData->pCellCtrlTypes[iCol-1]==GRID_CELL_CTRL_EDIT)
           {
              SetWindowPos(pGridData->hCtrlInCell,HWND_TOP,1,0,pGridData->pColWidths[iCol-1]-2,pGridData->iRowHeight,SWP_SHOWWINDOW);
              SetWindowText(pGridData->hCtrlInCell,pZStr);
              SetFocus(pGridData->hCtrlInCell);
              SendMessage(pGridData->hCtrlInCell,EM_SETSEL,(WPARAM)0,(LPARAM)-1);
           }
           if(pGridData->pCellCtrlTypes[iCol-1]==GRID_CELL_CTRL_COMBO)
           {
              SetWindowPos(pGridData->hCtrlInCell,HWND_TOP,1,0,pGridData->pColWidths[iCol-1]-2,180,SWP_SHOWWINDOW);
              SendMessage(pGridData->hCtrlInCell,CB_SETCURSEL,(WPARAM)-1,(LPARAM)0);
           }
           for(i=0; i<MAX_CONNECTIONS; i++)
           {
               if(pGridData->pComObj->pISink[i])
               {
                  pGridData->pComObj->pISink[i]->Grid_OnLButtonDown(iRow,pGridData->iEditedRow,iCol);
               }
           }
        }
        #ifdef MYDEBUG
        _ftprintf(fp,_T("Leaving fnCellProc()  --  case WM_LBUTTONDOWN\n\n"));
        #endif
        return 0;
     }
   case WM_PAINT:
     {
        PAINTSTRUCT ps;
        HDC hDC=BeginPaint(hCell,&ps);
        TCHAR* pBuffer=(TCHAR*)GetWindowLongPtr(hCell,0);                   // 0
        HFONT hFont=(HFONT)GetWindowLongPtr(hCell,sizeof(void*));           // 8
        COLORREF dwColor=(COLORREF)GetWindowLongPtr(hCell,2*sizeof(void*)); // 16
        HBRUSH hBrush=(HBRUSH)GetWindowLongPtr(hCell,3*sizeof(void*));      // 24
        if(pBuffer)
        {
           HFONT hTmp=NULL;
           COLORREF dwTmpClr=0;
           if(hFont)
              hTmp=(HFONT)SelectObject(hDC,hFont);
           if(dwColor)
              dwTmpClr=SetTextColor(hDC,dwColor);
           if(hBrush)
           {
              RECT rc;
              HBRUSH hTmpBr=(HBRUSH)SelectObject(hDC,hBrush);
              GetClientRect(hCell,&rc);
              FillRect(hDC,&rc,hBrush);
              SelectObject(hDC,hTmpBr);
           }
           int iBkMode=SetBkMode(hDC,TRANSPARENT);
           TextOut(hDC,1,0,pBuffer,_tcslen(pBuffer));
           if(hFont && hTmp)
              hFont=(HFONT)SelectObject(hDC,hTmp);
           if(dwColor)
              SetTextColor(hDC,dwTmpClr);
           SetBkMode(hDC,iBkMode);
        }
        EndPaint(hCell,&ps);
        return 0;
     }
 }

 return (DefWindowProc(hCell, msg, wParam, lParam));
}


--- End code ---

Frederick J. Harris:
Server.cpp


--- Code: ---// Server.cpp
// CD C:\Code\VStudio\VC++9\FHGrid
// CD C:\Code\VStudio\VC++9\64_Bit\FHGrid
// cl Server.cpp Grid.cpp WinCode.cpp Registry.cpp Strings.cpp FHGridRes.obj Kernel32.lib comctl32.lib User32.lib Gdi32.lib UUID.lib Advapi32.lib Ole32.lib OleAut32.lib FHGrid.def /MT /O1 /Os /FeFHGrid.dll /LD

#define       UNICODE
#define       _UNICODE
#define       X64_GRID            // This code can be compiled to create either a 32 bit or 64 bit COM object.  The X64_GRID define at
//#define     MYDEBUG             // left is the only equate I've found which was made necessary by the 32/64 bit issue.  The define is
#include      <windows.h>         // used in DllUnregisterServer() in the code that Unregisters the Type Library, i.e., UnRegisterTypeLib().
#include      <tchar.h>           // The 5th parameter of that function is an object of type SYSKIND, which is an enumeration with members
#include      <initguid.h>        // SYS_WIN32 and SYS_WIN64.  The creation of my X64_GRID #define seemed like a reasonable way to handle
#include      <ocidl.h>           // this somewhat unfortunate situation.
#include      <cstdio>
#include      "Grid.h"            // Note that if you have registered both a 32 bit version and a 64 bit version of this COM dll, and you
#include      "WinCode.h"
#include      "Registry.h"        // choose to Unregister one of those, only the win32 or win64 TypeLib subkey will be removed.

#if defined   MYDEBUG
FILE*         fp=NULL;
#endif

//Globals
HINSTANCE     g_hModule           = NULL;
const TCHAR   g_szFriendlyName[]  = _T("Fred Harris Grid Control v1");
const TCHAR   g_szVerIndProgID[]  = _T("FHGrid.Grid");
const TCHAR   g_szProgID[]        = _T("FHGrid.Grid.1");
long          g_lObjs             = 0;
long          g_lLocks            = 0;
long          g_CtrlId            = 1500;


STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
{
 GridClassFactory* pCF=NULL;
 TCHAR szBuffer[512];
 HRESULT hr;

 #if defined MYDEBUG
 if(fp==NULL)
 {
    GetCurrentDirectory(512,szBuffer);
    _tcscat(szBuffer,_T("\\Output.txt"));
    fp=_tfopen(szBuffer,_T("w"));
 }
 printf("  Entering DllGetClassObject()\n");
 _ftprintf(fp,_T("Entering DllGetClassObject()\n"));
 _ftprintf(fp,_T("  szBuffer = %s\n"),szBuffer);
 #endif
 if(rclsid!=CLSID_FHGrid)
    return E_FAIL;
 pCF=new GridClassFactory;
 if(pCF==0)
    return E_OUTOFMEMORY;
 #if defined MYDEBUG
 printf("    pCF = %d\n",pCF);
 _ftprintf(fp,_T("  pCF = %d\n"),pCF);
 #endif
 hr=pCF->QueryInterface(riid,ppv);
 if(FAILED(hr))
    delete pCF;
 else
    Initialize();
 #if defined MYDEBUG
 printf("  Leaving DllGetClassObject()\n");
 _ftprintf(fp,_T("Leaving DllGetClassObject()\n\n"));
 #endif

 return hr;
}


STDAPI DllCanUnloadNow()
{
 #if defined MYDEBUG
 printf("Entering DllCanUnloadNow()\n");
 printf("  g_lObjs  = %d\n",g_lObjs);
 printf("  g_lLocks = %d\n",g_lLocks);
 _ftprintf(fp,_T("Entering DllCanUnloadNow()\n"));
 _ftprintf(fp,_T("  g_lObjs  = %d\n"),g_lObjs);
 _ftprintf(fp,_T("  g_lLocks = %d\n"),g_lLocks);
 #endif
 if(g_lObjs||g_lLocks)
 {
    #if defined MYDEBUG
    printf("  Gonna Hang Around A Bit Yet Wheather You Like It Or Not!\n");
    printf("Leaving DllCanUnloadNow()\n");
    _ftprintf(fp,_T("  Gonna Hang Around A Bit Yet Wheather You Like It Or Not!\n"));
    _ftprintf(fp,_T("Leaving DllCanUnloadNow()\n"));
    #endif
    return S_FALSE;
 }
 else
 {
    #if defined MYDEBUG
    printf("  I'm Outta Here!\n");
    printf("Leaving DllCanUnloadNow()\n");
    _ftprintf(fp,_T("  I'm Outta Here!\n"));
    _ftprintf(fp,_T("Leaving DllCanUnloadNow()\n"));
    fclose(fp);
    #endif
    return S_OK;
 }
}


STDAPI DllRegisterServer()
{
 ITypeLib* pTypeLib=NULL;
 TCHAR szBuffer[512];
 wchar_t szWide[512];
 HRESULT hr=E_FAIL;

 #if defined MYDEBUG
 GetCurrentDirectory(512,szBuffer);
 _tcscat(szBuffer,_T("\\Output.txt"));
 fp=_tfopen(szBuffer,_T("w"));
 if(!fp)
    return E_FAIL;
 fprintf(fp,"Entering DLLRegisterServer\n");
 _ftprintf(fp,_T("  szBuffer = %s\n"),szBuffer);
 #endif
 if(GetModuleFileName(g_hModule,szBuffer,512)>=512)
 {
    #if defined MYDEBUG
    _ftprintf(fp,_T("  GetModuleFileName() Failed!\n"));
    _ftprintf(fp,_T("Leaving DllRegisterServer()\n"));
    fclose(fp);
    #endif
    return E_FAIL;
 }
 #if defined UNICODE
     _tcscpy(szWide,szBuffer);
 #else
     mbstowcs(szWide,szBuffer,511);
 #endif
 #if defined MYDEBUG
 _ftprintf(fp,_T("  szBuffer = %s\n"),szBuffer);
 fwprintf(fp,L"  szWide   = %s\n",szWide);
 #endif
 hr=LoadTypeLibEx(szWide, REGKIND_REGISTER, &pTypeLib);
 if(SUCCEEDED(hr))
 {
    #if defined MYDEBUG
    fprintf(fp,"  LoadTypeLibEx() Succeeded!\n");
    #endif
    pTypeLib->Release();
 }
 else
 {
    #if defined MYDEBUG
    _ftprintf(fp,_T("  LoadTypeLib() Failed!\n"));
    _ftprintf(fp,_T("Leaving DllRegisterServer()\n"));
    fclose(fp);
    #endif
    return E_FAIL;
 }
 hr=RegisterServer(szBuffer,CLSID_FHGrid,g_szFriendlyName,g_szVerIndProgID,g_szProgID);
 if(SUCCEEDED(hr))
 {
    #if defined MYDEBUG
    fprintf(fp,"  RegisterServer() Succeeded!\n");
    #endif
 }
 else
 {
    #if defined MYDEBUG
    fprintf(fp,"  RegisterServer() Failed!\n");
    #endif
 }
 #if defined MYDEBUG
 _ftprintf(fp,_T("Leaving DllRegisterServer()\n"));
 fclose(fp);
 #endif

 return hr;
}


STDAPI DllUnregisterServer()
{
 TCHAR szBuffer[512];
 HRESULT hr=E_FAIL;

 #if defined MYDEBUG
 GetCurrentDirectory(512,szBuffer);
 _tcscat(szBuffer,_T("\\Output.txt"));
 fp=_tfopen(szBuffer,_T("w"));
 if(!fp)
    return E_FAIL;
 _ftprintf(fp,_T("Entering DllUnregisterServer()\n"));
 #endif
 hr=UnregisterServer(CLSID_FHGrid,g_szVerIndProgID,g_szProgID);
 #if defined MYDEBUG
 _ftprintf(fp,_T("  hr = %d\n"),hr);
 #endif
 if(SUCCEEDED(hr))
 {
    #if defined MYDEBUG
    _ftprintf(fp,_T("  UnregisterServer() Succeeded!\n"));
    #endif
    #if defined X64_GRID
    hr=UnRegisterTypeLib(LIBID_FHGrid,1,0,LANG_NEUTRAL,SYS_WIN64);
    #else
    hr=UnRegisterTypeLib(LIBID_FHGrid,1,0,LANG_NEUTRAL,SYS_WIN32);
    #endif
    if(SUCCEEDED(hr))
    {
       #if defined MYDEBUG
       _ftprintf(fp,_T("  UnRegisterTypeLib() Succeeded!\n"));
       #endif
    }
    else
    {
       #if defined MYDEBUG
       _ftprintf(fp,_T("  UnRegisterTypeLib() Failed!\n"));
       #endif
    }
 }
 #if defined MYDEBUG
 _ftprintf(fp,_T("Leaving DllUnregisterServer()\n"));
 fclose(fp);
 #endif

 return hr;
}


BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved)
{
 switch (reason)
 {
  case DLL_PROCESS_ATTACH:
    g_hModule=hInst;
    break;
  case DLL_PROCESS_DETACH:
    break;
 }

 return TRUE;
}

--- End code ---

Frederick J. Harris:
Registry.cpp


--- Code: ---// Registry.cpp
#define   UNICODE
#define   _UNICODE
//#define MYDEBUG
#include  <objbase.h>
#include  <tchar.h>
#include  <cstdio>
#include  "Registry.h"
const int CLSID_STRING_BUFFER_LENGTH = 39; //A CLSID Converted Needs 38 chars, i.e., {30000000-0000-0000-0000-000000000000}. The 39 number is for the terminating NULL.
#if defined MYDEBUG
extern FILE* fp;
#endif


BOOL SetKeyAndValue(const TCHAR* szKey, const TCHAR* szSubkey, const TCHAR* szValue)
{
 TCHAR szKeyBuf[1024];
 long lResult;
 HKEY hKey;

 #if defined MYDEBUG
 _ftprintf(fp,_T("    Entering SetKeyAndValue()\n"));
 _ftprintf(fp,_T("      szKey    = %s\n"),szKey);
 _ftprintf(fp,_T("      szSubkey = %s\n"),szSubkey);
 _ftprintf(fp,_T("      szValue  = %s\n"),szValue);
 #endif
 _tcscpy(szKeyBuf,szKey);
 if(szSubkey!=NULL)          // Add subkey name to buffer.
 {
     _tcscat(szKeyBuf, _T("\\"));
     _tcscat(szKeyBuf, szSubkey);
     #if defined MYDEBUG
     _ftprintf(fp,_T("      szKeyBuf = %s\n"),szKeyBuf);
     #endif
 }
 //Create and open key and subkey.
 lResult=RegCreateKeyEx(HKEY_CLASSES_ROOT,szKeyBuf,0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,NULL);
 if(lResult!=ERROR_SUCCESS)
    return FALSE ;
 if(szValue!=NULL)         //Set the Value.
    RegSetValueEx(hKey,NULL,0,REG_SZ,(BYTE*)szValue,(_tcslen(szValue)*sizeof(TCHAR))+sizeof(TCHAR));
 RegCloseKey(hKey);
 #if defined MYDEBUG
 _ftprintf(fp,_T("    Leaving SetKeyAndValue()\n"));
 #endif

 return TRUE;
}


void CLSIDToTChar(const CLSID& clsid, TCHAR* szCLSID, int iStrlen)    // Convert a CLSID to a TCHAR string.
{
 LPOLESTR wszCLSID=NULL;
 size_t pRet=0;
 HRESULT hr;

 #if defined MYDEBUG
 _ftprintf(fp,_T("    Entering CLSIDToTChar()\n"));
 #endif
 hr=StringFromCLSID(clsid,&wszCLSID);      // Get CLSID
 #if defined MYDEBUG
 _ftprintf(fp,_T("      iStrLen  = %d\n"),iStrlen);
 fwprintf(fp,   L"      wszCLSID = %s\n",wszCLSID);
 #endif
 if(SUCCEEDED(hr))
 {
    #if defined UNICODE
        _tcscpy_s(szCLSID,iStrlen,wszCLSID);
        #if defined MYDEBUG
        _ftprintf(fp,_T("      szCLSID  = %s\n"),szCLSID);
        #endif
    #else
        wcstombs_s(&pRet,szCLSID,iStrlen,wszCLSID,iStrlen); // Covert from wide characters to non-wide.
        #if defined MYDEBUG
        _ftprintf(fp,  _T("      szCLSID  = %s\n"),szCLSID);
        _ftprintf(fp,  _T("      pRet     = %u\n"),pRet);
        #endif
    #endif
    CoTaskMemFree(wszCLSID);               // Free memory.
 }
 #if defined MYDEBUG
 _ftprintf(fp,_T("    Leaving CLSIDToTChar()\n"));
 #endif
}


LONG RecursiveDeleteKey(HKEY hKeyParent, const TCHAR* lpszKeyChild)       // Key to delete
{
 TCHAR szBuffer[256];
 DWORD dwSize=256 ;
 HKEY hKeyChild;
 FILETIME time;
 LONG lRes;

 lRes=RegOpenKeyEx(hKeyParent,lpszKeyChild,0,KEY_ALL_ACCESS,&hKeyChild); //Open the child.
 if(lRes!=ERROR_SUCCESS)
    return lRes;
 while(RegEnumKeyEx(hKeyChild,0,szBuffer,&dwSize,NULL,NULL,NULL,&time)==S_OK) //Enumerate all of the decendents of this child.
 {
  lRes=RecursiveDeleteKey(hKeyChild,szBuffer);  //Delete the decendents of this child.
  if(lRes!=ERROR_SUCCESS)
  {
     RegCloseKey(hKeyChild);  //Cleanup before exiting.
     return lRes;
  }
  dwSize=256;
 }
 RegCloseKey(hKeyChild);      // Close the child.

 return RegDeleteKey(hKeyParent,lpszKeyChild);  //Delete this child.
}


HRESULT RegisterServer(TCHAR* szModule, const CLSID& clsid, const TCHAR* szFriendlyName, const TCHAR* szVerIndProgID, const TCHAR* szProgID)
{
 TCHAR szCLSID[CLSID_STRING_BUFFER_LENGTH];   // GetModuleFileName(hModule,szModule,sizeof(szModule)/sizeof(TCHAR))
 TCHAR szKey[64];

 #if defined MYDEBUG
 _ftprintf(fp,_T("  Entering RegisterServer()\n"));
 _ftprintf(fp,_T("    szFriendlyName = %s\n"),szFriendlyName);
 _ftprintf(fp,_T("    szVerIndProgID = %s\n"),szVerIndProgID);
 _ftprintf(fp,_T("    szProgID       = %s\n"),szProgID);
 _ftprintf(fp,_T("    szModule       = %s\n"),szModule);
 #endif
 CLSIDToTChar(clsid, szCLSID, CLSID_STRING_BUFFER_LENGTH);            //Get server location &Convert the CLSID into a char.
 _tcscpy_s(szKey, _T("CLSID\\"));                                     //Build the key CLSID\\{...}
 _tcscat_s(szKey,szCLSID);
 #if defined MYDEBUG
 _ftprintf(fp,_T("    szCLSID        = %s\n"),szCLSID);
 _ftprintf(fp,_T("    szKey   = %s\n"),szCLSID);
 #endif
 SetKeyAndValue(szKey,NULL,szFriendlyName);                           //Add the CLSID to the registry.
 SetKeyAndValue(szKey, _T("InprocServer32"), szModule);               //Add the server filename subkey under the CLSID key.
 SetKeyAndValue(szKey, _T("ProgID"), szProgID);                       //Add the ProgID subkey under the CLSID key.
 SetKeyAndValue(szKey,_T("VersionIndependentProgID"),szVerIndProgID); //Add the version-independent ProgID subkey under CLSID key.
 SetKeyAndValue(szVerIndProgID, NULL, szFriendlyName);                //Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT.
 SetKeyAndValue(szVerIndProgID, _T("CLSID"), szCLSID);
 SetKeyAndValue(szVerIndProgID, _T("CurVer"), szProgID);
 SetKeyAndValue(szProgID, NULL, szFriendlyName);                      //Add the versioned ProgID subkey under HKEY_CLASSES_ROOT.
 SetKeyAndValue(szProgID, _T("CLSID"), szCLSID);
 #if defined MYDEBUG
 _ftprintf(fp,_T("  Leaving RegisterServer()\n"));
 #endif

 return S_OK ;
}


HRESULT UnregisterServer(const CLSID& clsid, const TCHAR* szVerIndProgID, const TCHAR* szProgID)
{
 TCHAR szCLSID[CLSID_STRING_BUFFER_LENGTH];
 TCHAR szKey[64];
 LONG lResult;

 #if defined MYDEBUG
 _ftprintf(fp,  _T("  Entering UnregisterServer()\n"));
 #endif
 CLSIDToTChar(clsid, szCLSID,CLSID_STRING_BUFFER_LENGTH);                //Convert the CLSID into a char.
 _tcscpy_s(szKey, _T("CLSID\\"));                                        //Build the key CLSID\\{...}
 _tcscat_s(szKey, szCLSID) ;
 lResult=RecursiveDeleteKey(HKEY_CLASSES_ROOT, szKey);                   //Delete the CLSID Key - CLSID\{...}
 lResult=RecursiveDeleteKey(HKEY_CLASSES_ROOT, szVerIndProgID);          //Delete the version-independent ProgID Key.
 lResult=RecursiveDeleteKey(HKEY_CLASSES_ROOT, szProgID) ;               //Delete the ProgID key.
 #if defined MYDEBUG
 _ftprintf(fp,  _T("  Leaving UnregisterServer()\n"));
 #endif

 return S_OK ;
}

--- End code ---

Frederick J. Harris:
Strings.cpp


--- Code: ---//Strings.cpp
#define   UNICODE
#define   _UNICODE
#define   JUST_NEED_PARSE   // << keep this active for compiling grid code
#include "windows.h"        // otherwise, comment it out so the rest of the
#include  <stdlib.h>        // string class works
#include  <cstdio>
#include  <tchar.h>
#include  <math.h>
#include  <string.h>
#include  "Strings.h"


#ifndef JUST_NEED_PARSE
String operator+(TCHAR* lhs, String& rhs)         //global function
{
 String sr=lhs;
 sr=sr+rhs;

 return sr;
}
#endif


String::String()
{
 lpBuffer=new TCHAR[MINIMUM_ALLOCATION];
 lpBuffer[0]=_T('\0');
 this->iCapacity=MINIMUM_ALLOCATION-1;
 this->iLen=0;
}


String::String(const TCHAR ch)  //Constructor: Initializes with TCHAR
{
 this->iLen=1;
 SIZE_T iNewSize=MINIMUM_ALLOCATION;
 this->lpBuffer=new TCHAR[iNewSize];
 this->iCapacity=iNewSize-1;
 this->lpBuffer[0]=ch, this->lpBuffer[1]=_T('\0');
}


String::String(const TCHAR* pStr)  //Constructor: Initializes with TCHAR*
{
 this->iLen=_tcslen(pStr);
 SIZE_T iNewSize=(this->iLen/16+1)*16;
 this->lpBuffer=new TCHAR[iNewSize];
 this->iCapacity=iNewSize-1;
 _tcscpy(lpBuffer,pStr);
}


String::String(const String& s)  //Constructor Initializes With Another String, i.e., Copy Constructor
{
 SIZE_T iNewSize=(s.iLen/16+1)*16;
 this->iLen=s.iLen;
 this->lpBuffer=new TCHAR[iNewSize];
 this->iCapacity=iNewSize-1;
 _tcscpy(this->lpBuffer,s.lpBuffer);
}


#ifndef JUST_NEED_PARSE
String::String(const SIZE_T iSize, bool blnFillNulls)  //Constructor Creates String With Custom Sized
{                                                   //Buffer (rounded up to paragraph boundary)
 SIZE_T iNewSize=(iSize/16+1)*16;
 this->lpBuffer=new TCHAR[iNewSize];
 this->iCapacity=iNewSize-1;
 this->iLen=0;
 this->lpBuffer[0]=_T('\0');
 if(blnFillNulls)
 {
    for(size_t i=0; i<this->iCapacity; i++)
        this->lpBuffer[i]=0;
 }
}


String::String(SIZE_T iCount, const TCHAR ch)
{
 SIZE_T iNewSize=(iCount/16+1)*16;
 this->lpBuffer=new TCHAR[iNewSize];
 this->iCapacity=iNewSize-1;
 for(size_t i=0; i<iCount; i++)
     this->lpBuffer[i]=ch;
 this->lpBuffer[iCount]=_T('\0');
 this->iLen=iCount;
}


String::String(SSIZE_T iNum)
{
 this->lpBuffer=new TCHAR[16];
 this->iCapacity=15;
 this->iLen=_stprintf(this->lpBuffer,_T("%d"),iNum);
}


String::String(SIZE_T iNum)
{
 this->lpBuffer=new TCHAR[16];
 this->iCapacity=15;
 this->iLen=_stprintf(this->lpBuffer,_T("%u"),iNum);
}


String::String(double dblNum)
{
 this->lpBuffer=new TCHAR[32];
 this->iCapacity=31;
 this->iLen=_stprintf(this->lpBuffer,_T("%10.14f"),dblNum);
}


String& String::operator=(double dblNum)
{
 if(this->iCapacity<32)
 {
    delete [] this->lpBuffer;
    lpBuffer=new TCHAR[32];
    this->iCapacity=31;
 }
 this->iLen=_stprintf(this->lpBuffer,_T("%10.14f"),dblNum);

 return *this;
}


void String::SetTCHAR(unsigned iOffset, TCHAR ch)   //zero based!
{
 if(iOffset<this->iCapacity)
 {
    this->lpBuffer[iOffset]=ch;
    if(ch==_T('\0'))
    {
       if(iOffset<this->iLen || this->iLen==0)
          this->iLen=iOffset;
    }
 }
}
#endif


String& String::operator=(const TCHAR ch)
{
 this->lpBuffer[0]=ch, this->lpBuffer[1]=_T('\0');
 this->iLen=1;
 return *this;
}


String& String::operator=(const TCHAR* pStr)
{
 size_t iNewLen=_tcslen(pStr);
 if(iNewLen>this->iCapacity)
 {
    delete [] this->lpBuffer;
    size_t iNewSize=(iNewLen*EXPANSION_FACTOR/16+1)*16;
    this->lpBuffer=new TCHAR[iNewSize];
    this->iCapacity=iNewSize-1;
 }
 _tcscpy(this->lpBuffer,pStr);
 this->iLen=iNewLen;

 return *this;
}


String& String::operator=(const String& strAnother)
{
 if(this==&strAnother)
    return *this;
 if(strAnother.iLen>this->iCapacity)
 {
    delete [] this->lpBuffer;
    SIZE_T iNewSize=(strAnother.iLen*EXPANSION_FACTOR/16+1)*16;
    this->lpBuffer=new TCHAR[iNewSize];
    this->iCapacity=iNewSize-1;
 }
 _tcscpy(this->lpBuffer,strAnother.lpBuffer);
 this->iLen=strAnother.iLen;

 return *this;
}


#ifndef JUST_NEED_PARSE
String& String::operator=(int iNum)
{
 if(this->iCapacity>=15)
    this->iLen=_stprintf(this->lpBuffer,_T("%d"),iNum);
 else
 {
    delete [] this->lpBuffer;
    this->lpBuffer=new TCHAR[16];
    this->iCapacity=15;
    this->iLen=_stprintf(this->lpBuffer,_T("%d"),iNum);
 }

 return *this;
}


String& String::operator=(unsigned int iNum)
{
  if(this->iCapacity>=15)
    this->iLen=_stprintf(this->lpBuffer,_T("%d"),iNum);
 else
 {
    delete [] this->lpBuffer;
    this->lpBuffer=new TCHAR[16];
    this->iCapacity=15;
    this->iLen=_stprintf(this->lpBuffer,_T("%d"),iNum);
 }

 return *this;
}


String String::operator+(const TCHAR ch)
{
 SIZE_T iNewLen=this->iLen+1;

 String s(iNewLen,false);
 _tcscpy(s.lpBuffer,this->lpBuffer);
 s.lpBuffer[iNewLen-1]=ch;
 s.lpBuffer[iNewLen]=_T('\0');
 s.iLen=iNewLen;

 return s;
}


String String::operator+(const TCHAR* pStr)
{
 SIZE_T iNewLen=(int)_tcslen(pStr)+this->iLen;
 String s(iNewLen,false);
 _tcscpy(s.lpBuffer,this->lpBuffer);
 _tcscat(s.lpBuffer,pStr);
 s.iLen=iNewLen;

 return s;
}


String String::operator+(String& strRef)
{
 SIZE_T iNewLen=strRef.iLen+this->iLen;
 String s(iNewLen,false);
 _tcscpy(s.lpBuffer,this->lpBuffer);
 _tcscat(s.lpBuffer,strRef.lpBuffer);
 s.iLen=iNewLen;

 return s;
}


String& String::operator+=(const TCHAR ch)
{
 SIZE_T iTot=this->iLen+1;
 if(iTot>this->iCapacity)
 {
    SIZE_T iNewSize=(iTot*EXPANSION_FACTOR/16+1)*16;
    TCHAR* pNew=new TCHAR[iNewSize];
    _tcscpy(pNew,this->lpBuffer);
    delete [] this->lpBuffer;
    this->lpBuffer=pNew;
    this->lpBuffer[iTot-1]=ch;
    this->lpBuffer[iTot]=_T('\0');
    this->iCapacity=iNewSize-1;
    this->iLen=iTot;
 }
 else
 {
    this->lpBuffer[iTot-1]=ch;
    this->lpBuffer[iTot]=_T('\0');
    this->iLen=iTot;
 }
 return *this;
}


String& String::operator+=(const TCHAR* pStr)
{
 size_t iStrlen=_tcslen(pStr);
 SIZE_T iTot=iStrlen+this->iLen;
 if(iTot>this->iCapacity)
 {
    SIZE_T iNewSize=(iTot*EXPANSION_FACTOR/16+1)*16;
    TCHAR* pNew=new TCHAR[iNewSize];
    _tcscpy(pNew,this->lpBuffer);
    delete [] this->lpBuffer;
    this->lpBuffer=pNew;
    _tcscat(pNew,pStr);
    this->iCapacity=iNewSize-1;
    this->iLen=iTot;
 }
 else
 {
    _tcscat(this->lpBuffer,pStr);
    this->iLen=iTot;
 }
 return *this;
}


String& String::operator+=(const String& strRef)
{
 SIZE_T iTot=strRef.iLen+this->iLen;
 if(iTot>this->iCapacity)
 {
    SIZE_T iNewSize=(iTot*EXPANSION_FACTOR/16+1)*16;
    TCHAR* pNew=new TCHAR[iNewSize];
    _tcscpy(pNew,this->lpBuffer);
    delete [] this->lpBuffer;
    this->lpBuffer=pNew;
    _tcscat(pNew,strRef.lpBuffer);
    this->iCapacity=iNewSize-1;
    this->iLen=iTot;
 }
 else
 {
    _tcscat(this->lpBuffer,strRef.lpBuffer);
    this->iLen=iTot;
 }
 return *this;
}


bool String::operator==(String& strRef)
{
 if(_tcscmp(this->lpStr(),strRef.lpStr())==0)
    return true;
 else
    return false;
}
#endif


bool String::operator==(const TCHAR* pStr)
{
 if(_tcscmp(this->lpStr(),pStr)==0)
    return true;
 else
    return false;
}


#ifndef JUST_NEED_PARSE
String String::Allocate(int iCount)
{
 if((unsigned)iCount>this->iCapacity)
 {
    delete [] lpBuffer;
    size_t iNewSize=(iCount*EXPANSION_FACTOR/16+1)*16;
    this->lpBuffer=new TCHAR[iNewSize];
    this->iCapacity=iNewSize-1;
 }
 this->lpBuffer[0]=_T('\0');
 this->iLen=0;

 return *this;
}


String& String::Make(const TCHAR ch, int iCount)    //Creates (Makes) a String with iCount TCHARs
{
 if((unsigned)iCount>this->iCapacity)
 {
    delete [] lpBuffer;
    size_t iNewSize=(iCount*EXPANSION_FACTOR/16+1)*16;
    this->lpBuffer=new TCHAR[iNewSize];
    this->iCapacity=iNewSize-1;
 }
 for(int i=0; i<iCount; i++)
     this->lpBuffer[i]=ch;
 this->lpBuffer[iCount]=0;
 this->iLen=iCount;
 return *this;
}


String String::Left(int iNum)   //  strncpy = _tcsncpy
{
 if((unsigned)iNum<this->iLen)
 {
    int iNewSize=(iNum*EXPANSION_FACTOR/16+1)*16;
    String sr(iNewSize,false);
    _tcsncpy(sr.lpBuffer,this->lpBuffer,iNum);
    sr.lpBuffer[iNum]=0;
    sr.iLen=iNum;
    return sr;
 }
 else
 {
    String sr=*this;
    return sr;
 }
}


String String::Right(int iNum)  //Returns Right$(strMain,iNum)
{
 if((unsigned)iNum<this->iLen)
 {
    int iNewSize=(iNum*EXPANSION_FACTOR/16+1)*16;
    String sr(iNewSize,false);
    _tcsncpy(sr.lpBuffer,this->lpBuffer+this->iLen-iNum,iNum);
    sr.lpBuffer[iNum]=_T('\0');
    sr.iLen=iNum;
    return sr;
 }
 else
 {
    String sr=*this;
    sr.iLen=this->iLen;
    return sr;
 }
}


String String::Mid(SIZE_T iStart, SIZE_T iCount)
{
 if(iStart<1)
 {
    String sr;
    return sr;
 }
 if(iCount+iStart>this->iLen)
    iCount=this->iLen-iStart+1;
 String sr(iCount,false);
 _tcsncpy(sr.lpBuffer,this->lpBuffer+iStart-1,iCount);
 sr.lpBuffer[iCount]=_T('\0');
 sr.iLen=iCount;

 return sr;
}


String String::Replace(TCHAR* pMatch, TCHAR* pNew)  //strncmp = _tcsncmp
{
 SIZE_T i,iLenMatch,iLenNew,iCountMatches,iExtra,iExtraLengthNeeded,iAllocation,iCtr;
 iLenMatch=(int)_tcslen(pMatch);
 iCountMatches=0, iAllocation=0, iCtr=0;
 iLenNew=(int)_tcslen(pNew);
 if(iLenNew==0)
 {
    String sr=this->Remove(pMatch,true); //return
    return sr;
 }
 else
 {
    iExtra=iLenNew-iLenMatch;
    for(i=0; i<this->iLen; i++)
    {
        if(_tcsncmp(lpBuffer+i,pMatch,iLenMatch)==0)
           iCountMatches++;  //Count how many match strings
    }
    iExtraLengthNeeded=iCountMatches*iExtra;
    iAllocation=this->iLen+iExtraLengthNeeded;
    String sr(iAllocation,false);
    for(i=0; i<this->iLen; i++)
    {
        if(_tcsncmp(this->lpBuffer+i,pMatch,iLenMatch)==0)
        {
           _tcscpy(sr.lpBuffer+iCtr,pNew);
           iCtr+=iLenNew;
           i+=iLenMatch-1;
        }
        else
        {
           sr.lpBuffer[iCtr]=this->lpBuffer[i];
           iCtr++;
        }
        sr.lpBuffer[iCtr]=_T('\0');
    }
    sr.iLen=iCtr;
    return sr;
 }
}


String String::Remove(TCHAR* pStr)
{
 SIZE_T i,j,iStrLen,iParamLen;
 TCHAR *pThis, *pThat, *p;
 bool blnFoundBadTCHAR;

 iStrLen=this->iLen;               //The length of this
 String sr((int)iStrLen,false);    //Create new String big enough to contain original String (this)
 iParamLen=(int)_tcslen(pStr);     //Get length of parameter (pStr) which contains TCHARs to be removed
 pThis=this->lpBuffer;
 p=sr.lpStr();
 for(i=0; i<iStrLen; i++)
 {
     pThat=pStr;
     blnFoundBadTCHAR=false;
     for(j=0; j<iParamLen; j++)
     {
         if(*pThis==*pThat)
         {
            blnFoundBadTCHAR=true;
            break;
         }
         pThat++;
     }
     if(!blnFoundBadTCHAR)
     {
        *p=*pThis;
         p++;        *p=_T('\0');
     }
     pThis++;
 }
 sr.iLen=(int)_tcslen(sr.lpStr());

 return sr;
}


String String::Remove(const TCHAR* pMatch, bool blnCaseSensitive)
{
 size_t i,iCountMatches=0,iCtr=0;

 int iLenMatch=(int)_tcslen(pMatch);
 for(i=0; i<this->iLen; i++)
 {
     if(blnCaseSensitive)
     {
        if(_tcsncmp(lpBuffer+i,pMatch,iLenMatch)==0)  //_tcsncmp
           iCountMatches++;
     }
     else
     {
        if(_tcsnicmp(lpBuffer+i,pMatch,iLenMatch)==0) //__tcsnicmp
           iCountMatches++;
     }
 }
 SIZE_T iAllocation=this->iLen-(iCountMatches*iLenMatch);
 String sr(iAllocation,false);
 for(i=0; i<this->iLen; i++)
 {
     if(blnCaseSensitive)
     {
        if(_tcsncmp(this->lpBuffer+i,pMatch,iLenMatch)==0)
           i+=iLenMatch-1;
        else
        {
           sr.lpBuffer[iCtr]=this->lpBuffer[i];
           iCtr++;
        }
        sr.lpBuffer[iCtr]=_T('\0');
     }
     else
     {
        if(_tcsnicmp(this->lpBuffer+i,pMatch,iLenMatch)==0)
           i+=iLenMatch-1;
        else
        {
           sr.lpBuffer[iCtr]=this->lpBuffer[i];
           iCtr++;
        }
        sr.lpBuffer[iCtr]=_T('\0');
     }
 }
 sr.iLen=iCtr;
 return sr;
}
#endif


int String::ParseCount(const TCHAR c)  //returns one more than # of
{                                      //delimiters so it accurately
 int iCtr=0;                           //reflects # of strings delimited
 TCHAR* p;                             //by delimiter.

 p=this->lpBuffer;
 while(*p)
 {
  if(*p==c)
     iCtr++;
  p++;
 }

 return ++iCtr;
}


void String::Parse(String* pStr, TCHAR delimiter)
{
 unsigned int i=0;
 TCHAR* pBuffer=0;
 TCHAR* c;
 TCHAR* p;

 pBuffer=new TCHAR[this->iLen+1];
 if(pBuffer)
 {
    pBuffer[0]=0, p=pBuffer;
    c=this->lpBuffer;
    while(*c)
    {
       if(*c==delimiter)
       {
          pStr[i]=pBuffer,  p=pBuffer;
          i++,              pBuffer[0]=0;
       }
       else
       {
          *p=*c,  p++;
          *p=0;
       }
       c++;
    }
    pStr[i]=pBuffer;
    delete [] pBuffer;
 }
}


#ifndef JUST_NEED_PARSE
SIZE_T iMatch(TCHAR* pThis, const TCHAR* pStr, bool blnCaseSensitive, bool blnStartBeginning, SIZE_T i, SIZE_T iParamLen)
{
 if(blnCaseSensitive)
 {
    if(_tcsncmp(pThis+i,pStr,iParamLen)==0)   //_tcsncmp
       return i+1;
    else
       return 0;
 }
 else
 {
    if(_tcsnicmp(pThis+i,pStr,iParamLen)==0)  //__tcsnicmp
       return i+1;
    else
       return 0;
 }
}


SIZE_T String::InStr(const TCHAR* pStr, bool blnCaseSensitive, bool blnStartBeginning)
{
 SIZE_T i,iParamLen,iRange,iReturn;

 if(*pStr==0)
    return 0;
 iParamLen=_tcslen(pStr);
 iRange=this->iLen-iParamLen;
 if(blnStartBeginning)
 {
    if(iRange>=0)
    {
       for(i=0; i<=iRange; i++)
       {
           iReturn=iMatch(this->lpBuffer,pStr,blnCaseSensitive,blnStartBeginning,i,iParamLen);
           if(iReturn)
              return iReturn;
       }
    }
 }
 else
 {
    if(iRange>=0)
    {
       for(i=iRange; i>=0; i--)
       {
           iReturn=iMatch(this->lpBuffer,pStr,blnCaseSensitive,blnStartBeginning,i,iParamLen);
           if(iReturn)
              return iReturn;
       }
    }
 }

 return 0;
}


SIZE_T String::InStr(const String& s, bool blnCaseSensitive, bool blnStartBeginning)
{
 SIZE_T i,iParamLen,iRange,iReturn;

 if(s.iLen==0)
    return 0;
 iParamLen=s.iLen;
 iRange=this->iLen-iParamLen;
 if(blnStartBeginning)
 {
    if(iRange>=0)
    {
       for(i=0; i<=iRange; i++)
       {
           iReturn=iMatch(this->lpBuffer,s.lpBuffer,blnCaseSensitive,blnStartBeginning,i,iParamLen);
           if(iReturn)
              return iReturn;
       }
    }
 }
 else
 {
    if(iRange>=0)
    {
       for(i=iRange; i>=0; i--)
       {
           iReturn=iMatch(this->lpBuffer,s.lpBuffer,blnCaseSensitive,blnStartBeginning,i,iParamLen);
           if(iReturn)
              return iReturn;
       }
    }
 }

 return 0;
}
#endif


void String::LTrim()
{
 size_t iCt=0;

 for(size_t i=0; i<this->iLen; i++)
 {
     if(this->lpBuffer[i]==32 || this->lpBuffer[i]==9)
        iCt++;
     else
        break;
 }
 if(iCt)
 {
    for(size_t i=iCt; i<=this->iLen; i++)
        this->lpBuffer[i-iCt]=this->lpBuffer[i];
 }
 this->iLen=this->iLen-iCt;
}


void String::RTrim()
{
 SIZE_T iCt=0;

 for(SIZE_T i=this->iLen-1; i>0; i--)
 {
     if(this->lpBuffer[i]==9||this->lpBuffer[i]==10||this->lpBuffer[i]==13||this->lpBuffer[i]==32)
        iCt++;
     else
        break;
 }
 this->lpBuffer[this->iLen-iCt]=0;
 this->iLen=this->iLen-iCt;
}


void String::Trim()
{
 this->LTrim();
 this->RTrim();
}


int String::iVal()
{
 return _ttoi(this->lpBuffer);  //_ttoi
}


SIZE_T String::Len(void)
{
 return this->iLen;
}


SIZE_T String::Capacity(void)
{
 return this->iCapacity;
}


TCHAR* String::lpStr()
{
 return lpBuffer;
}


#ifndef JUST_NEED_PARSE
void String::Print(bool blnCrLf)
{
 _tprintf(_T("%s"),lpBuffer);
 if(blnCrLf)
    _tprintf(_T("\n"));
}


void String::Print(TCHAR* pStr, bool blnCrLf)
{
 _tprintf(_T("%s%s"),pStr,lpBuffer);
 if(blnCrLf)
    _tprintf(_T("\n"));
}
#endif


String::~String()   //String Destructor
{
 delete [] lpBuffer;
 lpBuffer=0;
}

--- End code ---

Frederick J. Harris:
Strings.h


--- Code: ---//Strings.h
#if !defined(STRINGS_H)
#define STRINGS_H
#define EXPANSION_FACTOR      2
#define MINIMUM_ALLOCATION   16

class String
{
 public:
 #ifndef JUST_NEED_PARSE
 friend String operator+(TCHAR*, String&);
 #endif
 String();                                //Uninitialized Constructor
 String(const TCHAR);                     //Constructor Initializes With A TCHAR.
 String(const TCHAR*);                    //Constructor Initializes String With TCHAR*
 String(const String&);                   //Constructor Initializes String With Another String (Copy Constructor)
 #ifndef JUST_NEED_PARSE
 String(const SIZE_T, bool);              //Constructor Creates String With User Specified Capacity and optionally nulls out
 String(const SIZE_T, const TCHAR);       //Constructor initializes String with int # of TCHARs
 #endif
 String(SSIZE_T);                         //Constructor initializes String with int converted to String
 String(SIZE_T);                          //Constructor initializes String with unsigned int converted to String
 #ifndef JUST_NEED_PARSE
 String(double);                          //Constructor initializes String with double converted to String
 #endif
 String& operator=(const TCHAR);          //Assign A TCHAR To A String
 String& operator=(const TCHAR*);         //Assign A Null Terminated TCHARacter Array To A String
 String& operator=(const String&);        //Assigns Another String To this One
 #ifndef JUST_NEED_PARSE
 String& operator=(int iNum);             //Assigns an int to a String
 String& operator=(unsigned int iNum);    //Assigns an unsigned int to a String
 String& operator=(double dblNum);        //Assign a double to a String
 String operator+(const TCHAR);           //For adding TCHAR to String
 String operator+(const TCHAR*);          //Adds a TCHAR* to this
 String operator+(String&);               //Adds another String to this
 String& operator+=(const TCHAR ch);      //Add TCHAR to this
 String& operator+=(const String&);       //Adds a String to this and assigns it to left of equal sign
 String& operator+=(const TCHAR*);        //Adds a TCHAR*to this and assigns it to left of equal sign
 bool operator==(String&);                //Compares Strings For Case Sensitive Equality
 #endif
 bool operator==(const TCHAR*);           //Compares String Against TCHAR* For Case Sensitive Equality
 #ifndef JUST_NEED_PARSE
 String Allocate(int);                    //Allocates a String with a specified buffer size
 String& Make(const TCHAR, int);          //Returns reference to this with iCount ch TCHARs in it
 String Left(int);                        //Returns String of iNum Left Most TTCHARs of this
 String Right(int);                       //Returns String of iNum Right Most TTCHARs of this
 String Mid(SIZE_T, SIZE_T);              //Returns String consisting of number of TTCHARs from some offset
 String Replace(TCHAR*, TCHAR*);          //Returns String with 1st TCHAR* parameter replaced with 2nd TCHAR* parameter
 String Remove(TCHAR*);                   //Returns A String With All The TCHARs In A TCHAR* Removed (Individual TCHAR removal)
 String Remove(const TCHAR*, bool);       //Returns a String with 1st parameter removed.  2nd is bool for case sensitivity.
 SIZE_T InStr(const TCHAR*, bool, bool);  //Returns one based case sensitive/insensitive offset of a particular TCHAR pStr in a String, starting from left or right (left=true)
 SIZE_T InStr(const String&, bool, bool); //Returns one based case sensitive/insensitive offset of where a particular String is in another String, starting from left or right (left=true)
 #endif
 int ParseCount(const TCHAR);             //Returns count of Strings delimited by a TTCHAR passed as a parameter
 void Parse(String*, TCHAR);              //Returns array of Strings in first parameter as delimited by 2nd TTCHAR delimiter
 #ifndef JUST_NEED_PARSE
 void SetTCHAR(unsigned, TCHAR);               //Sets TCHAR at zero based offset in this
 #endif
 void LTrim();                            //Returns String with leading spaces/tabs removed
 void RTrim();                            //Returns String with spaces/tabs removed from end
 void Trim();                             //Returns String with both leading and trailing whitespace removed
 int iVal();                              //Returns integral value of String
 SIZE_T Len();                            //Returns Length Of String Controlled By this
 SIZE_T Capacity();                       //Returns Maximum Permissable TCHARacter Count (One Less Than Allocation).
 TCHAR* lpStr();                          //Returns TCHAR* To String
 #ifndef JUST_NEED_PARSE
 void Print(bool);                        //Outputs String To Console With Or Without CrLf.
 void Print(TCHAR*, bool);                //Outputs String To Console With Or Without CrLf.
 #endif
 ~String();                               //String Destructor

 private:
 TCHAR* lpBuffer;
 SIZE_T iLen;
 SIZE_T iCapacity;
};
#ifndef JUST_NEED_PARSE
String operator+(TCHAR* lhs, String& rhs);
#endif
#endif  //#if !defined(STRINGS_H)

--- End code ---

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version