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

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

(1/4) > >>

Frederick J. Harris:
     Isn't it a wonderful feeling to have tackled a complex and important coding project and to have finally finished it with a good outcome?  That's how I feel now with having translated my COM based PowerBASIC Grid Control over to C++.  So I know how you felt Patrice when you finally got your dlls/products working in C++!  While I used Microsoft's VC 9 from Visual Studio 2008 to compile the grid for both x86 and x64, I wrote a client for testing purposes which comes in six different flavors (different languages and compilers).  Before I get to the grid I'd like to talk about that testing client a little, as that’s what I’ve been working on for the past couple days since having completed the grid work last week.  So this will be like a movie that starts at the end, which has been a popular theatrical technique for some time now. 

     First, of course, I used the same compiler, i.e., Microsoft's, for two of the clients, that is, an x86 and a x64 version.  Then I used my favorite C++ compiler, which is the one I got with my Code::Blocks 10.05 installation - GCC 4.4.1-2 circa 2009 or so.  That only makes 32 bit binaries though.  The next two would be the latest MinGW GCC compiler, release date October 2013, which does both x86 and x64 exes….

http://tdm-gcc.tdragon.net/download

     Finally, I cobbled together a PowerBASIC client using version 10, i.e., PBWin 10.  Of course, that would be just for the 32 bit version of the grid.  I've got to say it was pretty cool running all six of those clients - some 32 bit and some 64 bit - at the same time on my laptop!  Especially when you consider that they all have the exact same GUIDS, ProgIDs, the works!  And except for the PowerBASIC code they all stem from the exact same source code, line for line.  The client program screen footprint is fairly small so they all fit on my screen at the same time.  There is just a grid with 8 rows of dummy data and seven buttons that exercise various functionality of the grid when clicked, such as retrieving data, filling the grid, coloring rows, selecting rows, showing the Combo Box in Column 5, etc.  All the clients were compiled with settings to minimize code size and strip debugging symbols from the executable.  Here's the results.  Read 'em and weep any of you PowerBASIC or Bob Zale haters out there!


--- Code: ---                                 ActiveX Grid Clients

Compiler                       Architecture   Date       Size    Easy String Handling
=======================================================================================
PowerBASIC Windows 10.03            x86      3/1/2011     25K    Yes  Native PowerBASIC

tdm-mingw-1.908.0-4.4.1-2 GCC       x86     10/4/2009     27K     No  C Style Strings

tdm-mingw-1.908.0-4.4.1-2 GCC       x86     10/4/2009     35K    Yes  My String Class

Microsoft VC++ 9 VStudio 2008       x64     11/8/2007     80K    Yes  My String Class
                                                                                                                                                                               
tdm64-gcc-4.8.1-3         GCC       x86     10/6/2013    159K    Yes  My String Class

tdm64-gcc-4.8.1-3         GCC       x64     10/6/2013    224K    Yes  My String Class

--- End code ---

     So PowerBASIC wins at 25K.  Note above I couldn't even beat my PowerBASIC client using C Style strings.  That would be the 2nd example above that came in 27K using the older GCC compiler.  That surprised me.  Usually if I resort to C style strings and leave out any uses of 'class' or 'new' in a C++ program, I can beat out PowerBASIC's size by a hair. For some reason it didn't work here.  PowerBASIC comes out smaller by a couple K.

     Note the massive bloated executables from the most recent GCC offering - 224K is the smallest I could bring down the client on the x64 version.  And this is for exactly the same program and functionality as the 25K PowerBASIC 10 version.  What the deal is there are the new C++ 11 coding standards, which apparently forces incorporation of the winpthreads library into every binary created by the package.  In fact, the installation of that package started with this unusual and noteworthy warning which had been lacking in their previous installations ...


--- Quote ---Hi! Sorry for the interruption, but you may want to take at least a few seconds
to look into some recent license changes for the software you're about to
install.

Parts of the "winpthreads" library will be compiled into every binary file (EXE
or DLL) you create. It's a necessary evil that is currently required in order to
provide support for threads and concurrency in programs compiled by GCC.

The license for winpthreads requires you to reproduce its text in every copy or
substantial portion of the winpthreads library that you distribute. This means
that even if you just want to distribute a single small executable, created with
TDM-GCC (or any winpthreads-based GCC release), you must include a copy of that
license.

Check the license out in the file "COPYING.winpthreads.txt", which will be
installed along with TDM-GCC. Consult with a lawyer if you have any concerns
about how you can use this software.

Does this new license hurt your usage of GCC? Let the developers know!
 
File a feature request asking them to change the winpthreads license or get rid
of GCC's winpthreads requirement, at:

https://sourceforge.net/p/mingw-w64/feature-requests/new/

Send an email to the MinGW-w64 mailing list, at:

mingw-w64-public@lists.sourceforge.net

--- End quote ---

     So there you have it.  Bob Zale is gone and the "Brave New World" we are entering is a world of bloat ware!  Bloat ware rules!  For all the good it will do I'm going to complain loudly at the above Source Forge email address.  I’ve heard the saying that 'Progress Rides In A Hearse', so when some of us old folks who bemoan such things are all gone there won't even be any memory of small and efficient programs. 

     Anyway, now to the grid.  My biggest concern (other than whether or not I'd successfully manage the translation and the thing would work) was how many K in size it would end up being.  I was proud of the fact that my PowerBASIC grid was about 50K and the UPX executable packer ...

http://upx.sourceforge.net/

... could compress it to a miniscule 22K!  I knew I'd have to use MSVC for the compiler because I wanted 64 bit, and in my opinion VC9 seemed to create pretty big binaries.  It turned out pretty good though.  I'm happy!  At first I was coming in about 100K in the release build.  I'm using my String Class rather than the one in the C++ Standard Library, so that helped quite a bit - probably to the tune of 30 or 40 K.  Then just here at the end it occurred to me that my grid code makes very little use of my String Class code (although I do need it badly for its ParseCount / Parse functionality), so the idea occurred to me that I could include a special build of the String Class which would only contain the parsing code my grid really needed and nothing else! I was actually able to remove most of the code, and that brought the release build down to 86K.  So I saved about 14 K there.  Finally, the good folks at UPX just released a new version of their exe packer that does x64 binaries (my old version didn't work on x64s - I tried).  So its coming in at 43 K packed.  I don't think that's too bad for a reasonably featured x64 ActiveX Grid Control with built in self-registration.   

     All the PowerBASIC code for my translated grid came in around 3400 lines of code and except for the *.idl file its all in one file which is posted and downloadable from here ...

http://www.jose.it-berater.org/smfforum/index.php?topic=4642.0

     I have the C++ version code organized pretty much according to C++ coding standards, such as they are, and here's what the file/project setup which I'm about to post looks like, with lines of code to the right ...


--- Code: ---FHGrid.dll -- ActiveX Grid Control
==================================
FHGrid.idl          58
FHGrid.def           7
Strings.h           81
Strings.cpp        806
Server.cpp         241
Registry.h           5
Registry.cpp       170
Interfaces.h        36
Grid.h             117
Grid.cpp          1121
WinCode.h           59
WinCode.cpp       1311
===================================
                  4012

--- End code ---


     By the way, the way I worked it with my special build of the string class, is I created this #define in it ...

#define   JUST_NEED_PARSE

... and if that's not commented out, then everything I don't need is left out using #ifndef conditional compilation logic.  You'll see that if you look at the string class code.  You'll see that in the Strings.cpp file.

I'll start posting the code now, and discuss it afterwards ...

Frederick J. Harris:
We'll start small.  Here is FHGrid.def ...


--- Code: ---;//FHGrid.def
LIBRARY      "FHGrid"
EXPORTS
    DllGetClassObject     PRIVATE 
    DllCanUnloadNow       PRIVATE
    DllRegisterServer     PRIVATE
    DllUnregisterServer   PRIVATE

--- End code ---

And even slaller, FHGrid.rc


--- Code: ---1 TYPELIB "FHGrid.tlb"

--- End code ---

Now, FHGrid.idl


--- Code: ---// FHGrid.idl
import "unknwn.idl";

[object, uuid(30000000-0000-0000-0000-000000000001), oleautomation] interface IGrid : IUnknown
{
 HRESULT CreateGrid
 (
  [in] HWND     hParent,
  [in] BSTR     strSetup,
  [in] int      x,
  [in] int      y,
  [in] int      cx,
  [in] int      cy,
  [in] int      iRows,
  [in] int      iCols,
  [in] int      iRowHt,
  [in] COLORREF iSelectionBackColor,
  [in] COLORREF iSelectionTextColor,
  [in] BSTR     strFontName,
  [in] int      iFontSize,
  [in] int      iFontWeight
 );
 HRESULT SetRowCount([in] int iRowCount, [in] int blnForce);
 HRESULT GetRowCount([out, retval] int* iRowCount);
 HRESULT SetData([in] int iRow, [in] int iCol, [in] BSTR strData);
 HRESULT GetData([in] int iRow, [in] int iCol, [out, retval] BSTR* strData);
 HRESULT FlushData();
 HRESULT Refresh();
 HRESULT GetVisibleRows([out, retval] int* iVisibleRows);
 HRESULT GethGrid([out, retval] HWND* hWnd);
 HRESULT GethCell([in] int iRow, [in] int iCol, [out, retval] HWND* hCell);
 HRESULT GethComboBox([in] int iCol, [out, retval] HWND* hCombo);
 HRESULT SetCellAttributes([in] int iRow, [in] int iCol, [in] int iBackColor, [in] int iTextColor);
 HRESULT DeleteRow([in] int iRow);
};

[object, uuid(30000000-0000-0000-0000-000000000002), oleautomation] interface IGridEvents : IUnknown
{
 HRESULT Grid_OnKeyPress([in] int iKeyCode, [in] int iKeyData, [in] int iRow, [in] int iCol, [out] int* blnCancel);
 HRESULT Grid_OnKeyDown([in] int KeyCode, [in] int iKeyData, [in] int iCellRow, [in] int iGridRow, [in] int iCol, [out] int* blnCancel);
 HRESULT Grid_OnLButtonDown([in] int iCellRow, [in] int iGridRow, [in] int iCol);
 HRESULT Grid_OnLButtonDblClk([in] int iCellRow, [in] int iGridRow, [in] int iCol);
 HRESULT Grid_OnPaste([in] int iCellRow, [in] int iGridRow, [in] int iCol);
 HRESULT Grid_OnRowSelection([in] int iRow, [in] int iAction);
 HRESULT Grid_OnDelete([in] int iRow);
};

[uuid(30000000-0000-0000-0000-000000000003), helpstring("FHGrid TypeLib"), version(1.0)] library FHGridLibrary
{
 importlib("stdole32.tlb");
 interface IGrid;
 interface IGridEvents;
 [uuid(30000000-0000-0000-0000-000000000000)] coclass FHGrid
 {
           interface IGrid;
  [source] interface IGridEvents;
 }
};

--- End code ---

Maybe I can fit a few headers ...


--- Code: ---//Grid.h
#ifndef     GRID_H_INCLUDED
#define     GRID_H_INCLUDED
#include    "Interfaces.h"
#define     MAX_CONNECTIONS  4
#define     dwIdx(r,c) ((r-1)*pGridData->iCols+(c-1))
extern long g_lObjs;
extern long g_lLocks;

class FHGrid : public IGrid, public IConnectionPointContainer, public IConnectionPoint
{
 public:
 FHGrid();            //Constructor
 virtual ~FHGrid();   //Destructor

 //Iunknown Functions
 virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID& iid, void** ppv);
 virtual ULONG   STDMETHODCALLTYPE AddRef();
 virtual ULONG   STDMETHODCALLTYPE Release();

 //IGrid Interface Methods/Functions
 virtual HRESULT STDMETHODCALLTYPE CreateGrid(HWND, BSTR, int, int, int, int, int, int, int, COLORREF, COLORREF, BSTR, int, int);
 virtual HRESULT STDMETHODCALLTYPE SetRowCount(int, int);
 virtual HRESULT STDMETHODCALLTYPE GetRowCount(int*);
 virtual HRESULT STDMETHODCALLTYPE SetData(int, int, BSTR);
 virtual HRESULT STDMETHODCALLTYPE GetData(int, int, BSTR*);
 virtual HRESULT STDMETHODCALLTYPE FlushData(void);
 virtual HRESULT STDMETHODCALLTYPE Refresh(void);
 virtual HRESULT STDMETHODCALLTYPE GetVisibleRows(int*);
 virtual HRESULT STDMETHODCALLTYPE GethGrid(HWND*);
 virtual HRESULT STDMETHODCALLTYPE GethCell(int, int, HWND*);
 virtual HRESULT STDMETHODCALLTYPE GethComboBox(int, HWND*);
 virtual HRESULT STDMETHODCALLTYPE SetCellAttributes(int, int, COLORREF, COLORREF);
 virtual HRESULT STDMETHODCALLTYPE DeleteRow(int);

 //IConnectionPointContainer Interface Methods/Functions
 virtual HRESULT STDMETHODCALLTYPE EnumConnectionPoints(IEnumConnectionPoints** ppEnum);            //not implemented
 virtual HRESULT STDMETHODCALLTYPE FindConnectionPoint(REFIID riid, IConnectionPoint** ppCP);

 // IConnectionPoint
 virtual HRESULT STDMETHODCALLTYPE GetConnectionInterface(IID* pIID);                               //not implemented
 virtual HRESULT STDMETHODCALLTYPE GetConnectionPointContainer(IConnectionPointContainer** ppCPC);  //not implemented
 virtual HRESULT STDMETHODCALLTYPE Advise(IUnknown* pUnknown, DWORD* pdwCookie);
 virtual HRESULT STDMETHODCALLTYPE Unadvise(DWORD dwCookie);
 virtual HRESULT STDMETHODCALLTYPE EnumConnections(IEnumConnections** ppEnum);                      //not implemented

 public:
 HWND          hWndCtrl;
 IGridEvents** pISink;
 long          m_lRef;
};


class GridClassFactory : public IClassFactory
{
 public:
 GridClassFactory();
 virtual ~GridClassFactory();

 public:
 //IUnknown
 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**);
 virtual ULONG   STDMETHODCALLTYPE AddRef();
 virtual ULONG   STDMETHODCALLTYPE Release();

 //IclassFactory
 virtual HRESULT STDMETHODCALLTYPE CreateInstance(LPUNKNOWN, REFIID, void**);
 virtual HRESULT STDMETHODCALLTYPE LockServer(BOOL);

 protected:
 long  m_lRef;
};


struct GridData
{
 int         iCtrlId;
 HWND        hParent;
 HWND        hGrid;
 HWND        hBase;
 HWND        hPane;
 HWND        hCtrlInCell;
 int         cx;
 int         cy;
 HWND        hHeader;
 int         iCols;
 int         iRows;
 int         iVisibleRows;
 int         iRowHeight;
 int         iPaneHeight;
 int         iEditedCellRow;
 int         iEditedRow;
 int         iEditedCol;
 FHGrid*     pComObj;
 DWORD*      pColWidths;
 DWORD*      pCellCtrlTypes;
 HWND*       pCellHandles;
 TCHAR**     pGridMemory;
 COLORREF*   pTextColor;
 HBRUSH*     pBackColor;
 COLORREF*   pCreatedColors;
 HBRUSH*     pCreatedBrushes;
 HWND*       pVButtons;
 HWND*       pCtrlHdls;
 COLORREF    iSelectionBackColor;
 COLORREF    iSelectionTextColor;
 int         blnRowSelected;
 int         iSelectedRow;
 int         iFontSize;
 int         iFontWeight;
 HFONT       hFont;
 TCHAR       szFontName[28];
};

void Initialize();
#endif
//End Grid.h

--- End code ---

Frederick J. Harris:
Interfaces.h


--- Code: ---//IFunctions.h
#ifndef INTERFACES_H_INCLUDED
#define INTERFACES_H_INCLUDED
const CLSID CLSID_FHGrid           =                    {0x30000000, 0x0000, 0x0000, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}            };
const IID   IID_IFHGrid            =                    {0x30000000, 0x0000, 0x0000, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}            };
const IID   IID_IFHGridEvents      =                    {0x30000000, 0x0000, 0x0000, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}            };
const IID   LIBID_FHGrid           =                    {0x30000000, 0x0000, 0x0000, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}            };

interface IGrid : IUnknown
{
 virtual HRESULT STDMETHODCALLTYPE CreateGrid           (HWND, BSTR, int, int, int, int, int, int, int, COLORREF, COLORREF, BSTR, int, int) = 0;
 virtual HRESULT STDMETHODCALLTYPE SetRowCount          (int, int                                                                         ) = 0;
 virtual HRESULT STDMETHODCALLTYPE GetRowCount          (int*                                                                             ) = 0;
 virtual HRESULT STDMETHODCALLTYPE SetData              (int, int, BSTR                                                                   ) = 0;
 virtual HRESULT STDMETHODCALLTYPE GetData              (int, int, BSTR*                                                                  ) = 0;
 virtual HRESULT STDMETHODCALLTYPE FlushData            (void                                                                             ) = 0;
 virtual HRESULT STDMETHODCALLTYPE Refresh              (void                                                                             ) = 0;
 virtual HRESULT STDMETHODCALLTYPE GetVisibleRows       (int *iVisibleRows                                                                ) = 0;
 virtual HRESULT STDMETHODCALLTYPE GethGrid             (HWND*                                                                            ) = 0;
 virtual HRESULT STDMETHODCALLTYPE GethCell             (int, int, HWND*                                                                  ) = 0;
 virtual HRESULT STDMETHODCALLTYPE GethComboBox         (int, HWND*                                                                       ) = 0;
 virtual HRESULT STDMETHODCALLTYPE SetCellAttributes    (int, int, COLORREF, COLORREF                                                     ) = 0;
 virtual HRESULT STDMETHODCALLTYPE DeleteRow            (int                                                                              ) = 0;
};

interface IGridEvents : IUnknown
{
 virtual HRESULT STDMETHODCALLTYPE Grid_OnKeyPress      (int iKeyCode, int iKeyData, int iRow, int iCol, int* blnCancel                   ) = 0;
 virtual HRESULT STDMETHODCALLTYPE Grid_OnKeyDown       (int KeyCode, int iKeyData, int iCellRow, int iGridRow, int iCol, int* blnCancel  ) = 0;
 virtual HRESULT STDMETHODCALLTYPE Grid_OnLButtonDown   (int iCellRow, int iGridRow, int iCol                                             ) = 0;
 virtual HRESULT STDMETHODCALLTYPE Grid_OnLButtonDblClk (int iCellRow, int iGridRow, int iCol                                             ) = 0;
 virtual HRESULT STDMETHODCALLTYPE Grid_OnPaste         (int iCellRow, int iGridRow, int iCol                                             ) = 0;
 virtual HRESULT STDMETHODCALLTYPE Grid_OnRowSelection  (int iRow, int iAction                                                            ) = 0;
 virtual HRESULT STDMETHODCALLTYPE Grid_OnDelete        (int iRow                                                                         ) = 0;
};
#endif

--- End code ---

WinCode.h

--- Code: ---//WinCode.h
#ifndef WIN_CODE_H_INCLUDED
#define WIN_CODE_H_INCLUDED

#define GRID_CELL_CTRL_NONE         0
#define GRID_CELL_CTRL_EDIT         1
#define GRID_CELL_CTRL_COMBO        2
#define GRID_CELL_CTRL_CHECK        3
#define IDC_STATIC                  -1
#define MAX_COLORS                  15
#define ID_PANE                     1500
#define ID_HEADER                   1505
#define ID_CELL                     1600
#define IDC_EDIT                    1605
#define IDC_COMBO                   1705

#define dim(x) (sizeof(x) / sizeof(x[0]))
LRESULT CALLBACK fnGridProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK fnPaneProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK fnBaseProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK fnCellProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam);


struct                              WindowsEventArguments
{
 HWND                               hWnd;
 WPARAM                             wParam;
 LPARAM                             lParam;
 HINSTANCE                          hIns;
};

typedef WindowsEventArguments*      lpWndEventArgs;

long fnGridProc_OnCreate            (lpWndEventArgs Wea);
long fnGridProc_OnSize              (lpWndEventArgs Wea);
long fnGridProc_OnHScroll           (lpWndEventArgs Wea);
long fnGridProc_OnVScroll           (lpWndEventArgs Wea);
long fnGridProc_OnKeyDown           (lpWndEventArgs Wea);
long fnGridProc_OnCommand           (lpWndEventArgs Wea);
long fnGridProc_OnDestroy           (lpWndEventArgs Wea);

struct EVENTHANDLER
{
 unsigned int                       iMsg;
 long                               (*fnPtr)(lpWndEventArgs);
};

const EVENTHANDLER EventHandler[]=
{
 {WM_CREATE,                        fnGridProc_OnCreate},
 {WM_SIZE,                          fnGridProc_OnSize},
 {WM_HSCROLL,                       fnGridProc_OnHScroll},
 {WM_VSCROLL,                       fnGridProc_OnVScroll},
 {WM_KEYDOWN,                       fnGridProc_OnKeyDown},
 {WM_COMMAND,                       fnGridProc_OnCommand},
 {WM_DESTROY,                       fnGridProc_OnDestroy}
};

#endif

--- End code ---

Registry.h

--- Code: ---BOOL SetKeyAndValue(const TCHAR* szKey, const TCHAR* szSubkey, const TCHAR* szValue);
void CLSIDToChar(const CLSID& clsid, TCHAR* szCLSID, int length);
LONG RecursiveDeleteKey(HKEY hKeyParent, const TCHAR* lpszKeyChild);
HRESULT RegisterServer(TCHAR* szModule, const CLSID& clsid, const TCHAR* szFriendlyName, const TCHAR* szVerIndProgID, const TCHAR* szProgID);
HRESULT UnregisterServer(const CLSID& clsid, const TCHAR* szVerIndProgID, const TCHAR* szProgID);

--- End code ---

Frederick J. Harris:
Grid.cpp


--- Code: ---//Grid.cpp
#define   UNICODE
#define   _UNICODE
//#define MYDEBUG
#include  <windows.h>
#include  <commctrl.h>
#include  <objbase.h>
#include  <ocidl.h>
#include  <olectl.h>
#include  <tchar.h>
#include  <cstdio>
#include  "Grid.h"
#include  "WinCode.h"

extern WNDPROC   fnEditWndProc;
extern HINSTANCE g_hModule;
extern long      g_CtrlId;

#if defined MYDEBUG
extern FILE*     fp;
#endif


FHGrid::FHGrid()   //C++ Constructor for class FHGrid
{
 #if defined MYDEBUG
 printf("  Entering FHGrid Constructor!\n");
 #endif
 this->pISink=NULL,  this->hWndCtrl=NULL,  m_lRef=0;
 #if defined MYDEBUG
 printf("    this->m_lRef = %d\n", this->m_lRef);
 #endif
 InterlockedIncrement(&g_lObjs);
 #if defined MYDEBUG
 printf("    g_lObjs       = %d\n", g_lObjs);
 printf("    sizeof(*this) = %d\n",sizeof(*this));
 #endif
 #if defined MYDEBUG
 printf("  Leaving FHGrid Constructor!\n");
 #endif
}


HRESULT STDMETHODCALLTYPE FHGrid::QueryInterface(REFIID riid, void** ppv)
{
 #if defined MYDEBUG
 printf("    Entering FHGrid::QueryInterface()\n");
 printf("      this = %d\n", this);
 #endif
 *ppv=0;
 if(riid==IID_IUnknown)
    *ppv=(IGrid*)this;
 else if(riid==IID_IFHGrid)
    *ppv=(IGrid*)this;
 else if(riid==IID_IConnectionPointContainer)
    *ppv=(IConnectionPointContainer*)this;
 else if(riid==IID_IConnectionPoint)
    *ppv=(IConnectionPoint*)this;
 if(*ppv)
 {
    AddRef();
    #if defined MYDEBUG
    printf("      *ppv = %u\n",*ppv);
    printf("    Leaving FHGrid::QueryInterface()\n");
    #endif
    return S_OK;
 }
 #if defined MYDEBUG
 printf("    Leaving FHGrid::QueryInterface()\n");
 #endif

 return(E_NOINTERFACE);
}


ULONG STDMETHODCALLTYPE FHGrid::AddRef()
{
 #if defined MYDEBUG
 printf("    Entering FHGrid::AddRef()\n");
 printf("      m_lRef = %d\n", m_lRef);
 #endif
 InterlockedIncrement(&m_lRef);
 #if defined MYDEBUG
 printf("      m_lRef = %d\n", m_lRef);
 printf("    Leaving FHGrid::AddRef()\n");
 #endif

 return m_lRef;
}


ULONG STDMETHODCALLTYPE FHGrid::Release()
{
 #if defined MYDEBUG
 printf("    Entering FHGrid::Release()\n");
 printf("      m_lRef = %d\n", m_lRef);
 #endif
 if(InterlockedDecrement(&m_lRef)==0)
 {
    #if defined MYDEBUG
    printf("      m_lRef = %d\n", m_lRef);
    printf("      Will Now Delete this ...\n");
    printf("      this->pISink = %u\n\n",this->pISink);
    printf("      i\t\t&this->pISink[i]\t\tthis->pISink[i]\n");
    printf("      ============================================================\n");
    for(size_t i=0; i<MAX_CONNECTIONS; i++)
        printf("      %u\t\t%u\t\t\t\t%u\n",i,&this->pISink[i],this->pISink[i]);
    printf("    \nLeaving FHGrid::Release()\n");
    #endif
    DestroyWindow(this->hWndCtrl);
    CoTaskMemFree(this->pISink);
    delete this;
    return 0;
 }
 #if defined MYDEBUG
 printf("      m_lRef = %d\n", m_lRef);
 printf("    Leaving FHGrid::Release()\n");
 #endif

 return m_lRef;
}


HRESULT STDMETHODCALLTYPE FHGrid::CreateGrid(HWND hParent, BSTR strSetup, int x, int y, int cx, int cy, int iRows, int iCols, int iRowHt, COLORREF iSelBckClr, COLORREF iSelTxtClr, BSTR strFntNme, int iFntSize, int iFntWt)
{
 GridData* pGridData=NULL;
 DWORD dwStyle;
 HWND hGrid=0;
 GridData gd;

 #ifndef UNICODE
 return E_FAIL;
 #endif
 #if defined MYDEBUG
 printf("Entering FHGrid::CreateGrid()\n");
 _ftprintf(fp,_T("Entering FHGrid::CreateGrid()\n"));
 _ftprintf(fp,_T("  this       = %u\n"),this);
 _ftprintf(fp,_T("  hParent    = %u\n"),hParent);
 _ftprintf(fp,_T("  strSetup   = %s\n"),strSetup);
 _ftprintf(fp,_T("  x          = %d\n"),x);
 _ftprintf(fp,_T("  y          = %d\n"),y);
 _ftprintf(fp,_T("  cx         = %d\n"),cx);
 _ftprintf(fp,_T("  cy         = %d\n"),cy);
 _ftprintf(fp,_T("  iRows      = %d\n"),iRows);
 _ftprintf(fp,_T("  iCols      = %d\n"),iCols);
 _ftprintf(fp,_T("  iRowHt     = %d\n"),iRowHt);
 _ftprintf(fp,_T("  iSelBckClr = %d\n"),iSelBckClr);
 _ftprintf(fp,_T("  iSelTxtClr = %d\n"),iSelTxtClr);
 _ftprintf(fp,_T("  strFntNme  = %s\n"),strFntNme);
 _ftprintf(fp,_T("  iFntSize   = %d\n"),iFntSize);
 _ftprintf(fp,_T("  iFntWt     = %d\n"),iFntWt);
 #endif
 dwStyle                       = WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;
 gd.hParent                    = hParent;
 gd.cx                         = cx;
 gd.cy                         = cy;
 gd.iRows                      = iRows;
 gd.iCols                      = iCols;
 gd.iRowHeight                 = iRowHt;
 gd.iFontSize                  = iFntSize;
 gd.iFontWeight                = iFntWt;
 gd.iSelectionBackColor        = iSelBckClr;
 gd.iSelectionTextColor        = iSelTxtClr;
 gd.iCtrlId=g_CtrlId;
 wcscpy(gd.szFontName,strFntNme);
 #if defined MYDEBUG
 _ftprintf(fp,_T("  gd.szFontName       = %s\n\n"),gd.szFontName);
 _ftprintf(fp,_T("  g_CtrlId            = %d\n"),g_CtrlId);
 #endif
 hGrid=CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,L"Grid",strSetup,dwStyle,x,y,cx,cy,hParent,(HMENU)g_CtrlId,g_hModule,&gd);
 if(hGrid==0)
    return E_FAIL;
 g_CtrlId++;
 this->hWndCtrl=hGrid;
 pGridData=(GridData*)GetWindowLongPtr(hGrid,0);
 if(!pGridData)
    return E_FAIL;
 pGridData->pComObj=this;

 if(iSelBckClr==0)
    pGridData->iSelectionBackColor=RGB(0x41,0x69,0xE1);  //  RGB_ROYALBLUE;    // %RGB_ROYALBLUE = 0xE16941
 if(iSelTxtClr==0)
    pGridData->iSelectionTextColor=RGB(0x80,0x00,0x00);  //  RGB_MAROON;       // %RGB_MAROON    = 0x000080
 this->SetCellAttributes(0,0,pGridData->iSelectionBackColor,pGridData->iSelectionTextColor);
 SetFocus(hGrid);

 #if defined MYDEBUG
 _ftprintf(fp,_T("  hGrid                          = %u\n"),hGrid);
 _ftprintf(fp,_T("  pGridData                      = %u\n"),pGridData);
 _ftprintf(fp,_T("  pGridData->pComObj             = %u\n"),pGridData->pComObj);
 _ftprintf(fp,_T("  this->hWndCtrl                 = %u\n"),this->hWndCtrl);
 _ftprintf(fp,_T("  &gd                            = %u\n"),&gd);
 _ftprintf(fp,_T("  pGridData->blnRowSelected      = %d\n"),pGridData->blnRowSelected);
 _ftprintf(fp,_T("  pGridData->iSelectionBackColor = %0x\n"),pGridData->iSelectionBackColor);
 _ftprintf(fp,_T("  pGridData->iSelectionTextColor = %0x\n"),pGridData->iSelectionTextColor);
 _ftprintf(fp,_T("Leaving FHGrid::CreateGrid()\n\n"));
 printf("  Leaving FHGrid::CreateGrid()\n");
 #endif

 return S_OK;
}


HRESULT STDMETHODCALLTYPE FHGrid::SetRowCount(int iRowCount, int blnForce)
{
 GridData* pGridData=NULL;
 int iSize=0,blnFree=0;
 HANDLE hHeap=0;
 SCROLLINFO si;
 int i;

 #ifdef MYDEBUG
 _ftprintf(fp,_T("Entering FHGrid::SetRowCount()\n"));
 _ftprintf(fp,_T("  i         blnFree\n"));
 _ftprintf(fp,_T("  =================\n"));
 #endif
 pGridData=(GridData*)GetWindowLongPtr(this->hWndCtrl,0);
 iSize=pGridData->iRows*pGridData->iCols;
 hHeap=GetProcessHeap();
 for(i=0; i<iSize; i++)
 {
     blnFree=HeapFree(hHeap,0,pGridData->pGridMemory[i]);
     #ifdef MYDEBUG
     _ftprintf(fp,_T("  %d\t%d\n"),i,blnFree);
     #endif
 }
 blnFree=HeapFree(hHeap,0,pGridData->pGridMemory);
 #ifdef MYDEBUG
 _ftprintf(fp,_T("\n  HeapFree(hHeap,0,pGridData->pGridMemory) = %d\n"),blnFree);
 #endif
 blnFree=HeapFree(hHeap,0,pGridData->pTextColor);
 #ifdef MYDEBUG
 _ftprintf(fp,_T("  HeapFree(hHeap,0,pGridData->pTextColor) = %d\n"),blnFree);
 #endif
 blnFree=HeapFree(hHeap,0,pGridData->pBackColor);
 #ifdef MYDEBUG
 _ftprintf(fp,_T("  HeapFree(hHeap,0,pGridData->pBackColor) = %d\n"),blnFree);
 #endif

 //Create A New Memory Block
 if(iRowCount < pGridData->iVisibleRows)
 {
    #ifdef MYDEBUG
    _ftprintf(fp,_T("  Got In Where iRowCount < iVisibleRows"));
    #endif
    iRowCount=pGridData->iVisibleRows+1;
 }
 iSize = iRowCount * pGridData->iCols;
 pGridData->pGridMemory=(TCHAR**)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iSize*sizeof(void*));
 if(!pGridData->pGridMemory)
    return E_FAIL;
 pGridData->iRows=iRowCount;
 ZeroMemory(&si, sizeof(SCROLLINFO));
 si.cbSize=sizeof(SCROLLINFO);
 si.fMask=SIF_RANGE | SIF_PAGE | SIF_POS;
 si.nMin=1;
 si.nMax=pGridData->iRows;
 si.nPage=pGridData->iVisibleRows;
 si.nPos=1;
 SetScrollInfo(this->hWndCtrl,SB_VERT,&si,TRUE);
 pGridData->pTextColor=(COLORREF*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iSize*sizeof(void*));
 #ifdef MYDEBUG
 _ftprintf(fp,_T("  pGridData->pTextColor = %u\n"),pGridData->pTextColor);
 #endif
 if(!pGridData->pTextColor)
    return E_FAIL;
 pGridData->pBackColor=(HBRUSH*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iSize*sizeof(void*));
 #ifdef MYDEBUG
 _ftprintf(fp,_T("  pGridData->pBackColor = %u\n"),pGridData->pBackColor);
 #endif
 if(!pGridData->pBackColor)
    return E_FAIL;
 #ifdef MYDEBUG
 _ftprintf(fp,_T("Leaving FHGrid::SetRowCount()\n\n"));
 #endif

 return S_OK;
}


HRESULT STDMETHODCALLTYPE FHGrid::GetRowCount(int* iRowCount)
{
 #ifdef MYDEBUG
 _ftprintf(fp,_T("Entering FHGrid::GetRowCount()\n"));
 #endif
 GridData* pGridData=(GridData*)GetWindowLong(this->hWndCtrl,0);
 if(pGridData)
 {
    *iRowCount=pGridData->iRows;
    #ifdef MYDEBUG
    _ftprintf(fp,_T("  *iRowCount = %d\n"),*iRowCount);
    _ftprintf(fp,_T("Leaving FHGrid::GetRowCount()\n"));
    #endif
    return S_OK;
 }
 #ifdef MYDEBUG
 _ftprintf(fp,_T("  *iRowCount = %d\n"),*iRowCount);
 _ftprintf(fp,_T("Leaving FHGrid::GetRowCount()\n"));
 #endif

 return E_FAIL;
}


HRESULT STDMETHODCALLTYPE FHGrid::SetData(int iRow, int iCol, BSTR strData)
{
 GridData* pGridData=NULL;
 HANDLE hHeap=NULL;
 int iIndex;

 #ifdef MYDEBUG
 printf("Called FHGrid::SetData()\n");
 _ftprintf(fp,_T("Entering FHGrid::SetData()\n"));
 _ftprintf(fp,_T("  this         = %u\n"),this);
 _ftprintf(fp,_T("  iRow         = %d\n"),iRow);
 _ftprintf(fp,_T("  iCol         = %d\n"),iCol);
 _ftprintf(fp,_T("  strData      = %s\n"),strData);
 #endif
 pGridData=(GridData*)GetWindowLongPtr(this->hWndCtrl,0);
 if(pGridData)
 {
    if(iRow && iRow<=pGridData->iRows)
    {
       if(iCol && iCol<=pGridData->iCols)
       {
          iIndex=dwIdx(iRow,iCol);
          hHeap=GetProcessHeap();
          #ifdef MYDEBUG
          _ftprintf(fp,_T("  iIndex       = %d\n"),iIndex);
          _ftprintf(fp,_T("  pGridData->pGridMemory[iIndex] = %u\n"),pGridData->pGridMemory[iIndex]);
          _ftprintf(fp,_T("  pGridData->pGridMemory[iIndex] = %s\n"),pGridData->pGridMemory[iIndex]);
          #endif
          if(pGridData->pGridMemory[iIndex]==NULL)
          {
             #ifdef MYDEBUG
             _ftprintf(fp,_T("  Got In Where Memory Is Null\n"));
             #endif
             pGridData->pGridMemory[iIndex]=(TCHAR*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,(SysStringLen(strData)*sizeof(TCHAR))+sizeof(TCHAR));
             if(pGridData->pGridMemory[iIndex])
                _tcscpy(pGridData->pGridMemory[iIndex],strData);
             else
                return S_FALSE;
          }
          else
          {
             if(wcscmp(pGridData->pGridMemory[iIndex],strData)==0)  // Both Strings Are The Same, So No Need To Replace.  Therefore, Just Return.
             {
                #ifdef MYDEBUG
                _ftprintf(fp,_T("  Got In Where Parameter Is Same As Memory, So Just Return.\n"));
                #endif
                return S_OK;
             }
             else
             {
                #ifdef MYDEBUG
                _ftprintf(fp,_T("  Got In Where We'll Allocate Memory And Copy Parameter To it.\n"));
                #endif
                HeapFree(hHeap,0,pGridData->pGridMemory[iIndex]);
                pGridData->pGridMemory[iIndex]=(TCHAR*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,(SysStringLen(strData)*sizeof(TCHAR))+sizeof(TCHAR));
                if(pGridData->pGridMemory[iIndex])
                   _tcscpy(pGridData->pGridMemory[iIndex],strData);
                else
                   return S_FALSE;
             }
          }
       }
       else
          return S_FALSE;
    }
    else
       return S_FALSE;
 }
 else
    return S_FALSE;
 #ifdef MYDEBUG
 _ftprintf(fp,_T("Leaving FHGrid::SetData()\n\n"));
 #endif

 return S_OK;
}


HRESULT STDMETHODCALLTYPE FHGrid::GetData(int iRow, int iCol, BSTR* strData)
{
 #ifdef MYDEBUG
 printf("Called FHGrid::GetData()\n");
 #endif
 GridData* pGridData=(GridData*)GetWindowLongPtr(this->hWndCtrl,0);
 if(pGridData)
 {
    if(iRow<=pGridData->iRows && iRow>0 && iCol<=pGridData->iCols && iCol>0)
    {
       int iIndex=dwIdx(iRow,iCol);
       SysReAllocString(strData,pGridData->pGridMemory[iIndex]);
       return S_OK;
    }
 }

 return E_FAIL;
}


HRESULT STDMETHODCALLTYPE FHGrid::FlushData()
{
 GridData* pGridData=NULL;
 HWND hGrid;

 #ifdef MYDEBUG
 printf("Called FHGrid::FlushData()\n");
 _ftprintf(fp,_T("  Entering FHGrid::FlushData()\n"));
 #endif
 hGrid=this->hWndCtrl;
 pGridData=(GridData*)GetWindowLongPtr(hGrid,0);
 #ifdef MYDEBUG
 _ftprintf(fp,_T("    hGrid     = %u\n"),hGrid);
 _ftprintf(fp,_T("    pGridData = %u\n"),pGridData);
 #endif
 if(pGridData->hCtrlInCell)
 {
    #ifdef MYDEBUG
    _ftprintf(fp,_T("    Got In Where pGridData->hCtrlInCell = TRUE!\n"));
    #endif
    int iLen=GetWindowTextLength(pGridData->hCtrlInCell);
    HANDLE hHeap=GetProcessHeap();
    TCHAR* pZStr=(TCHAR*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,(iLen+1)*sizeof(TCHAR));
    if(pZStr)
    {
       GetWindowText(pGridData->hCtrlInCell,pZStr,iLen+1);
       BSTR strData=SysAllocString(pZStr);
       this->SetData(pGridData->iEditedRow,pGridData->iEditedCol,strData);
       SetWindowLongPtr(pGridData->hCtrlInCell,GWLP_WNDPROC,(LONG_PTR)fnEditWndProc);
       SetParent(pGridData->hCtrlInCell,hGrid);
       SetWindowPos(pGridData->hCtrlInCell,HWND_BOTTOM,0,0,0,0,SWP_HIDEWINDOW);
       pGridData->hCtrlInCell=0;
       this->Refresh();
    }
    else
    {
       return E_FAIL;
    }
 }
 #ifdef MYDEBUG
 _ftprintf(fp,_T("  Leaving FHGrid::FlushData()\n"));;
 #endif


 return S_OK;
}


HRESULT STDMETHODCALLTYPE FHGrid::Refresh()
{
 int iRows,iCols,iCountCells,iReturn,iIdx;
 GridData* pGridData=NULL;
 TCHAR* pText=NULL;
 SCROLLINFO si;

 #ifdef MYDEBUG
 printf("Called FHGrid::Refresh()\n");
 _ftprintf(fp,_T("Entering FHGrid::Refresh()\n"));
 #endif
 pGridData=(GridData*)GetWindowLongPtr(this->hWndCtrl,0);
 #ifdef MYDEBUG
 _ftprintf(fp,_T("  pGridData    = %u\n"),pGridData);
 #endif
 if(pGridData)
 {
    iRows       = pGridData->iVisibleRows;
    iCols       = pGridData->iCols;
    iCountCells =iRows*iCols;
    si.cbSize   = sizeof(SCROLLINFO);
    si.fMask    = SIF_POS;
    iReturn     = GetScrollInfo(this->hWndCtrl,SB_VERT,&si);
    #ifdef MYDEBUG
    _ftprintf(fp,_T("  iReturn                 = %d\n"),iReturn);
    _ftprintf(fp,_T("  pGridData->iVisibleRows = %d\n"),pGridData->iVisibleRows);
    _ftprintf(fp,_T("  pGridData->iCols        = %d\n"),pGridData->iCols);
    _ftprintf(fp,_T("  iCountCells             = %d\n"),iCountCells);
    _ftprintf(fp,_T("  si.nPos                 = %d\n\n"),si.nPos);
    _ftprintf(fp,_T("  i    pGridData->pCellHandles[i]  pGridData->pGridMemory[i]    pText   pGridData->pBackColor[iIdx]  pGridData->pTextColor[iIdx]\n"));
    _ftprintf(fp,_T("  ==============================================================================================================================\n"));
    #endif
    if(iReturn)
    {
       for(int i=0; i<iCountCells; i++)
       {
           iIdx=iCols*(si.nPos-1)+i;
           SetWindowLongPtr(pGridData->pCellHandles[i],0,(LONG_PTR)pGridData->pGridMemory[iIdx]);
           SetWindowLongPtr(pGridData->pCellHandles[i],2*sizeof(void*),(LONG_PTR)pGridData->pTextColor[iIdx]);
           SetWindowLongPtr(pGridData->pCellHandles[i],3*sizeof(void*),(LONG_PTR)pGridData->pBackColor[iIdx]);
           InvalidateRect(pGridData->pCellHandles[i],NULL, TRUE);
           pText=(TCHAR*)pGridData->pGridMemory[i];
           #ifdef MYDEBUG
           _ftprintf
           (
             fp,
             _T("  %d\t\t%u\t\t\t%u\t\t\t%s\t\t\t0x%x\t\t\t0x%x\n"),
             i,pGridData->pCellHandles[i],pGridData->pGridMemory[i],pText,pGridData->pBackColor[iIdx],pGridData->pTextColor[iIdx]
           );
           #endif
       }
    }
 }
 #ifdef MYDEBUG
 _ftprintf(fp,_T("Leaving FHGrid::Refresh()\n"));
 #endif

 return S_OK;
}


HRESULT STDMETHODCALLTYPE FHGrid::GetVisibleRows(int* iVisibleRows)
{
 GridData* pGridData=(GridData*)GetWindowLongPtr(this->hWndCtrl,0);
 if(pGridData)
 {
    *iVisibleRows=pGridData->iVisibleRows;
    return S_OK;
 }

 return E_FAIL;
}



HRESULT STDMETHODCALLTYPE FHGrid::GethGrid(HWND* hWnd)
{
 GridData* pGridData=(GridData*)GetWindowLongPtr(this->hWndCtrl,0);
 if(pGridData)
 {
    *hWnd=pGridData->hGrid;
    return S_OK;
 }

 return E_FAIL;
}


HRESULT STDMETHODCALLTYPE FHGrid::GethCell(int iRow, int iCol, HWND* hCell)
{
 GridData* pGridData=(GridData*)GetWindowLongPtr(this->hWndCtrl,0);
 if(pGridData)
 {
    if(iRow<=pGridData->iRows && iRow)
    {
       if(iCol<=pGridData->iCols && iCol)
       {
          int iIndex=dwIdx(iRow,iCol);
          *hCell=pGridData->pCellHandles[iIndex];
          return S_OK;
       }
    }
 }

 return E_FAIL;
}


HRESULT STDMETHODCALLTYPE FHGrid::GethComboBox(int iCol, HWND* hCombo)
{
 #ifdef MYDEBUG
 _ftprintf(fp,_T("Entering FHGrid::GethComboBox()\n"));
 #endif
 GridData* pGridData=(GridData*)GetWindowLongPtr(this->hWndCtrl,0);
 if(pGridData->pCellCtrlTypes[iCol-1]==GRID_CELL_CTRL_COMBO)
    *hCombo=(HWND)pGridData->pCtrlHdls[iCol-1];
 else
    return E_FAIL;
 #ifdef MYDEBUG
 _ftprintf(fp,_T("  *hCombo = %u\n"),*hCombo);
 _ftprintf(fp,_T("Leaving FHGrid::GethComboBox()\n\n"));
 #endif

 return S_OK;
}


HRESULT STDMETHODCALLTYPE FHGrid::SetCellAttributes(int iRow, int iCol, COLORREF iBackColor, COLORREF iTextColor)
{
 int iIdx=0,i=0,blnFound=0;
 GridData* pGridData=NULL;

 #if defined MYDEBUG
 printf("Called FHGrid::SetCellAttributes()\n");
 _ftprintf(fp,_T("  Entering FHGrid::SetCellAttributes()\n"));
 _ftprintf(fp,_T("    iRow       = %u\n"),iRow);
 _ftprintf(fp,_T("    iCol       = %u\n"),iCol);
 _ftprintf(fp,_T("    iBackColor = 0x%x\n"),iBackColor);
 _ftprintf(fp,_T("    iTextColor = 0x%x\n"),iTextColor);
 #endif
 pGridData=(GridData*)GetWindowLongPtr(this->hWndCtrl,0);
 if(iRow && iCol)
 {
    #if defined MYDEBUG
    _ftprintf(fp,_T("    Got In Where iRow And iCol Are Both Something!\n"));
    #endif
    iIdx=dwIdx(iRow,iCol);
    pGridData->pTextColor[iIdx] = iTextColor;
    #if defined MYDEBUG
    _ftprintf(fp,_T("    iIdx       = %u\n"),iIdx);
    #endif
 }
 else
 {
    #if defined MYDEBUG
    _ftprintf(fp,_T("    Got In Where Either iRow Or iCol Ain't Shit!\n"));
    #endif
 }
 #if defined MYDEBUG
 _ftprintf(fp,_T("    pGridData->iCols               = %d\n"),pGridData->iCols);
 _ftprintf(fp,_T("    iIdx                           = %u\n"),iIdx);
 _ftprintf(fp,_T("    pGridData->pTextColor          = %d\n"),pGridData->pTextColor);
 _ftprintf(fp,_T("    pGridData->pTextColor[iIdx]    = 0x%x\n"),pGridData->pTextColor[iIdx]);
 _ftprintf(fp,_T("    pGridData->pCellHandles[iIdx]  = %u\n"),pGridData->pCellHandles[iIdx]);
 _ftprintf(fp,_T("    pGridData->pCreatedColors[0]   = %u\n"),pGridData->pCreatedColors[0]);
 _ftprintf(fp,_T("    pGridData->pCreatedBrushes[0]  = %u\n\n"),pGridData->pCreatedBrushes[0]);
 _ftprintf(fp,_T("    i          pGridData->pCreatedColors[i]            iBackColor\n"));
 _ftprintf(fp,_T("    =============================================================\n"));
 #endif
 //pGridMemory                         As Dword Ptr  'Will be storing ZStr Ptrs here.  We need a
 //pTextColor                          As Dword Ptr  'Will be storing RGB values here, i.e., %Red, %Blue, etc
 //pBackColor                          As Dword Ptr  'Will be storing HBRUSHs here.  May be zero for default brush.
 //pCreatedColors                      As Dword Ptr  'Colors so far asked for by user per grid instance, e.g., %Red, %Yellow, %Blue, etc.
 //pCreatedBrushes                     As Dword Ptr  'Will be storing created HBRUSHs here.  Accumulate them. Numbers such as &HA0556789
 for(i=1; i<=pGridData->pCreatedColors[0]; i++)
 {
     #if defined MYDEBUG
     _ftprintf(fp,_T("    %d\t\t0x%x\t\t0x%x\n"),i,pGridData->pCreatedColors[i],iBackColor);
     #endif
     if(pGridData->pCreatedColors[i]==iBackColor)
     {
        blnFound=TRUE;
        break;
     }
 }
 #if defined MYDEBUG
 _ftprintf(fp,_T("    blnFound = %d\n"),blnFound);
 _ftprintf(fp,_T("    i        = %d\n"),i);
 #endif
 if(blnFound)  // Color Was Already Created
 {
    if(iRow && iCol)
    {
       pGridData->pBackColor[iIdx]=pGridData->pCreatedBrushes[i];
    }
    #if defined MYDEBUG
    _ftprintf(fp,_T("\n"));
    _ftprintf(fp,_T("    Got In Where blnFound = %True!\n"));
    _ftprintf(fp,_T("    pGridData->pCreatedBrushes[i] = 0x%x\n"),pGridData->pCreatedBrushes[i]);
    #endif
 }
 else          // Need To Create Brush And Store It
 {
    #if defined MYDEBUG
    _ftprintf(fp,_T("\n"));
    _ftprintf(fp,_T("    Got In Where blnFound = False!\n"));
    _ftprintf(fp,_T("    pGridData->pCreatedBrushes[0] = %d   << Before\n"),pGridData->pCreatedBrushes[0]);
    #endif
    if((int)pGridData->pCreatedBrushes[0]<MAX_COLORS)  // Test to see if pGridData->pCreatedBrushes[0]
    {                                                  // is less than 15, i.e., %MAX_COLORS
        int iCreatedBrushes=(int)pGridData->pCreatedBrushes[0];
        iCreatedBrushes++;
        pGridData->pCreatedBrushes[0]=(HBRUSH)iCreatedBrushes;
        int iCreatedColors=(int)pGridData->pCreatedColors[0];
        iCreatedColors++;
        pGridData->pCreatedColors[0]=(COLORREF)iCreatedColors;
        #if defined MYDEBUG
        _ftprintf(fp,_T("    pGridData->pCreatedColors[0] = %d\n"),pGridData->pCreatedColors[0]);
        _ftprintf(fp,_T("    Will Be Able To Create Another Brush!\n"));
        #endif
     }
     else
     {
        #if defined MYDEBUG
        _ftprintf(fp,_T("    Can't Create Another Brush!\n"));
        _ftprintf(fp,_T("  Leaving IGrid_SetCellAttributes()\n"));
        #endif
        return E_FAIL;                                // We've already created 15 brushes (Or Whatever MAX_COLORS Is).
     }
     #if defined MYDEBUG
     _ftprintf(fp,_T("    pGridData->pCreatedBrushes[0] = %d   << After\n"),pGridData->pCreatedBrushes[0]);
     #endif
     pGridData->pCreatedBrushes[(int)pGridData->pCreatedBrushes[0]] = CreateSolidBrush(iBackColor);
     pGridData->pCreatedColors[pGridData->pCreatedColors[0]]   = iBackColor;
     #if defined MYDEBUG
     _ftprintf(fp,_T("    pGridData->pCreatedBrushes[(int)pGridData->pCreatedBrushes[0]] = 0x%x\n"),pGridData->pCreatedBrushes[(int)pGridData->pCreatedBrushes[0]]);
     #endif
     if(iRow && iCol)
     {
        pGridData->pBackColor[iIdx] = pGridData->pCreatedBrushes[(int)pGridData->pCreatedBrushes[0]];
        #if defined MYDEBUG
        _ftprintf(fp,_T("    Have Just Assigned A Newly Created Brush To pBackColor[] At correct Location\n"));
        _ftprintf(fp,_T("    pGridData->pBackColor[iIdx] = 0x%x\n"),pGridData->pBackColor[iIdx]);
        #endif
     }
 }
 #if defined MYDEBUG
 _ftprintf(fp,_T("  Leaving FHGrid::SetCellAttributes()\n\n"));
 #endif

 return S_OK;
}


HRESULT STDMETHODCALLTYPE FHGrid::DeleteRow(int iRow)
{
 #if defined MYDEBUG
 _ftprintf(fp,_T("Entering FHGrid::DeleteRow()\n"));
 #endif
 GridData* pGridData=(GridData*)GetWindowLongPtr(this->hWndCtrl,0);
 int iSize=(pGridData->iRows-1)*pGridData->iCols-1;
 int iStart=dwIdx(iRow,1);
 int iCols=pGridData->iCols;
 for(int i=iStart; i<=iSize; i++)
 {
     pGridData->pGridMemory[i] = pGridData->pGridMemory[i+iCols];
     pGridData->pTextColor[i]  = pGridData->pTextColor[i+iCols];
     pGridData->pBackColor[i]  = pGridData->pBackColor[i+iCols];
 }
 iStart=dwIdx(pGridData->iRows,1);
 for(int i=iStart; i<iStart+iCols; i++)
 {
     pGridData->pGridMemory[i] = 0;
     pGridData->pTextColor[i]  = 0;
     pGridData->pBackColor[i]  = 0;
 }
 for(int i=1; i<=iCols; i++)
     pGridData->pComObj->SetCellAttributes(iRow,i,pGridData->iSelectionBackColor,pGridData->iSelectionTextColor);
 #if defined MYDEBUG
 _ftprintf(fp,_T("Leaving FHGrid::DeleteRow()\n"));
 #endif

 return S_OK;
}


HRESULT FHGrid::EnumConnectionPoints(IEnumConnectionPoints** ppEnum)
{
 #ifdef MYDEBUG
 printf("Called FHGrid::EnumConnectionPoints()\n");
 #endif
 return E_NOTIMPL;
}


HRESULT FHGrid::FindConnectionPoint(REFIID riid, IConnectionPoint** ppCP)
{
 #ifdef MYDEBUG
 printf("Entering FHGrid::FindConnectionPoint()\n");
 printf("  this  = %u\n",this);
 printf("  *ppCP = %u\n",*ppCP);
 #endif
 HRESULT hr=this->QueryInterface(IID_IConnectionPoint,(void**)ppCP);
 if(SUCCEEDED(hr))
 {
    #ifdef MYDEBUG
    printf("  QueryInterface(IID_IConnectionPoint) Succeeded!\n");
    printf("  *ppCP = %u\n",*ppCP);
    printf("Leaving FHGrid::FindConnectionPoint()\n");
    #endif
    return hr;
 }
 else
 {
    #ifdef MYDEBUG
    printf("  QueryInterface(IID_IConnectionPoint) Failed!\n");
    printf("Leaving FHGrid::FindConnectionPoint()\n");
    #endif
    return E_NOINTERFACE;
 }
}


HRESULT FHGrid::GetConnectionInterface(IID* pIID)
{
 return E_NOTIMPL;
}


HRESULT FHGrid::GetConnectionPointContainer(IConnectionPointContainer** ppCPC)
{
 return E_NOTIMPL;
}


HRESULT FHGrid::Advise(IUnknown* pUnkSink, DWORD* pdwCookie)
{
 int blnFoundOpenSlot=FALSE,i;

 #ifdef MYDEBUG
 printf("  Entering FHGrid::Advise()\n");
 printf("    this     = %u\n",this);
 printf("    pUnkSink = %u\n\n",pUnkSink);
 printf("    i   &this->pISink[i]     this->pISink[i]\n");
 printf("    ===========================================\n");
 #endif
 for(i=0; i<MAX_CONNECTIONS; i++)
 {
     #ifdef MYDEBUG
     printf("    %d\t%u\t\t\t\t%d\n",i,&this->pISink[i],this->pISink[i]);
     #endif
     if(this->pISink[i]==0)
     {
        blnFoundOpenSlot=TRUE;
        break;
     }
 }
 if(blnFoundOpenSlot)
 {
    HRESULT hr=pUnkSink->QueryInterface(IID_IFHGridEvents,(void**)&this->pISink[i]);
    if(SUCCEEDED(hr))
    {
       #ifdef MYDEBUG
       printf("    i               = %d\n",i);
       printf("    pUnkSink->QueryInterface() For Client Sink Succeeded!\n");
       printf("    this->pISink[i] = %u\n",this->pISink[i]);
       printf("  Leaving FHGrid::Advise()\n");
       #endif
       *pdwCookie=(DWORD)i;
       return S_OK;
    }
    else
    {
       #ifdef MYDEBUG
       printf("    pUnkSink->QueryInterface() For Client Sink Failed!\n");
       #endif
    }
 }
 else
 {
    #ifdef MYDEBUG
    printf("    Couldn't Find An Open Slot To Store Connection!\n");
    #endif
 }
 #ifdef MYDEBUG
 printf("  Leaving FHGrid::Advise()\n");
 #endif

 return E_FAIL;
}


HRESULT FHGrid::Unadvise(DWORD dwCookie)
{
 #ifdef MYDEBUG
 printf("Entering FHGrid::Unadvise()\n");
 printf("  dwCookie = %u\n",dwCookie);
 #endif
 IUnknown* pIUnknown=this->pISink[dwCookie];
 pIUnknown->Release();
 this->pISink[dwCookie]=0;
 #ifdef MYDEBUG
 printf("  pIUnknown = %u\n",pIUnknown);
 printf("Leaving FHGrid::Unadvise()\n");
 #endif

 return NOERROR;
}


HRESULT FHGrid::EnumConnections(IEnumConnections** ppEnum)
{
 return E_NOTIMPL;
}


FHGrid::~FHGrid()  //C++ Destructor for class FHGrid
{
 #if defined MYDEBUG
 printf("  Entering FHGrid Destructor!\n");
 printf("    g_lObjs = %d\n", g_lObjs);
 #endif
 InterlockedDecrement(&g_lObjs);
 #if defined MYDEBUG
 printf("    g_lObjs = %d\n", g_lObjs);
 printf("  Leaving FHGrid Destructor!\n");
 #endif
}

// Grid Class Factory
GridClassFactory::GridClassFactory()
{
 #if defined MYDEBUG
 printf("    Entering GridClassFactory Constructor!\n");
 #endif
 m_lRef=0;
 #if defined MYDEBUG
 printf("      this->m_lRef = %d\n", this->m_lRef);
 #endif
 #if defined MYDEBUG
 printf("    Leaving GridClassFactory Constructor!\n");
 #endif
}


GridClassFactory::~GridClassFactory()  //GridClassFactory Destructor
{
 #if defined MYDEBUG
 printf("  Entering GridClassFactory Destructor!\n");
 #endif
 #if defined MYDEBUG
 printf("    this->m_lRef = %d\n", this->m_lRef);
 #endif
 #if defined MYDEBUG
 printf("  Leaving GridClassFactory Destructor!\n");
 #endif
}


HRESULT STDMETHODCALLTYPE GridClassFactory::QueryInterface(REFIID riid, void** ppv)
{
 printf("    Entering GridClassFactory::QueryInterface()\n");
 *ppv=0;
 if(riid==IID_IUnknown || riid==IID_IClassFactory)
    *ppv=this;
 #if defined MYDEBUG
 printf("      *ppv = %u\n", *ppv);
 #endif
 if(*ppv)
 {
    AddRef();
    printf("    Leaving GridClassFactory::QueryInterface()\n");
    return S_OK;
 }

 return E_NOINTERFACE;
}


ULONG STDMETHODCALLTYPE GridClassFactory::AddRef()
{
 #if defined MYDEBUG
 printf("      Entering GridClassFactory::AddRef()!\n");
 printf("        this->m_lRef = %d\n", this->m_lRef);
 #endif
 InterlockedIncrement(&m_lRef);
 #if defined MYDEBUG
 printf("        this->m_lRef = %d\n", this->m_lRef);
 printf("      Leaving GridClassFactory::AddRef()!\n");
 #endif

 return this->m_lRef;
}


ULONG STDMETHODCALLTYPE GridClassFactory::Release()
{
 #if defined MYDEBUG
 printf("  Entering GridClassFactory::Release()!\n");
 printf("    this->m_lRef = %d\n", this->m_lRef);
 #endif
 InterlockedDecrement(&m_lRef);
 if(this->m_lRef==0)
 {
    printf("    this->m_lRef = %d\n", this->m_lRef);
    delete this;
    #if defined MYDEBUG
    printf("    GridClassFactory Has Been Destroyed!\n");
    printf("  Leaving GridClassFactory::Release()!\n");
    #endif
    return 0;
 }
 #if defined MYDEBUG
 printf("    this->m_lRef = %d\n", this->m_lRef);
 printf("  Leaving GridClassFactory::Release()!\n");
 #endif

 return m_lRef;
}


HRESULT STDMETHODCALLTYPE GridClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
{
 FHGrid* pGrid=NULL;
 HRESULT hr;

 #if defined MYDEBUG
 printf("  Entering GridClassFactory::CreateInstance()\n");
 #endif
 *ppvObj=0;
 pGrid=new FHGrid;
 #if defined MYDEBUG
 printf("    pGrid          = %u\n",pGrid);
 printf("    sizeof(*pGrid) = %d\n",sizeof(*pGrid));
 #endif
 if(pGrid==NULL)
    return E_OUTOFMEMORY;
 hr=pGrid->QueryInterface(riid,ppvObj);
 if(FAILED(hr))
    delete pGrid;
 else
 {
    pGrid->pISink=(IGridEvents**)CoTaskMemAlloc(MAX_CONNECTIONS*sizeof(void*));
    #if defined MYDEBUG
    printf("    pGrid->pISink = %u\n",pGrid->pISink);
    printf("    pGrid->pISink[0] = %u\n",pGrid->pISink[0]);
    printf("    pGrid->pISink[1] = %u\n",pGrid->pISink[1]);
    printf("    pGrid->pISink[2] = %u\n",pGrid->pISink[2]);
    printf("    pGrid->pISink[3] = %u\n",pGrid->pISink[3]);
    #endif
    if(pGrid->pISink==NULL)
       return E_OUTOFMEMORY;
    else
    {
       pGrid->pISink[0]=(IGridEvents*)0;
       pGrid->pISink[1]=(IGridEvents*)NULL;
       pGrid->pISink[2]=(IGridEvents*)NULL;
       pGrid->pISink[3]=(IGridEvents*)NULL;
       #if defined MYDEBUG
       printf("    pGrid->pISink = %u\n",pGrid->pISink);
       printf("    pGrid->pISink[0] = %u\n",pGrid->pISink[0]);
       printf("    pGrid->pISink[1] = %u\n",pGrid->pISink[1]);
       printf("    pGrid->pISink[2] = %u\n",pGrid->pISink[2]);
       printf("    pGrid->pISink[3] = %u\n",pGrid->pISink[3]);
       #endif
    }
 }
 #if defined MYDEBUG
 printf("  Leaving GridClassFactory::CreateInstance()\n");
 #endif

 return hr;
}


HRESULT STDMETHODCALLTYPE GridClassFactory::LockServer(BOOL fLock)
{
 if(fLock)
    InterlockedIncrement(&g_lLocks);
 else
    InterlockedDecrement(&g_lLocks);

 return S_OK;
}


void Initialize()
{
 INITCOMMONCONTROLSEX uCC;
 TCHAR szClassName[16];
 short int iRet=0;
 WNDCLASSEX wc;

 #if defined MYDEBUG
 printf("    Entering Initialize()\n");
 #endif

 uCC.dwSize = sizeof(uCC);             // Initialize Common Controls (need header control).
 uCC.dwICC  = ICC_LISTVIEW_CLASSES;
 InitCommonControlsEx(&uCC);

 _tcscpy(szClassName,_T("Grid"));      // Register Grid Class
 wc.lpszClassName  = szClassName;
 wc.lpfnWndProc    = fnGridProc;
 wc.cbSize         = sizeof(wc);
 wc.style          = 0;
 wc.cbClsExtra     = 0;
 wc.cbWndExtra     = sizeof(void*);
 wc.hInstance      = g_hModule;
 wc.hIcon          = LoadIcon(NULL,IDI_APPLICATION);
 wc.hCursor        = LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground  = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
 wc.lpszMenuName   = NULL;
 wc.hIconSm        = NULL;
 iRet              = RegisterClassEx(&wc);
 #if defined MYDEBUG
 printf("      RegisterClassEx(Grid) = %d\n",iRet);
 #endif

 _tcscpy(szClassName,_T("Pane"));      // Register Pane Class
 wc.lpszClassName  = szClassName;
 wc.lpfnWndProc    = fnPaneProc;
 wc.cbSize         = sizeof(wc);
 wc.style          = 0;
 wc.cbClsExtra     = 0;
 wc.cbWndExtra     = sizeof(void*);
 wc.hInstance      = g_hModule;
 wc.hIcon          = LoadIcon(NULL,IDI_APPLICATION);
 wc.hCursor        = LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);
 wc.lpszMenuName   = NULL;
 wc.hIconSm        = NULL;
 iRet              = RegisterClassEx(&wc);
 #if defined MYDEBUG
 printf("      RegisterClassEx(Pane) = %d\n",iRet);
 #endif

 _tcscpy(szClassName,_T("Base"));      // Register Pane Class
 wc.lpszClassName  = szClassName;
 wc.lpfnWndProc    = fnBaseProc;
 wc.cbSize         = sizeof(wc);
 wc.style          = 0;
 wc.cbClsExtra     = 0;
 wc.cbWndExtra     = 0;
 wc.hInstance      = g_hModule;
 wc.hIcon          = LoadIcon(NULL,IDI_APPLICATION);
 wc.hCursor        = LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground  = (HBRUSH)GetStockObject(GRAY_BRUSH);
 wc.lpszMenuName   = NULL;
 wc.hIconSm        = NULL;
 iRet              = RegisterClassEx(&wc);
 #if defined MYDEBUG
 printf("      RegisterClassEx(Pane) = %d\n",iRet);
 #endif

 _tcscpy(szClassName,_T("Cell"));      // Register Cell Class
 wc.lpszClassName  = szClassName;
 wc.lpfnWndProc    = fnCellProc;
 wc.cbSize         = sizeof(wc);
 wc.style          = 0;
 wc.cbClsExtra     = 0;
 wc.cbWndExtra     = 4*sizeof(void*);
 wc.hInstance      = g_hModule;
 wc.hIcon          = LoadIcon(NULL,IDI_APPLICATION);
 wc.hCursor        = LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);
 wc.lpszMenuName   = NULL;
 wc.hIconSm        = NULL;
 iRet              = RegisterClassEx(&wc);
 #if defined MYDEBUG
 printf("      RegisterClassEx(Cell) = %d\n",iRet);
 printf("    Leaving Initialize()\n");
 #endif
}
//End Grid.cpp


--- End code ---

Frederick J. Harris:
WinCode.cpp will have to be broken up.  I'll try 1st half ...


--- Code: ---#define  UNICODE
#define  _UNICODE
#include <windows.h>
#include <commctrl.h>
#include <objbase.h>
#include <ocidl.h>
#include <olectl.h>
#include <cstdio>
#include <tchar.h>
#include "Strings.h"
#include "Grid.h"
#include "WinCode.h"
//#define MYDEBUG
#if defined MYDEBUG
extern   FILE* fp;
#endif
WNDPROC  fnEditWndProc;  // edit control subclass


long fnGridProc_OnCreate(lpWndEventArgs Wea)
{
 int iEndRectHt,iHalf,iRemainder,iDifference,iNewGridHt;
 int iCols=0,iFlds=0,iHdlCount=0,iCtr=0,iSize=0;
 CREATESTRUCT* pCreateStruct=NULL;
 GridData* pGridData1=NULL;
 GridData* pGridData2=NULL;
 String* strParseData;
 HANDLE hHeap=NULL;
 TCHAR szText[64];
 String strSetup;
 HDITEM hdrItem;
 DWORD dwStyle;
 HWND hCell;
 HDC hDC;
 RECT rc;

 #if defined MYDEBUG
 _ftprintf(fp,_T("  Entering fnGridProc_OnCreate()\n"));
 #endif
 pCreateStruct=(CREATESTRUCT*)Wea->lParam;
 Wea->hIns=pCreateStruct->hInstance;
 pGridData1=(GridData*)pCreateStruct->lpCreateParams;
 strSetup=(TCHAR*)pCreateStruct->lpszName;
 #if defined MYDEBUG
 _ftprintf(fp,_T("    Wea->hWnd                  = %u\n"),Wea->hWnd);
 _ftprintf(fp,_T("    pCreateStruct              = %u\n"),pCreateStruct);
 _ftprintf(fp,_T("    pGridData1                 = %u\n"),pGridData1);
 _ftprintf(fp,_T("    strSetup.lpStr()           = %s\n"),strSetup.lpStr());
 _ftprintf(fp,_T("    pCreateStruct->hwndParent  = %u\n"),pCreateStruct->hwndParent);
 _ftprintf(fp,_T("    pCreateStruct->x           = %d\n"),pCreateStruct->x);
 _ftprintf(fp,_T("    pCreateStruct->y           = %d\n"),pCreateStruct->y);
 _ftprintf(fp,_T("    pCreateStruct->cx          = %d\n"),pCreateStruct->cx);
 _ftprintf(fp,_T("    pCreateStruct->cy          = %d\n"),pCreateStruct->cy);
 _ftprintf(fp,_T("    pCreateStruct->hMenu       = %u\n"),pCreateStruct->hMenu);
 _ftprintf(fp,_T("    pGridData1->cx             = %d\n"),pGridData1->cx);
 _ftprintf(fp,_T("    pGridData1->iRows          = %d\n"),pGridData1->iRows);
 _ftprintf(fp,_T("    pGridData1->iCols          = %d\n"),pGridData1->iCols);
 _ftprintf(fp,_T("    pGridData1->iRowHeight     = %d\n"),pGridData1->iRowHeight);
 _ftprintf(fp,_T("    pGridData1->szFontName     = %s\n"),pGridData1->szFontName);
 _ftprintf(fp,_T("    pGridData1->iFontSize      = %d\n"),pGridData1->iFontSize);
 _ftprintf(fp,_T("    pGridData1->iFontWeight    = %d\n"),pGridData1->iFontWeight);
 #endif
 pGridData1->hGrid=Wea->hWnd;
 GetClientRect(Wea->hWnd,&rc);
 iCols=strSetup.ParseCount(_T(','));
 #if defined MYDEBUG
 _ftprintf(fp,_T("    rc.left                    = %d\n"),rc.left);
 _ftprintf(fp,_T("    rc.top                     = %d\n"),rc.top);
 _ftprintf(fp,_T("    rc.right                   = %d\n"),rc.right);
 _ftprintf(fp,_T("    rc.bottom                  = %d\n"),rc.bottom);
 _ftprintf(fp,_T("    iCols                      = %d\n"),iCols);
 #endif
 if(iCols!=pGridData1->iCols)
    return -1;
 hHeap=GetProcessHeap();
 if(!hHeap)
    return -1;
 pGridData2=(GridData*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(GridData));
 if(!pGridData2)
    return -1;
 SetWindowLongPtr(Wea->hWnd,0,(LONG_PTR)pGridData2);
 pGridData1->blnRowSelected=FALSE;
 #if defined MYDEBUG
 _ftprintf(fp,_T("    pGridData2                 = %u\n"),pGridData2);
 #endif
 memcpy(pGridData2,pGridData1,sizeof(GridData));
 iNewGridHt=pCreateStruct->cy;
 iHalf=pGridData2->iRowHeight/2;
 iRemainder=rc.bottom % pGridData2->iRowHeight;
 #ifdef MYDEBUG
 _ftprintf(fp,_T("    iNewGridHt                 = %d\n"),iNewGridHt);
 _ftprintf(fp,_T("    pGridData2->iRowHeight     = %d\n"),pGridData2->iRowHeight);
 _ftprintf(fp,_T("    iHalf                      = %d\n"),iHalf);
 _ftprintf(fp,_T("    iRemainder                 = %d\n"),iRemainder);
 #endif
 if(iRemainder>=iHalf)
 {
    iDifference=pGridData2->iRowHeight-iRemainder;
    iEndRectHt=rc.bottom+(pGridData2->iRowHeight-iRemainder);
 }
 else
 {
    iDifference=-iRemainder;
    iEndRectHt=rc.bottom-iRemainder;
 }
 iNewGridHt=iNewGridHt+iDifference;
 #ifdef MYDEBUG
 _ftprintf(fp,_T("    iEndRectHt                 = %d\n"),iEndRectHt);
 _ftprintf(fp,_T("    iDifference                = %d\n"),iDifference);
 _ftprintf(fp,_T("    iNewGridHt                 = %d\n"),iNewGridHt);
 #endif
 pGridData2->iVisibleRows=(iEndRectHt-pGridData2->iRowHeight)/pGridData2->iRowHeight;
 if(pGridData2->iRows<pGridData2->iVisibleRows)
    pGridData2->iRows=pGridData2->iVisibleRows+1;
 pGridData2->iPaneHeight=(pGridData2->iVisibleRows+1)*pGridData2->iRowHeight;
 #if defined MYDEBUG
 _ftprintf(fp,_T("    pGridData2->hParent        = %u\n"),pGridData2->hParent);
 _ftprintf(fp,_T("    pGridData2->hGrid          = %u\n"),pGridData2->hGrid);
 _ftprintf(fp,_T("    pGridData2->iCtrlId        = %d\n"),pGridData2->iCtrlId);
 _ftprintf(fp,_T("    pGridData2->cx             = %u\n"),pGridData2->cx);
 _ftprintf(fp,_T("    pGridData2->cy             = %u\n"),pGridData2->cy);
 _ftprintf(fp,_T("    pGridData2->iRows          = %d\n"),pGridData2->iRows);
 _ftprintf(fp,_T("    pGridData2->iCols          = %d\n"),pGridData2->iCols);
 _ftprintf(fp,_T("    pGridData2->iRowHeight     = %d\n"),pGridData2->iRowHeight);
 _ftprintf(fp,_T("    pGridData2->szFontName     = %s\n"),pGridData2->szFontName);
 _ftprintf(fp,_T("    pGridData2->iFontSize      = %d\n"),pGridData2->iFontSize);
 _ftprintf(fp,_T("    pGridData2->iFontWeight    = %d\n"),pGridData2->iFontWeight);
 _ftprintf(fp,_T("    pGridData2->iVisibleRows   = %d\n"),pGridData2->iVisibleRows);
 _ftprintf(fp,_T("    pGridData2->iPaneHeight    = %d\n"),pGridData2->iPaneHeight);
 _ftprintf(fp,_T("    pGridData2->blnRowSelected = %d\n\n"),pGridData2->blnRowSelected);
 _ftprintf(fp,_T("    i         strParseData(i) \n"));
 _ftprintf(fp,_T("    ============================\n"));
 #endif
 strParseData=new String[iCols];
 strSetup.Parse(strParseData,_T(','));
 for(unsigned int i=0; i<iCols; i++)
 {
     strParseData[i].Trim();
     #if defined MYDEBUG
     _ftprintf(fp,_T("    %d\t%s\n"),i,strParseData[i].lpStr());
     #endif
 }
 pGridData2->pColWidths=(DWORD*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,sizeof(DWORD)*(iCols+1));
 if(!pGridData2->pColWidths)
    goto CleanUp;
 #if defined MYDEBUG
 _ftprintf(fp,_T("\n    pGridData2->pColWidths    = %u\n"),pGridData2->pColWidths);
 #endif
 pGridData2->hBase=CreateWindowEx(0,_T("Base"),_T(""),WS_CHILD|WS_VISIBLE,0,0,0,0,Wea->hWnd,(HMENU)1499,Wea->hIns,0);
 pGridData2->hPane=CreateWindowEx(0,_T("Pane"),_T(""),WS_CHILD|WS_VISIBLE,0,0,0,0,pGridData2->hBase,(HMENU)ID_PANE,Wea->hIns,0);
 dwStyle=WS_CHILD | WS_BORDER | WS_VISIBLE | HDS_HOTTRACK | HDS_HORZ;
 pGridData2->hHeader=CreateWindowEx(0,WC_HEADER,_T(""),dwStyle,0,0,0,0,pGridData2->hPane,(HMENU)ID_HEADER,Wea->hIns,0);
 #if defined MYDEBUG
 _ftprintf(fp,_T("    pGridData2->hBase         = %u\n"),pGridData2->hBase);
 _ftprintf(fp,_T("    pGridData2->hPane         = %u\n"),pGridData2->hPane);
 _ftprintf(fp,_T("    pGridData2->hHeader       = %u\n"),pGridData2->hHeader);
 _ftprintf(fp,_T("    HDF_LEFT                  = %d\n"),HDF_LEFT);
 _ftprintf(fp,_T("    HDF_CENTER                = %d\n"),HDF_CENTER);
 _ftprintf(fp,_T("    HDF_RIGHT                 = %d\n\n"),HDF_RIGHT);
 #endif
 SetWindowLongPtr(pGridData2->hPane,0,(LONG_PTR)pGridData2);
 pGridData2->pCellCtrlTypes=(DWORD*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iCols*sizeof(DWORD));    // no extra bytes allocated here, so its zero based
 if(!pGridData2->pCellCtrlTypes)
    goto CleanUp;
 pGridData2->pCtrlHdls=(HWND*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iCols*sizeof(HWND*));          // no extra bytes allocated here either, so its zero based
 if(!pGridData2->pCtrlHdls)
    goto CleanUp;
 hdrItem.mask=HDI_FORMAT | HDI_WIDTH | HDI_TEXT;
 #if defined MYDEBUG
 _ftprintf(fp,_T("    i\tstrFieldData[0]\tpGridData2->pColWidths[i]\tstrFieldData[1]\tstrFieldData[2]\tstrFieldData[3]\tpPos[i]\t\tpGridData2->pCellCtrlTypes[i]\n"));
 _ftprintf(fp,_T("    ============================================================================================================================================\n"));
 #endif
 int* pPos=(int*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iCols*sizeof(int));    // and no extra bytes allocated here
 if(!pPos)
    goto CleanUp;
 pGridData2->pColWidths[iCols]=0;
 for(unsigned int i=0; i<iCols; i++)
 {
     iFlds=strParseData[i].ParseCount(_T(':'));
     String* strFieldData=new String[iFlds];
     strParseData[i].Parse(strFieldData,_T(':'));
     pGridData2->pColWidths[i]=(DWORD)strFieldData[0].iVal();
     pGridData2->pColWidths[iCols]=pGridData2->pColWidths[iCols]+pGridData2->pColWidths[i];
     hdrItem.cxy=pGridData2->pColWidths[i];
     _tcscpy(szText,strFieldData[1].lpStr());   // here's the line that's crashing it!!!!!!!!!!!!!!!!!!!!
     hdrItem.pszText=szText;
     hdrItem.cchTextMax=_tcslen(szText);
     hdrItem.fmt=0;
     if(strFieldData[2]==_T("<"))
        hdrItem.fmt=HDF_LEFT;
     else
     {
        if(strFieldData[2]==_T("^"))
           hdrItem.fmt=HDF_CENTER;
        else
           hdrItem.fmt=HDF_RIGHT;
     }
     hdrItem.fmt=hdrItem.fmt|HDF_STRING;
     Header_InsertItem(pGridData2->hHeader,i,&hdrItem);
     if(i)
        pPos[i]=pPos[i-1]+pGridData2->pColWidths[i-1];
     if(strFieldData[3]==_T("none"))
        pGridData2->pCellCtrlTypes[i]=0;
     else
     {
        if(strFieldData[3]==_T("edit"))
           pGridData2->pCellCtrlTypes[i]=1;
        else
        {
           if(strFieldData[3]==_T("combo"))
              pGridData2->pCellCtrlTypes[i]=2;
           if(strFieldData[3]==_T("check"))
              pGridData2->pCellCtrlTypes[i]=0;
        }
     }
     #if defined MYDEBUG
     _ftprintf
     (
      fp,
      _T("    %d\t%s\t\t%u\t\t\t\t%s\t%s\t\t%s\t\t%d\t\t%u\n"),
      i,strFieldData[0].lpStr(),pGridData2->pColWidths[i],strFieldData[1].lpStr(),strFieldData[2].lpStr(),strFieldData[3].lpStr(),pPos[i],pGridData2->pCellCtrlTypes[i]
     );
     #endif
     delete [] strFieldData;
 }
 #if defined MYDEBUG
 _ftprintf(fp,_T("\n"));
 _ftprintf(fp,_T("    iCols = %u\n\n"),iCols);
 _ftprintf(fp,_T("    i\tpGridData2->pColWidths[i]\n"));
 _ftprintf(fp,_T("    ================================\n"));
 for(unsigned int i=0; i<=iCols; i++)
     _ftprintf(fp,_T("    %u\t\t%u\n"),i,pGridData2->pColWidths[i]);
 _ftprintf(fp,_T("\n"));
 _ftprintf(fp,_T("    i\tpGridData2->pCtrlHdls[i]\n"));
 _ftprintf(fp,_T("    ==================================\n"));
 #endif
 int blnEditCreated = 0;
 int iCboCtr        = 0;
 for(unsigned int i=0; i<iCols; i++)
 {
     // Edit Control In Column
     if(pGridData2->pCellCtrlTypes[i]==GRID_CELL_CTRL_EDIT)
     {
        if(blnEditCreated==FALSE)
        {
           dwStyle = WS_CHILD | ES_AUTOHSCROLL;
           pGridData2->pCtrlHdls[i]=CreateWindowEx(0,_T("edit"),_T(""),dwStyle,0,0,0,0,Wea->hWnd,(HMENU)IDC_EDIT,Wea->hIns,0);
           pGridData2->hCtrlInCell=pGridData2->pCtrlHdls[i];
           blnEditCreated=TRUE;
        }
        else
        {
           pGridData2->pCtrlHdls[i]=pGridData2->hCtrlInCell;
        }
     }

     // Combo Box In Column
     if(pGridData2->pCellCtrlTypes[i]==GRID_CELL_CTRL_COMBO)
     {
        dwStyle=WS_CHILD | CBS_DROPDOWNLIST | WS_VSCROLL; //Or %CBS_NOINTEGRALHEIGHT
        pGridData2->pCtrlHdls[i]=CreateWindowEx(0,_T("combobox"),_T(""),dwStyle,0,0,0,0,Wea->hWnd,(HMENU)(IDC_COMBO+iCboCtr),Wea->hIns,0);
        iCboCtr++;
     }

     #if defined MYDEBUG
     _ftprintf(fp,_T("    %u\t\t%u\n"),i,pGridData2->pCtrlHdls[i]);
     #endif
 }
 pGridData2->hCtrlInCell=0;    //    DANGER!!!!!! Addition!  I don't know why this needes to be initially set?

 #if defined MYDEBUG
 _ftprintf(fp,_T("\n"));
 _ftprintf(fp,_T("    pGridData2->pColWidths[iCols] = %d\n"),pGridData2->pColWidths[iCols]);
 _ftprintf(fp,_T("\n"));
 #endif

 MoveWindow(Wea->hWnd,pCreateStruct->x,pCreateStruct->y,pCreateStruct->cx,iNewGridHt,FALSE);
 MoveWindow(pGridData2->hBase,12,0,rc.right-12,pGridData2->iPaneHeight,FALSE);
 MoveWindow(pGridData2->hPane,0,0,pGridData2->pColWidths[iCols],pGridData2->iPaneHeight,FALSE);
 MoveWindow(pGridData2->hHeader,0,0,pGridData2->pColWidths[iCols],pGridData2->iRowHeight,TRUE);
 delete [] strParseData;
 pGridData2->pVButtons=(HWND*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,(pGridData2->iVisibleRows+1)*sizeof(void*));
 #if defined MYDEBUG
 _ftprintf(fp,_T("    pGridData2->pVButtons = %u\n\n"),pGridData2->pVButtons);
 _ftprintf(fp,_T("    i\tpGridData2->pVButtons[i]\n"));
 _ftprintf(fp,_T("    ===================================\n"));
 #endif
 if(!pGridData2->pVButtons)
    goto CleanUp;
 else
 {
    for(unsigned int i=0; i<=pGridData2->iVisibleRows; i++)
    {
        pGridData2->pVButtons[i]=CreateWindowEx(0,_T("button"),_T(""),WS_CHILD|WS_VISIBLE|BS_FLAT,0,pGridData2->iRowHeight*i,12,pGridData2->iRowHeight,Wea->hWnd,(HMENU)(20000+i),Wea->hIns,0);
        #if defined MYDEBUG
        _ftprintf(fp,_T("    %u\t%u\n"),i,pGridData2->pVButtons[i]);
        #endif

    }
 }

 // Now gonna try to create font ...
 #if defined MYDEBUG
 _ftprintf(fp,_T("\n    Now Gonna Try To Create Font...\n"));
 _ftprintf(fp,_T("    pGridData2->szFontName = %s\n"),pGridData2->szFontName);
 #endif
 if(pGridData2->szFontName)
 {
    hDC=GetDC(Wea->hWnd);
    pGridData2->hFont=CreateFont(-1*(pGridData2->iFontSize*GetDeviceCaps(hDC,LOGPIXELSY))/72,0,0,0,pGridData2->iFontWeight,0,0,0,ANSI_CHARSET,0,0,DEFAULT_QUALITY,0,pGridData2->szFontName);
    #if defined MYDEBUG
    _ftprintf(fp,_T("    pGridData2->hFont = %u\n\n"),pGridData2->hFont);
    #endif
    ReleaseDC(Wea->hWnd,hDC);
 }
 else
    goto CleanUp;

 iHdlCount=pGridData2->iCols*pGridData2->iVisibleRows;
 pGridData2->pCellHandles=(HWND*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iHdlCount*sizeof(void*));
 #if defined MYDEBUG
 _ftprintf(fp,_T("    iCols                    = %d\n"),iCols);
 _ftprintf(fp,_T("    pGridData2->iCols        = %u\n"),pGridData2->iCols);
 _ftprintf(fp,_T("    iHdlCount                = %d\n"),iHdlCount);
 _ftprintf(fp,_T("    pGridData2->pCellHandles = %u\n"),pGridData2->pCellHandles);
 #endif
 if(!pGridData2->pCellHandles)
    goto CleanUp;
 dwStyle=WS_CHILD | WS_VISIBLE | WS_BORDER;
 #if defined MYDEBUG
 _ftprintf(fp,_T("\n"));
 _ftprintf(fp,_T("    i\t\tj\tiPos(j)\tyLoc\thCell\n"));
 _ftprintf(fp,_T("    =============================================================\n"));
 #endif
 for(int i=0; i<pGridData2->iVisibleRows; i++)
 {
     for(int j=0; j<pGridData2->iCols; j++)
     {
         hCell=CreateWindowEx(0,_T("Cell"),_T(""),dwStyle,pPos[j],pGridData2->iRowHeight+(i*pGridData2->iRowHeight),pGridData2->pColWidths[j],pGridData2->iRowHeight,pGridData2->hPane,(HMENU)(ID_CELL+iCtr),Wea->hIns,0);
         pGridData2->pCellHandles[iCtr]=hCell;
         SetWindowLongPtr(hCell,sizeof(void*),(LONG_PTR)pGridData2->hFont);   // 4 for 32 bit; 8 for 64 bit
         #if defined MYDEBUG
         _ftprintf(fp,_T("    %d\t\t%d\t%u\t%d\t%u\n"),i,j,pPos[j],pGridData2->iRowHeight+(i*pGridData2->iRowHeight),hCell);
         #endif
         iCtr++;
     }
 }

 // grid memory
 iSize=pGridData2->iCols*pGridData2->iRows;
 pGridData2->pGridMemory=(TCHAR**)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iSize*sizeof(void*));
 if(!pGridData2->pGridMemory)
    goto CleanUp;
 pGridData2->pTextColor=(COLORREF*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iSize*sizeof(void*));
 if(!pGridData2->pTextColor)
    goto CleanUp;
 pGridData2->pBackColor=(HBRUSH*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,iSize*sizeof(void*));
 if(!pGridData2->pBackColor)
    goto CleanUp;
 pGridData2->pCreatedColors=(COLORREF*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,(MAX_COLORS+1)*sizeof(void*));
 if(!pGridData2->pCreatedColors)
    goto CleanUp;
 pGridData2->pCreatedBrushes=(HBRUSH*)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,(MAX_COLORS+1)*sizeof(void*));
 if(!pGridData2->pCreatedBrushes)
    goto CleanUp;
 #ifdef MYDEBUG
 _ftprintf(fp,_T("    iSize                   = %d\n"),iSize);
 _ftprintf(fp,_T("    pGridData2->pGridMemory = %u\n"),pGridData2->pGridMemory);
 #endif

 //Done
 if(pPos)
    HeapFree(hHeap,0,pPos);
 #if defined MYDEBUG
 _ftprintf(fp,_T("    Everything Allocated OK!\n"));
 _ftprintf(fp,_T("  Leaving fnGridProc_OnCreate()\n\n"));
 #endif
 return 0;

 CleanUp:
 if(pGridData2->pColWidths)
 {
    HeapFree(hHeap,0,pGridData2->pColWidths);
    pGridData2->pColWidths=NULL;
 }
 if(pGridData2->pCellCtrlTypes)
 {
    HeapFree(hHeap,0,pGridData2->pCellCtrlTypes);
    pGridData2->pCellCtrlTypes=NULL;
 }
 if(pGridData2->pCtrlHdls)
 {
    HeapFree(hHeap,0,pGridData2->pCtrlHdls);
    pGridData2->pCtrlHdls=NULL;
 }
 if(pPos)
    HeapFree(hHeap,0,pPos);
 if(pGridData2->pVButtons)
 {
    HeapFree(hHeap,0,pGridData2->pVButtons);
    pGridData2->pVButtons=NULL;
 }
 if(pGridData2->hFont)
    DeleteObject(pGridData2->hFont);
 if(pGridData2->pCellHandles)
    HeapFree(hHeap,0,pGridData2->pCellHandles);
 if(pGridData2->pGridMemory)
    HeapFree(hHeap,0,pGridData2->pGridMemory);
 if(pGridData2->pTextColor)
    HeapFree(hHeap,0,pGridData2->pTextColor);
 if(pGridData2->pBackColor)
    HeapFree(hHeap,0,pGridData2->pBackColor);
 if(pGridData2->pCreatedColors)
    HeapFree(hHeap,0,pGridData2->pCreatedColors);
 if(pGridData2->pCreatedBrushes)
    HeapFree(hHeap,0,pGridData2->pCreatedBrushes);
 #if defined MYDEBUG
 _ftprintf(fp,_T("  Leaving fnGridProc_OnCreate()\n\n"));
 #endif

 return 0;
}


long fnGridProc_OnSize(lpWndEventArgs Wea)
{
 GridData* pGridData=NULL;
 SCROLLINFO si;
 int iCols;

 #if defined MYDEBUG
 _ftprintf(fp,_T("  Entering fnGridProc_OnSize()\n"));
 _ftprintf(fp,_T("    Wea->hWnd = %u\n"),Wea->hWnd);
 #endif
 pGridData=(GridData*)GetWindowLongPtr(Wea->hWnd,0);
 iCols=pGridData->iCols;
 #ifdef MYDEBUG
 _ftprintf(fp,_T("    pGridData    = %u\n"),pGridData);
 _ftprintf(fp,_T("    iCols        = %d\n"),iCols);
 #endif

 //Set Up Horizontal Scrollbar
 ZeroMemory(&si, sizeof(SCROLLINFO));
 si.cbSize = sizeof(SCROLLINFO);
 si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_DISABLENOSCROLL;
 si.nMin   = 0;
 si.nMax   = pGridData->pColWidths[iCols];
 si.nPage  = pGridData->cx-33; // 33 is the width of vert
 si.nPos   = 0;                // btns + width scroll bar + window edge
 SetScrollInfo(Wea->hWnd,SB_HORZ,&si,TRUE);
 #ifdef MYDEBUG
 _ftprintf(fp,_T("    Horizontal Scrollbar....\n"));
 _ftprintf(fp,_T("    si.nMin    = %d\n"),si.nMin);
 _ftprintf(fp,_T("    si.nMax    = %d\n"),si.nMax);
 _ftprintf(fp,_T("    si.nPos    = %d\n"),si.nPos);
 #endif

 //Set Up Verticle Scrollbar
 ZeroMemory(&si, sizeof(SCROLLINFO));
 si.cbSize = sizeof(SCROLLINFO);
 si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
 si.nMin   = 1;
 si.nMax   = pGridData->iRows;
 si.nPage  = pGridData->iVisibleRows;
 si.nPos   = 1;
 SetScrollInfo(Wea->hWnd,SB_VERT,&si,TRUE);
 #ifdef MYDEBUG
 _ftprintf(fp,_T("    Verticle Scrollbar....\n"));
 _ftprintf(fp,_T("    si.nMin    = %d\n"), si.nMin);
 _ftprintf(fp,_T("    si.nMax    = %d\n"), si.nMax);
 _ftprintf(fp,_T("    si.nPos    = %d\n"), si.nPos);
 _ftprintf(fp,_T("    Leaving %WM_SIZE Case\n"));
 _ftprintf(fp,_T("  Leaving fnGridProc_OnSize()\n\n"));
 #endif

 return 0;
}


long fnGridProc_OnHScroll(lpWndEventArgs Wea)
{
 GridData* pGridData=NULL;
 int iCols,iScrollPos;
 SCROLLINFO si;

 #if defined MYDEBUG
 _ftprintf(fp,_T("Entering fnGridProc_OnHScroll()\n"));
 _ftprintf(fp,_T("  Wea->hWnd = %u\n"),Wea->hWnd);
 #endif
 ZeroMemory(&si, sizeof(SCROLLINFO));
 pGridData = (GridData*)GetWindowLongPtr(Wea->hWnd,0);
 iCols     = pGridData->iCols;
 si.cbSize = sizeof(SCROLLINFO);
 si.fMask  = SIF_ALL;
 GetScrollInfo(pGridData->hGrid,SB_HORZ,&si);
 iScrollPos=si.nPos;
 #ifdef MYDEBUG
 _ftprintf(fp,_T("    Before Adjustments\n"));
 _ftprintf(fp,_T("    si.nMin    = %d\n"), si.nMin);
 _ftprintf(fp,_T("    si.nMax    = %d\n"), si.nMax);
 _ftprintf(fp,_T("    si.nPos    = %d\n"), si.nPos);
 #endif
 switch(LOWORD(Wea->wParam))
 {
   case SB_LINELEFT:
     {
        if(si.nPos > si.nMin)
           si.nPos=si.nPos-50;
        break;
     }
   case SB_PAGELEFT:
     {
        si.nPos = si.nPos - si.nPage;
        break;
     }
   case SB_LINERIGHT:
     {
        if(si.nPos<si.nMax)
           si.nPos=si.nPos+50;
        break;
     }
   case SB_PAGERIGHT:
     {
        si.nPos = si.nPos + si.nPage;
        break;
     }
   case SB_THUMBTRACK:
     {
        si.nPos=si.nTrackPos;
        break;
     }
 }
 si.fMask = SIF_POS;
 SetScrollInfo(pGridData->hGrid,SB_HORZ,&si,TRUE);
 GetScrollInfo(pGridData->hGrid,SB_HORZ,&si);
 if(iScrollPos!=si.nPos)
 {
    if(si.nPos==0)
       SetWindowPos(pGridData->hPane,HWND_TOP,0,0,pGridData->pColWidths[iCols],pGridData->iPaneHeight,SWP_SHOWWINDOW);
    else
       SetWindowPos(pGridData->hPane,HWND_TOP,-si.nPos,0,pGridData->pColWidths[iCols],pGridData->iPaneHeight,SWP_SHOWWINDOW);
 }
 #ifdef MYDEBUG
 _ftprintf(fp,_T("    After All Adjustments\n"));
 _ftprintf(fp,_T("    si.nMin    = %d\n"),si.nMin);
 _ftprintf(fp,_T("    si.nMax    = %d\n"),si.nMax);
 _ftprintf(fp,_T("    si.nPos    = %d\n"),si.nPos);
 _ftprintf(fp,_T("    Leaving %WM_HSCROLL Case\n"));
 _ftprintf(fp,_T("Leaving fnGridProc_OnHScroll()\n\n"));
 #endif

 return 0;
}


long fnGridProc_OnVScroll(lpWndEventArgs Wea)
{
 GridData* pGridData=NULL;
 int iCols,iScrollPos;
 SCROLLINFO si;
 HWND hCell;

 #if defined MYDEBUG
 _ftprintf(fp,_T("Entering fnGridProc_OnVScroll()\n"));
 _ftprintf(fp,_T("  Wea->hWnd        = %u\n"),Wea->hWnd);
 #endif
 ZeroMemory(&si, sizeof(SCROLLINFO));
 pGridData = (GridData*)GetWindowLongPtr(Wea->hWnd,0);
 pGridData->pComObj->FlushData();
 si.cbSize = sizeof(SCROLLINFO);
 si.fMask  = SIF_ALL;
 GetScrollInfo(pGridData->hGrid,SB_VERT,&si);
 iScrollPos=si.nPos;
 #ifdef MYDEBUG
 _ftprintf(fp,_T("  Before Adjustments\n"));
 _ftprintf(fp,_T("  si.nMin          = %d\n"), si.nMin);
 _ftprintf(fp,_T("  si.nMax          = %d\n"), si.nMax);
 _ftprintf(fp,_T("  si.nPos          = %d\n"), si.nPos);
 _ftprintf(fp,_T("  pGridData->hGrid = %u\n"), pGridData->hGrid);
 _ftprintf(fp,_T("  pGridData        = %u\n"), pGridData);
 #endif
 switch(LOWORD(Wea->wParam))             // this originally didn't work
 {
    case SB_LINEUP:
      {
         if(si.nPos > si.nMin)
            si.nPos=si.nPos-1;
         break;
      }
    case SB_PAGEUP:
      {
         si.nPos = si.nPos - si.nPage;
         break;
      }
    case SB_LINEDOWN:
      {
         if(si.nPos<si.nMax)
            si.nPos=si.nPos+1;
         break;
      }
    case SB_PAGEDOWN:
      {
         si.nPos = si.nPos + si.nPage;
         break;
      }
    case SB_THUMBTRACK:
      {
         si.nPos=si.nTrackPos;
         break;
      }
 }
 si.fMask=SIF_POS;
 SetScrollInfo(pGridData->hGrid,SB_VERT,&si,TRUE);
 GetScrollInfo(pGridData->hGrid,SB_VERT,&si);
 if(iScrollPos!=si.nPos)
 {
     int iNum,iLast;
     iNum=pGridData->iCols*(si.nPos-1);
     iLast=(pGridData->iCols * pGridData->iVisibleRows) - 1;
     for(int i=0; i<=iLast; i++)
     {
       hCell=pGridData->pCellHandles[i];
       SetWindowLongPtr(hCell,0,(LONG_PTR)pGridData->pGridMemory[iNum]);
       SetWindowLongPtr(hCell,2*sizeof(void*),(LONG_PTR)pGridData->pTextColor[iNum]);
       SetWindowLongPtr(hCell,3*sizeof(void*),(LONG_PTR)pGridData->pBackColor[iNum]);
       iNum++;
     }
 }
 InvalidateRect(pGridData->hGrid,NULL,TRUE);
 #ifdef MYDEBUG
 _ftprintf(fp,_T("  After All Adjustments\n"));
 _ftprintf(fp,_T("  si.nMin    = %d\n"),si.nMin);
 _ftprintf(fp,_T("  si.nMax    = %d\n"),si.nMax);
 _ftprintf(fp,_T("  si.nPos    = %d\n"),si.nPos);
 _ftprintf(fp,_T("  Leaving %WM_VSCROLL Case\n"));
 _ftprintf(fp,_T("Leaving fnGridProc_OnVScroll()\n\n"));
 #endif

 return 0;
}

--- End code ---

Navigation

[0] Message Index

[#] Next page

Go to full version