Converting Data Bound Grid Control Code To PowerBASIC Windows 10

Started by Frederick J. Harris, September 19, 2014, 02:47:05 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Frederick J. Harris

     It appears  there are significant if not insurmountable obstacles to converting Visual Basic data bound grid control code (or the lack thereof) directly to PowerBASIC.  Let me explain this in detail, and the workarounds.  The key word in my first sentence above is 'directly'.

     Here is the issue.  One of the reasons Visual Basic was so popular was that it allowed for the first time novice programmers to accomplish really significant applications with almost no coding.  One of the best examples of that were data bound grid controls.  With these, a coder could drag a data control onto a Form, then a data bound grid control, and by just filling in a couple 'properties' in Visual Basic's 'Property Pane' such as the database path to connect to and the table desired, and with no code written at all create a usable app!  Such an app would then transparently accomplish the following ...

1) Open a database and table;
2) Determine schematics of table such as number rows, columns, column names, data types, etc;
3) Configure grid to accept this data;
4) Retrieve data from database table and populate grid;
5) Persist user edits/changes in grid back to database and table

The code to accomplish the above is not trivial.  And Visual Basic users did not have to deal with it.  It was taken care of transparently by Visual Basic.  Now it would stand to reason that since the components involved, i.e., data controls and data bound grid controls, are ActiveX Components with published interfaces, that it would be possible to translate this code on a line by line basis directly to PowerBASIC, because we have the capability in PowerBASIC to use ActiveX Controls.  The problem appears to be the connection or interface between the grid control which displays data and the data control which negotiates with the connected data source.  When using Visual Basic all one needs to do to make the connection is fill in the DataSource property of a grid control and it just works.  Allowable DataSource names would be the name of a data control on the user's Form.  But when looking at the interface names exported from a type library by either the PowerBASIC COM Browser or Jose Roca's TypeLib Browser, the Set DataSource method requires not a data control name but an IUnknown interface pointer.  And neither Jose Roca or myself have been able to provide any which work.  Worse, examining the *.idl file for these controls (Interface Definition Language) produced by OleView.exe indicates that the parameter is actually a DataSource*  (an interface pointer), and these are part of non-creatable COM objects.  And so far I've found no way to retrieve one and use it so as to make these things work.  So near but yet so far!  I've had no difficulty instantiating these objects with PowerBASIC; I just can't get them to speak to each other!  You've probably heard the old adage "Close only counts in horseshoes and hand grenades!"

     So the bottom line is that if you have Visual Basic code using any of these things and you wish to convert it to PowerBASIC, you are going to have to perform my five steps above yourself.  Just like in the good old days before Visual Basic.  If you just want to display data and not persist it back to the data source then you can get by with just the top four. 

     Now this situation raises all kinds of questions if you wish to translate such code to PowerBASIC.  Let's take a look at my #1 above - "Open a database and table".  Well, now you are going to have to decide which database technology or Api you are going to use.  Any old VB code from before VB6 is going to be using ODBC (Open Database Connectivity) or more likely DAO (Data Access Objects).  RDO is even a remote possibility.  With VB6 we're probably talking DAO, ADO (ActiveX Data Objects) or ODBC.  So your choices in PowerBASIC are SQL Tools by Perfect Sync Software if you want to purchase an ODBC Api, make direct ODBC function calls yourself which is free, develop your own Class wrapper around the ODBC Api like I've done, or use the PowerBASIC COM Browser to create includes which will work with DAO or ADO which are COM technologies.  Also, Jose Roca has developed ODBC, ADO, and DAO wrappers which are excellent and are available here on this forum.  And when you've finally made this choice of which database Api to use, you are going to have to write the code yourself to extract your data out of the database.  PowerBASIC won't do it for you.

     Now let's consider my #3 above - "Configure grid to accept this data".  Well, which grid?  The data bound grids are out of the picture I believe.  Maybe someone can correct me if I'm wrong, but I believe they were designed specifically to accept their data from data controls, and we can't get these to work together as I've explained above.  That's why I'm writing this.  So you are going to have to come up with a grid control that you can use.  There are choices.  If you have the Professional or Enterprise Edition of Visual Basic 6 you have a license to use the MSFlexGrid ActiveX Control supplied with those editions.  I'll provide code here showing how to use this grid to accomplish my five steps above.  Jose Roca has already provided such code here and other places for every version of PowerBASIC since version 7, but I'll rehash that with an eye to conversions from Visual Basic and persisting edits back to the database.

     But the MSFlexGrid is rather old, dating all the way back to 1998 or so, and it is for sure your typical bloat ware Microsoft product, and to make matters worse there is some miserable licensing code to deal with as well as other dependencies.  So since you are going to have to deal with all this yourself from scratch, so to speak, you may wish to consider other grid controls, and there are a lot of choices.  Around 2003 I purchased a grid control from a PowerBASIC vendor named the SIGrid.  It really worked well for me, but I don't believe its available anymore.  At the present time I'm aware of two PowerBASIC Forum members who market grid controls, and that would be James Klutho and Elias Montoya.  Other PowerBASIC Forum members have provided grid code in the PowerBASIC Forums, and I've provided grid code here in Jose's Forum in both ActiveX Control and Custom Control form.  After I've shown several different techniques of using the MSFlexGrid in terms of my five steps above, I'll demonstrate accomplishing the same with my grid code.  And I'll use for an example connecting to some tables in the Biblio.mdb file supplied, I believe, with all versions of Visual Basic and likely Microsoft Access too.  And maybe we can get James Klutho and Elias Montoya to provide examples using their grids.

     The next issue to consider is include files.  In working with ActiveX Controls, for example the MSFlexGrid described above, its easier to use Jose Roca's include set.  What I've always done is create a \WinApiEx directory right under my PowerBASIC installation directory, and alongside the WinApi directory already there, and unpack Jose's includes to there.  Its possible to use the PowerBASIC includes but sometimes there's some tweaking involved.  You'll find that some interfaces and types haven't been defined, for example.  Nonetheless, I'll provide one example using the PowerBASIC includes.  If you aren't going to be using ActiveX Controls it likely won't matter.

     Another somewhat related issue is the one of ActiveX Control Containers.  If you use my ActiveX Grid Control you won't need one, or if you use a non-COM custom grid control you won't need one, but if you want to use Microsoft's MSFlexGrid Control you will definitely need one.  And there are realistically three choices there.   And I'll list these in no particular order of desirability.  You will have to make the choice.  First comes an ActiveX Control Container provided by Microsoft itself through an Active Template Library dll named Atl71.dll.  There are some functions exported from this dll that provide ActiveX Control containment.  What's that all about you ask? 

     When you put an ActiveX Control in the Visual Basic 'Toolbox' its actually loaded and running.  These controls have two modes - a design time mode and a runtime mode.   For example, when you place an ActiveX Control on your Visual Basic Form and use the resizing functionality of the IDE to drag the corners about to achieve the sizing you want, running code in the IDE is interacting with running code in the ActiveX Dll to make this all work.  So the point to take home from this is that these controls were largely designed to work within an IDE designed for graphical design such as Visual Basic.  It is for this reason that I'm throwing out the idea to you that if you are a new PowerBASIC user migrating away from Visual Basic then your interests might best be served by using other types of controls than ActiveX Controls.  There are substitutes for at least some of Visual Basic's ActiveX Controls.  As I've mentioned, grids are available elsewhere.  The MS Calendar Common Control can be substituted for MSCAL.OCX.  If the situation were such that you could make a line by line translation of Visual Basic code to PowerBASIC code, then I can see there is a good argument for using the same controls in PowerBASIC that exist in a Visual Basic Project.  But if there are no substitutes in PowerBASIC for various Visual Basic functionality, and a good deal of actual code must be written in PowerBASIC to achieve what Visual Basic was auto-generating 'behind the scenes', so to speak, then it seems to me to make sense to use different controls from those used in Visual Basic. 

     I almost forgot where I was at.  We were discussing ActiveX Control Containers.  In addition to the one provided by ATL there is Jose Roca's OLE Container Control.  The code is in OLECON.inc, and if you download Jose's Include file set you will have it.  I believe it all involves around 5000 lines of code Jose has written just in OLECON.inc.  Of course, that code relies on additional code in his includes. 

     And Dominic Mitchell has created an ActiveX Control Container as part of his Phoenix product.  As of yet I don't have that but I'm mentioning it because it is no doubt another very good alternative.   I intend to try it out soon myself.

     What I'm going to do here is show how I would translate Visual Basic Data Bound Grid Control code to PowerBASIC.  First I'll describe the Visual Basic code I'm translating, then show how to use the MSFlexGrid and my grid control to hold the data.  I'll try to provide examples using the PowerBASIC includes and Jose Roca's includes although most of my emphasis will be using Jose's includes.  Here is the Visual Basic 6 project I'll use for an example ...

1) Open Visual Basic 6  and create a new *.exe project.  You can leave the names of the default Form file and project file as Form1.frm and Project1.vbp;

2) Go to the Project Main Menu item and select 'Components'.  This will bring up the Components Dialog Box where you can add various ActiveX Controls to the project.  Add these two components to your Project1...     

Microsoft ADO Data Control 6.0 (SP6) (OLEDB)     C:\Windows\SysWow64\MSADODC.OCX
Microsoft DataGrid Control 6.0 (SP6) (OLEDB)        C:\Windows\SysWow64\MSDATGRD.OCX

There are check boxes to do that.  What that will do is add icons to these two ActiveX Controls to you VB 'Toolbox'.  Then drag instances of these to your Form1.  Align the ADO Data Control about 95% of the full width of Form1 at the bottom and use the rest of the space for the grid.  Make it nice and pretty.  While you are at it make the Form1 two or three times bigger;

3) Then go to the 'Properties" Window.  Select the ADO Data Control, and that will display the properties of the data control in that window.  The default name VB would have given the data control is Adodc1.  That's fine.  Click on the 'ConnectionString' property, and that will bring up a tabbed dialog where VB will guide you through creating a connection string.  Set the Provider to Microsoft Jet OLEDB 4.0 and set the database to the Biblio.mdb that ships with every edition of Visual Basic.  On my machines I always accept the default installation path, and its located in C:\Program Files (x86)\Microsoft Visual Studio\VB98.  Then set the 'CommandType' to 2 - adCmdTable.  That tells the data control its source within the database will be a plain ordinary table.

4) Next click on the data grid.  That will bring up its properties in the 'Properties' pane.  Find the all important 'DataSource' property.  Click on that and a drop down arrow will appear in the value field.  By this time VB is smart enough to realize a data control is on the form and when you click that drop down arrow you'll see Adodc1, which you can select.  Do that.  That's it!  Not one line of code written!  You can run this project and after several seconds you should see a form with a grid on it containing all the data from the Titles Table of Biblio.mdb.   I believe any edits you make will be automatically written back to Biblio.mdb.  So let's see what's involved in translating this to PowerBASIC.  We'll start real simple and basic at first.  For this example we'll just try to get a working MSFlexGrid ActiveX Control on a Form.  We'll just specify three columns named 'Column 1', 'Column 2', and 'Column 3'.  We'll use the PowerBASIC COM Browser from PBWin 10 to generate the MSFlexGrid interface includes, and we'll use the PowerBASIC Win Api includes installed by default with the PowerBASIC installation.  And we'll use Active Template Library (ATL) Control Containment.  So you'll need preferably Atl71.dll to be somewhere in your path.  I'm not sure exactly where you'll get that file if you don't have it.  I can email it to you if you are having difficulties locating it.  Also, before getting ahead of myself, let me state that you need to be a licensed user of Visual Basic 6 Professional or Enterprise Edition and that needs to be installed.

     Which brings up another nasty issue.  The MSFlexGrid.OCX ActiveX Control is what is known as a licensed control.  If you have either of those editions of Visual Basic I mentioned above you are a licensed user of that control.  The way Microsoft has this all set up is tricky in the usual Microsoft fashion.  The computer on which either of those versions is installed has what is known as a 'Machine License'.  When such a machine is used to code a project using the MSFlexGrid, if you aren't using Visual Basic but PowerBASIC, C++, or something else, you need to use object creation code that includes the Runtime License for the control, or when the executable is run on a different machine without a 'Machine License', the MSFlexGrid won't instantiate, even if it has been satisfactorily registered with RegSvr32.  I suppose this is to prevent another developer from getting a 'free' copy of the control from an install of an app and using it like he/she paid for it.  When you use Jose Roca's TypeLib Browser to generate includes for ActiveX Controls, there is an option to generate the license code and include it in the file.  I don't believe the PowerBASIC COM Browser has that option, so here is a little utility you can use to get your license code.   Ohhh!  But there's a catch!  While we can avoid using Jose's TypeLib Browser to get the license, and we can avoid using his OleCon.inc ActiveX Control Container, we still can't leave Jose out of the picture (not that we would want to - I'm just trying to illustrate the pure stock PB way of doing it), for the code below requires the definition of the IClassFactory2 Interface, and unless you want to translate it from the IDL (Interface Definition Language) file yourself, you'll need Jose's includes to run this program!   ...


#Compile Exe
#Dim All
#Include "Windows.inc"
#Include Once "Ocidl.inc"
$CLSID_MSFlexGrid = GUID$("{6262D3A0-531B-11CF-91F6-C2863C385E30}")
Declare Function DllGetClassObjectImpl(Byref Clsid As Guid, Byref iid As Guid, Byref pCF As IUnknown) As Long

Function PBMain() As Long
  Local pClassFactory As IClassFactory2
  Local pDllGetClassObject As Dword
  Local strLicense As WString
  Local lic as LICINFO
  Local hDll As Dword
  Local hr As Long

  hDll=LoadLibrary("C:\Windows\SysWOW64\MSFlxGrd.ocx")
  If hDll Then
     pDllGetClassObject=GetProcAddress(hDll,"DllGetClassObject")
     If pDllGetClassObject Then
        Call Dword pDllGetClassObject Using DllGetClassObjectImpl($CLSID_MSFlexGrid, $IID_IClassFactory2, pClassFactory) To hr
        If SUCCEEDED(hr) Then
           hr=pClassFactory.GetLicInfo(lic)
           If SUCCEEDED(hr) Then
              If lic.fRuntimeKeyAvail And lic.fLicVerified Then
                 hr=pClassFactory.RequestLicKey(0, strLicense)
                 If SUCCEEDED(hr) Then
                    Con.Print "strLicense = " strLicense
                 End If
              End If
           End If
           Set pClassFactory = Nothing
        End If
     End If
     Call FreeLibrary(hDll)
  End If
  Con.Waitkey$

  PBMain=0
End Function


And its a Console Compiler 6 program.  If you don't have the Console Compiler print the outputs to a text file, e.g., Print #1, "strLicense = " strLicense.  Here is the output on my computer ...

strLicense = 72E67120-5959-11cf-91F6-C2863C385E30

So if you just output it to a Message Box you are going to have to copy that correctly without mistakes.  Its a GUID. 

Next step is to open the PowerBASIC COM Browser and look for "Microsoft FlexGrid Control 6.0".  Double click on that and the interface definitions will be created for you.  Just a warning!  With mine I had to change about a half dozen items, specifically, there was a method parameter named data that conflicted with a PowerBASIC reserved word, and several instances of the same problem with a 'Shift' keyword.  I changed them like so ...

Data      Changed To GridData
Shift      Changed to  iShift

I'll provide my include below, but if you generate yours from the PowerBASIC COM Browser you might run into those minor difficulties.  If you are new to PowerBASIC and are not familiar with such issues then I suppose the problem isn't minor to you.  Without further ado, here is MSFlexGrid1.bas ...


continued....



Frederick J. Harris


'MSFlexGrid1.bas                                  ' Creates an instance of the MSFlexGrid
#Compile                Exe  "MSFlexGrid1"        ' ActiveX Control on a Form.  Compiles
%UNICODE                = 1                       ' with PBWin 10.  Uses wide characters
#Include                "Windows.inc"             ' throughout.  Requires Atl71.dll to be
#Include                "MSFlexGrid.inc"          ' in your PATH.
$ATL_DLLNAME            = "Atl71.dll"
%ID_CONTAINER           = 2000

Declare Function AtlAxWinInit Lib $ATL_DLLNAME Alias "AtlAxWinInit" () AS LONG

Declare Function AtlAxCreateControlLic Lib $ATL_DLLNAME Alias "AtlAxCreateControlLic" _
( _
  Byref lpszName        As WStringz, _
  Byval hWnd            As Dword, _
  Byval pStream         As IUnknown, _            ' This is actually an IStream
  Byref ppUnkContainer  As IUnknown, _
  Byval bstrLic         As WString _
) As Long

Declare Function AtlAxGetControl Lib $ATL_DLLNAME Alias "AtlAxGetControl" _
( _
  Byval hWnd As Dword, _
  Byref pp As IUnknown _
) As Long

Macro  CObj(pUnk, dwAddr) = Poke Dword, Varptr(pUnk), dwAddr

Type WndEventArgs
  wParam                As Long
  lParam                As Long
  hWnd                  As Dword
  hInst                 As Dword
End Type


Sub GridSetup(Byref pGrid As IMSFlexGrid)
  pGrid.FontName    = "Times New Roman"
  pGrid.FontSize    = 10
  pGrid.Cols        = 4
  pGrid.Rows        = 20
  pGrid.ColWidth(0) = 200
  pGrid.ColWidth(1) = 1220
  pGrid.ColWidth(2) = 1220
  pGrid.ColWidth(3) = 1220
  pGrid.Col         = 1
  pGrid.Row         = 0
  pGrid.Text        = "Column 1"
  pGrid.Col         = 2
  pGrid.Row         = 0
  pGrid.Text        = "Column 2"
  pGrid.Col         = 3
  pGrid.Row         = 0
  pGrid.Text        = "Column 3"
End Sub


Function fnWndProc_OnCreate(Wea As WndEventArgs) As Long   ' This procedure is exactly equivalent to Form_Load() in Visual Basic.
  Local pStream,ppUnkContainer,pUnkGrid As IUnknown        ' 1st thing we do is retrieve the HINSTANCE from the CREATESTRUCT UDT.
  Local lpCreateStruct As CREATESTRUCT Ptr                 ' Next create a 'label' (static) control to 'contain' the grid.  Then
  Local pEvents As DMSFlexGridEvents                       ' pass in the Program ID and License to AtlAxCreateControlLic().  This
  Local pFlexGrid As IMSFlexGrid                           ' will give us the IUnknown of the Control Container.  Next we create
  Local pDispGrid As IDispatch                             ' an instance of the Event or Sink Class "Class_DMSFlexGridEvents".
  Local szProgId As Wstringz*32                            ' The definition and implementation of this class is in the MSFlexGrid
  Local strLicense As WString                              ' include file.  Then I store the interface pointer pEvents in the
  Local hContainer As Dword                                ' Window Class structure of "OCX Test" object at WNDCLASS::cbWndExtra
  Local hr As Long                                         ' memory at offset 4.  Then we use AtlAxGetControl() from Atl71.dll to
                                                           ' get the IUnknown of the grid itself.  We AddRef() that so PowerBASIC's
  lpCreateStruct=Wea.lParam : Wea.hInst=@lpCreateStruct.hInstance  ' stack variable clean up code won't Release() the object at...
  hr=AtlAxWinInit()
  If SUCCEEDED(hr) Then
     hContainer=CreateWindowEx(0,"static","",%WS_CHILD OR %WS_VISIBLE,10,10,280,250,Wea.hWnd,%ID_CONTAINER,Wea.hInst,Byval %NULL)
     szProgId   = "MSFlexGridLib.MSFlexGrid"
     strLicense = "72E67120-5959-11cf-91F6-C2863C385E30" ' you need your license here - not mine!
     hr=AtlAxCreateControlLic(szProgId,hContainer,pStream,ppUnkContainer,strLicense)
     If SUCCEEDED(hr) Then
        pEvents=Class "Class_DMSFlexGridEvents"            ' procedure termination.  Note all my variables are locals - no globals
        Call SetWindowLong(Wea.hWnd,4,Objptr(pEvents))     ' in this program.  Then I store that pointer at offset zero in the
        hr = AtlAxGetControl(hContainer, pUnkGrid)         ' WNDCLASSEX::cbWndExtra bytes.  To turn on event handling from the
        If SUCCEEDED(hr) Then                              ' grid we use PowerBASIC's 'Events From' ... Call syntax.  I put
           pUnkGrid.AddRef()                               ' various code to configure the grid in my GridSetup() procedure.  That
           Call SetWindowLong(Wea.hWnd,0,Objptr(pUnkGrid)) ' requires an IMSFlexGrid pointer, so I had to QueryInterface() for
           pDispGrid=pUnkGrid                              ' that using pFlexGrid=pUnkGrid syntax (PB calls QueryInterface().  And
           Events From pDispGrid Call pEvents              ' the Events code is a dispinterface only (not dual), and requires an
           pFlexGrid=pUnkGrid                              ' IDispatch pointer - pDispGrid.
           Call GridSetup(pFlexGrid)
        End If
     End If
  End If

  fnWndProc_OnCreate=0
End Function


Function fnWndProc_OnDestroy(Wea As WndEventArgs) As Long  ' This is Form_Unload() or Form_Terminate() in Visual Basic - not sure
  Local pEvents As DMSFlexGridEvents                       ' which.  You can't prevent destruction of the Form at this point.  Its
  Local pGrid As IUnknown                                  ' on the way out and 'nothin's gonna bring it back.  I've got a reference
  Local pObj As Dword                                      ' count of +1 on the grid though that I've got to cancel out if I want
                                                           ' the grid released though (that's why it wasn't destroyed when
  pObj=GetWindowLong(Wea.hWnd,4)                           ' fnWndProc_OnCreate() exited - that +1 count). So here I retrieve my
  CObj(pEvents,pObj)                                       ' stored pointer to the Events interface = pEvents, and terminate that
  If IsObject(pEvents) Then                                ' connection.  Next cause a Release call on the grid itself by setting
     Events End pEvents                                    ' the pointer to 'Nothing'.  Note one needs to do some chicanery here
     Set pEvents=Nothing                                   ' to outwit the compiler.  It won't allow you to directly install values
  End If                                                   ' into interface pointers or read them.  My CObj macro uses Poke Dword
  pObj=GetWindowLong(Wea.hWnd,0)                           ' to slip (poke) the number in when it isan't looking.  Finally,
  If pObj Then                                             ' PostQuitMessage() ends the message pump down in WinMain() and the
     CObj(pGrid,pObj)                                      ' program ends.
     Set pGrid=Nothing
  End If
  Call PostQuitMessage(0)

  fnWndProc_OnDestroy=0
End Function


Function fnWndProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  Local Wea As WndEventArgs

  Select Case As Long wMsg
    Case %WM_CREATE
      Wea.hWnd=hWnd : Wea.wParam=wParam : Wea.lParam=lParam
      fnWndProc=fnWndProc_OnCreate(Wea)
      Exit Function
    Case %WM_DESTROY
      Wea.hWnd=hWnd : Wea.wParam=wParam : Wea.lParam=lParam
      fnWndProc=fnWndProc_OnDestroy(Wea)
      Exit Function
  End Select

  fnWndProc=DefWindowProc(hWnd,wMsg,wParam,lParam)
End Function


Function WinMain(ByVal hIns As Long,ByVal hPrev As Long,ByVal lpCL As Asciiz Ptr,ByVal iShow As Long) As Long
  Local winclass As WndClassEx
  Local szAppName As WStringz*16
  Local Msg As tagMsg
  Local hWnd As Dword

  szAppName="OCX Test"                                    : winclass.cbSize=SizeOf(winclass)
  winclass.lpfnWndProc=CodePtr(fnWndProc)                 : winclass.cbClsExtra=0
  winclass.cbWndExtra=8                                   : winclass.hInstance=hIns
  winclass.hIcon=LoadIcon(%NULL,ByVal %IDI_APPLICATION)   : winclass.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW)
  winclass.hbrBackground=%COLOR_BTNFACE+1                 : winclass.lpszClassName=VarPtr(szAppName)
  Call RegisterClassEx(winclass)
  hWnd=CreateWindowEx(0,szAppName,"Try MSFlexGrid",%WS_OVERLAPPEDWINDOW Xor %WS_MAXIMIZEBOX,200,100,310,310,0,0,hIns,ByVal 0)
  Call ShowWindow(hWnd,iShow)
  While GetMessage(Msg,%NULL,0,0)
    Call TranslateMessage(Msg)
    Call DispatchMessage(Msg)
  Wend

  Function=msg.wParam
End Function


I don't consider the above to be an exceedingly large Win32 Api SDK style program for creating something as sophisticated as an ActiveX Grid Control.  But we haven't looked at the Auto-Generated MSFlexGrid.inc file yet mostly generated by the PowerBASIC COM Browser.  That's a good bit bigger, but simply because the MSFlexGrid has a lot of methods in its interfaces ...



' Generated by: PowerBASIC COM Browser v.2.00.0086
' Date & Time : 9/15/2014 at 3:07 PM
' Options:
' Always use an Interface Prefix : Off
' Interface Prefix               : grd
' Prefix ProgIDs, ClassIDs...    : Off
' Use ANSI Strings               : Off
' Use Singular Enumerations      : On
' Generate Dispatch Interfaces   : Off
' Include Parameter Names        : On
' Use Property Get/Set statements: On
' ------------------------------------------------
' Library Name: MSFlexGridLib
' Library File: C:\Windows\SysWow64\MSFLXGRD.OCX
' Description : Microsoft FlexGrid Control 6.0 (SP6)
' Help File : C:\Windows\HELP\MSHFlx98.chm
' Help Context : 0
' GUID : {5E9E78A0-531B-11CF-91F6-C2863C385E30}
' LCID : 0
' Version : 1.0

' Version Dependent ProgIDs
$PROGID_MSFlexGrid1 = "MSFlexGridLib.MSFlexGrid.1"

' Version Independent ProgIDs
$PROGID_MSFlexGrid = "MSFlexGridLib.MSFlexGrid"

' Class Identifiers
$CLSID_DataObject = GUID$("{2334D2B2-713E-11CF-8AE5-00AA00C00905}")
$CLSID_DataObjectFiles = GUID$("{2334D2B4-713E-11CF-8AE5-00AA00C00905}")
$CLSID_MSFlexGrid = GUID$("{6262D3A0-531B-11CF-91F6-C2863C385E30}")
$CLSID_Event_DMSFlexGridEvents = GUID$("{8BAAFAFB-74CA-4062-A7D8-146C6EEE03C3}")

' Interface Identifiers
$IID_IVBDataObject = GUID$("{2334D2B1-713E-11CF-8AE5-00AA00C00905}")
$IID_IVBDataObjectFiles = GUID$("{2334D2B3-713E-11CF-8AE5-00AA00C00905}")
$IID_IRowCursor = GUID$("{9F6AA700-D188-11CD-AD48-00AA003C9CB6}")
$IID_IMSFlexGrid = GUID$("{5F4DF280-531B-11CF-91F6-C2863C385E30}")
$IID_DMSFlexGridEvents = GUID$("{609602E0-531B-11CF-91F6-C2863C385E30}")

Enum OLEDragConstants Singular
  flexOLEDragManual = 0
  flexOLEDragAutomatic = 1
End Enum

Enum OLEDropConstants Singular
  flexOLEDropNone = 0
  flexOLEDropManual = 1
End Enum

Enum DragOverConstants Singular
  flexEnter = 0
  flexLeave = 1
  flexOver = 2
End Enum

Enum ClipBoardConstants Singular
  flexCFText = 1
  flexCFBitmap = 2
  flexCFMetafile = 3
  flexCFDIB = 8
  flexCFPalette = 9
  flexCFEMetafile = 14
  flexCFFiles = 15
  flexCFRTF = -16639
End Enum

Enum OLEDropEffectConstants Singular
  flexOLEDropEffectNone = 0
  flexOLEDropEffectCopy = 1
  flexOLEDropEffectMove = 2
  flexOLEDropEffectScroll = -2147483648
End Enum

Enum ErrorConstants Singular
  flexerrIllegaFunctionCall = 5
  flexerrObjIllegalUse = 425
  flexerrClipInvalidFormat = 461
  flexerrDataObjectLocked = 672
  flexerrExpectedAnArgument = 673
  flexerrRecursiveOLEDrag = 674
  flexerrUserFormatNotBinArray = 675
  flexerrDataNotSetForFormat = 676
  flexerrUnknownError = 600
  flexerrSubscript = 381
  flexerrBadValue = 380
  flexerrGetNotSupported = 394
  flexerrSetNotPermitted = 387
  flexerrOutOfMemory = 7
  flexerrVB30000 = 30000
  flexerrVB30001 = 30001
  flexerrVB30002 = 30002
  flexerrVB30004 = 30004
  flexerrVB30005 = 30005
  flexerrVB30006 = 30006
  flexerrVB30008 = 30008
  flexerrVB30009 = 30009
  flexerrVB30010 = 30010
  flexerrVB30011 = 30011
  flexerrVB30013 = 30013
  flexerrVB30014 = 30014
  flexerrVB30015 = 30015
  flexerrVB30016 = 30016
  flexerrVB30017 = 30017
End Enum

Enum AppearanceSettings Singular
  flexFlat = 0
  flex3D = 1
End Enum

Enum BorderStyleSettings Singular
  flexBorderNone = 0
  flexBorderSingle = 1
End Enum

Enum FocusRectSettings Singular
  flexFocusNone = 0
  flexFocusLight = 1
  flexFocusHeavy = 2
End Enum

Enum HighLightSettings Singular
  flexHighlightNever = 0
  flexHighlightAlways = 1
  flexHighlightWithFocus = 2
End Enum

Enum ScrollBarsSettings Singular
  flexScrollBarNone = 0
  flexScrollBarHorizontal = 1
  flexScrollBarVertical = 2
  flexScrollBarBoth = 3
End Enum

Enum TextStyleSettings Singular
  flexTextFlat = 0
  flexTextRaised = 1
  flexTextInset = 2
  flexTextRaisedLight = 3
  flexTextInsetLight = 4
End Enum

Enum FillStyleSettings Singular
  flexFillSingle = 0
  flexFillRepeat = 1
End Enum

Enum GridLineSettings Singular
  flexGridNone = 0
  flexGridFlat = 1
  flexGridInset = 2
  flexGridRaised = 3
End Enum

Enum SelectionModeSettings Singular
  flexSelectionFree = 0
  flexSelectionByRow = 1
  flexSelectionByColumn = 2
End Enum

Enum MergeCellsSettings Singular
  flexMergeNever = 0
  flexMergeFree = 1
  flexMergeRestrictRows = 2
  flexMergeRestrictColumns = 3
  flexMergeRestrictAll = 4
End Enum

Enum PictureTypeSettings Singular
  flexPictureColor = 0
  flexPictureMonochrome = 1
End Enum

Enum AllowUserResizeSettings Singular
  flexResizeNone = 0
  flexResizeColumns = 1
  flexResizeRows = 2
  flexResizeBoth = 3
End Enum

Enum MousePointerSettings Singular
  flexDefault = 0
  flexArrow = 1
  flexCross = 2
  flexIBeam = 3
  flexIcon = 4
  flexSize = 5
  flexSizeNESW = 6
  flexSizeNS = 7
  flexSizeNWSE = 8
  flexSizeEW = 9
  flexUpArrow = 10
  flexHourglass = 11
  flexNoDrop = 12
  flexArrowHourGlass = 13
  flexArrowQuestion = 14
  flexSizeAll = 15
  flexCustom = 99
End Enum

Enum SortSettings Singular
  flexSortNone = 0
  flexSortGenericAscending = 1
  flexSortGenericDescending = 2
  flexSortNumericAscending = 3
  flexSortNumericDescending = 4
  flexSortStringNoCaseAscending = 5
  flexSortStringNoCaseDescending = 6
  flexSortStringAscending = 7
  flexSortStringDescending = 8
End Enum

Enum AlignmentSettings Singular
  flexAlignLeftTop = 0
  flexAlignLeftCenter = 1
  flexAlignLeftBottom = 2
  flexAlignCenterTop = 3
  flexAlignCenterCenter = 4
  flexAlignCenterBottom = 5
  flexAlignRightTop = 6
  flexAlignRightCenter = 7
  flexAlignRightBottom = 8
  flexAlignGeneral = 9
End Enum


' Interface Name  : IVBDataObject
' Class Name      : DataObject
' ClassID         : $CLSID_DataObject
' This Interface cannot be created directly it can only
' be returned by a Method or Property in this library.
Interface IVBDataObject $IID_IVBDataObject
  Inherit IDispatch

  Method Clear <1> ()
  Method GetData <2> (Byval sFormat As Integer) As Variant
  Method GetFormat <3> (Byval sFormat As Integer) As Integer
  Method SetData <4> (Opt Byval vValue As Variant, Opt Byval vFormat As Variant)
  Property Get Files <5> () As IVBDataObjectFiles
End Interface

' Interface Name  : IVBDataObjectFiles
' Class Name      : DataObjectFiles
' ClassID         : $CLSID_DataObjectFiles
' This Interface cannot be created directly it can only
' be returned by a Method or Property in this library.
Interface IVBDataObjectFiles $IID_IVBDataObjectFiles
  Inherit IDispatch

  Property Get Item <0> (ByVal lIndex As Long) As WString
  Property Get Count <1> () As Long
  Method Add <2> (Byval bstrFilename As WString, Opt Byval vIndex As Variant)
  Method Clear <3> ()
  Method Remove <4> (Byval vIndex As Variant)
  Method Meth__NewEnum <-4> () As IUnknown
End Interface

' Interface Name  : IRowCursor
' This Interface cannot be created directly it can only
' be returned by a Method or Property in this library.
Interface IRowCursor $IID_IRowCursor
  Inherit IDispatch

End Interface

' Interface Name  : IMSFlexGrid
' Description     : Dispatch interface for Microsoft FlexGrid Control
' Class Name      : MSFlexGrid
' ClassID         : $CLSID_MSFlexGrid
' ProgID          : $PROGID_MSFlexGrid
' Version ProgID  : $PROGID_MSFlexGrid1
Interface IMSFlexGrid $IID_IMSFlexGrid
  Inherit IDispatch

  Property Get Rows <4> () As Long
  Property Set Rows <4> (ByVal Rows As Long)
  Property Get Cols <5> () As Long
  Property Set Cols <5> (ByVal Cols As Long)
  Property Get FixedRows <6> () As Long
  Property Set FixedRows <6> (ByVal FixedRows As Long)
  Property Get FixedCols <7> () As Long
  Property Set FixedCols <7> (ByVal FixedCols As Long)
  Property Get Version <1> () As Integer
  Property Get FormatString <2> () As WString
  Property Set FormatString <2> (ByVal FormatString As WString)
  Property Get TopRow <8> () As Long
  Property Set TopRow <8> (ByVal TopRow As Long)
  Property Get LeftCol <9> () As Long
  Property Set LeftCol <9> (ByVal LeftCol As Long)
  Property Get Row <10> () As Long
  Property Set Row <10> (ByVal Row As Long)
  Property Get Col <11> () As Long
  Property Set Col <11> (ByVal Col As Long)
  Property Get RowSel <12> () As Long
  Property Set RowSel <12> (ByVal RowSel As Long)
  Property Get ColSel <13> () As Long
  Property Set ColSel <13> (ByVal ColSel As Long)
  Property Get Text <0> () As WString
  Property Set Text <0> (ByVal Text As WString)
  Property Get BackColor <-501> () As DWord
  Property Set BackColor <-501> (ByVal BackColor As DWord)
  Property Get ForeColor <-513> () As DWord
  Property Set ForeColor <-513> (ByVal ForeColor As DWord)
  Property Get BackColorFixed <14> () As DWord
  Property Set BackColorFixed <14> (ByVal BackColorFixed As DWord)
  Property Get ForeColorFixed <15> () As DWord
  Property Set ForeColorFixed <15> (ByVal ForeColorFixed As DWord)
  Property Get BackColorSel <16> () As DWord
  Property Set BackColorSel <16> (ByVal BackColorSel As DWord)
  Property Get ForeColorSel <17> () As DWord
  Property Set ForeColorSel <17> (ByVal ForeColorSel As DWord)
  Property Get BackColorBkg <18> () As DWord
  Property Set BackColorBkg <18> (ByVal BackColorBkg As DWord)
  Property Get WordWrap <19> () As Integer
  Property Set WordWrap <19> (ByVal WordWrap As Integer)
  Property Get Font <-512> () As IDispatch
  Property Set PutRef_Font <-512> (ByVal PB_Font As IDispatch)
  Property Get FontWidth <84> () As Single
  Property Set FontWidth <84> (ByVal FontWidth As Single)
  Property Get CellFontName <77> () As WString
  Property Set CellFontName <77> (ByVal CellFontName As WString)
  Property Get CellFontSize <78> () As Single
  Property Set CellFontSize <78> (ByVal CellFontSize As Single)
  Property Get CellFontBold <79> () As Integer
  Property Set CellFontBold <79> (ByVal CellFontBold As Integer)
  Property Get CellFontItalic <80> () As Integer
  Property Set CellFontItalic <80> (ByVal CellFontItalic As Integer)
  Property Get CellFontUnderline <81> () As Integer
  Property Set CellFontUnderline <81> (ByVal CellFontUnderline As Integer)
  Property Get CellFontStrikeThrough <82> () As Integer
  Property Set CellFontStrikeThrough <82> (ByVal CellFontStrikeThrough As Integer)
  Property Get CellFontWidth <83> () As Single
  Property Set CellFontWidth <83> (ByVal CellFontWidth As Single)
  Property Get TextStyle <20> () As Long
  Property Set TextStyle <20> (ByVal TextStyle As Long)
  Property Get TextStyleFixed <21> () As Long
  Property Set TextStyleFixed <21> (ByVal TextStyleFixed As Long)
  Property Get ScrollTrack <22> () As Integer
  Property Set ScrollTrack <22> (ByVal ScrollTrack As Integer)
  Property Get FocusRect <23> () As Long
  Property Set FocusRect <23> (ByVal FocusRect As Long)
  Property Get HighLight <24> () As Long
  Property Set HighLight <24> (ByVal HighLight As Long)
  Property Get Redraw <25> () As Integer
  Property Set Redraw <25> (ByVal PB_Redraw As Integer)
  Property Get ScrollBars <26> () As Long
  Property Set ScrollBars <26> (ByVal ScrollBars As Long)
  Property Get MouseRow <27> () As Long
  Property Get MouseCol <28> () As Long
  Property Get CellLeft <29> () As Long
  Property Get CellTop <30> () As Long
  Property Get CellWidth <31> () As Long
  Property Get CellHeight <32> () As Long
  Property Get RowHeightMin <33> () As Long
  Property Set RowHeightMin <33> (ByVal RowHeightMin As Long)
  Property Get FillStyle <-511> () As Long
  Property Set FillStyle <-511> (ByVal FillStyle As Long)
  Property Get GridLines <34> () As Long
  Property Set GridLines <34> (ByVal GridLines As Long)
  Property Get GridLinesFixed <35> () As Long
  Property Set GridLinesFixed <35> (ByVal GridLinesFixed As Long)
  Property Get GridColor <36> () As DWord
  Property Set GridColor <36> (ByVal GridColor As DWord)
  Property Get GridColorFixed <37> () As DWord
  Property Set GridColorFixed <37> (ByVal GridColorFixed As DWord)
  Property Get CellBackColor <38> () As DWord
  Property Set CellBackColor <38> (ByVal CellBackColor As DWord)
  Property Get CellForeColor <39> () As DWord
  Property Set CellForeColor <39> (ByVal CellForeColor As DWord)
  Property Get CellAlignment <40> () As Integer
  Property Set CellAlignment <40> (ByVal CellAlignment As Integer)
  Property Get CellTextStyle <41> () As Long
  Property Set CellTextStyle <41> (ByVal CellTextStyle As Long)
  Property Get CellPictureAlignment <43> () As Integer
  Property Set CellPictureAlignment <43> (ByVal CellPictureAlignment As Integer)
  Property Get Clip <45> () As WString
  Property Set Clip <45> (ByVal Clip As WString)
  Property Set Sort <46> (ByVal Rhs As Integer)
  Property Get SelectionMode <47> () As Long
  Property Set SelectionMode <47> (ByVal SelectionMode As Long)
  Property Get MergeCells <48> () As Long
  Property Set MergeCells <48> (ByVal MergeCells As Long)
  Property Get AllowBigSelection <51> () As Integer
  Property Set AllowBigSelection <51> (ByVal AllowBigSelection As Integer)
  Property Get AllowUserResizing <52> () As Long
  Property Set AllowUserResizing <52> (ByVal AllowUserResizing As Long)
  Property Get BorderStyle <-504> () As Long
  Property Set BorderStyle <-504> (ByVal BorderStyle As Long)
  Property Get hWnd <-515> () As Long
  Property Get Enabled <-514> () As Integer
  Property Set Enabled <-514> (ByVal Enabled As Integer)
  Property Get Appearance <-520> () As Long
  Property Set Appearance <-520> (ByVal Appearance As Long)
  Property Get MousePointer <53> () As Long
  Property Set MousePointer <53> (ByVal MousePointer As Long)
  Property Get MouseIcon <54> () As IDispatch
  Property Set PutRef_MouseIcon <54> (ByVal MouseIcon As IDispatch)
  Property Get PictureType <50> () As Long
  Property Set PictureType <50> (ByVal PictureType As Long)
  Property Get Picture <49> () As IDispatch
  Property Get CellPicture <42> () As IDispatch
  Property Set PutRef_CellPicture <42> (ByVal CellPicture As IDispatch)
  Method AboutBox <-552> ()
  Property Get TextArray <55> (ByVal index As Long) As WString
  Property Set TextArray <55> (ByVal index As Long, ByVal TextArray As WString)
  Property Get ColAlignment <56> (ByVal index As Long) As Integer
  Property Set ColAlignment <56> (ByVal index As Long, ByVal ColAlignment As Integer)
  Property Get ColWidth <57> (ByVal index As Long) As Long
  Property Set ColWidth <57> (ByVal index As Long, ByVal ColWidth As Long)
  Property Get RowHeight <58> (ByVal index As Long) As Long
  Property Set RowHeight <58> (ByVal index As Long, ByVal RowHeight As Long)
  Property Get MergeRow <59> (ByVal index As Long) As Integer
  Property Set MergeRow <59> (ByVal index As Long, ByVal MergeRow As Integer)
  Property Get MergeCol <60> (ByVal index As Long) As Integer
  Property Set MergeCol <60> (ByVal index As Long, ByVal MergeCol As Integer)
  Property Set RowPosition <61> (ByVal index As Long, ByVal Rhs As Long)
  Property Set ColPosition <62> (ByVal index As Long, ByVal Rhs As Long)
  Property Get RowData <63> (ByVal index As Long) As Long
  Property Set RowData <63> (ByVal index As Long, ByVal RowData As Long)
  Property Get ColData <64> (ByVal index As Long) As Long
  Property Set ColData <64> (ByVal index As Long, ByVal ColData As Long)
  Property Get TextMatrix <65> (ByVal Row As Long, ByVal Col As Long) As WString
  Property Set TextMatrix <65> (ByVal Row As Long, ByVal Col As Long, ByVal TextMatrix As WString)
  Method AddItem <66> (Byval Item As WString, Opt Byval index As Variant)
  Method RemoveItem <67> (Byval index As Long)
  Method Clear <68> ()
  Method Refresh <-550> ()
  Property Get DataSource <76> () As IRowCursor
  Property Set DataSource <76> (ByVal DataSource As IRowCursor)
  Property Get RowIsVisible <85> (ByVal index As Long) As Integer
  Property Get ColIsVisible <86> (ByVal index As Long) As Integer
  Property Get RowPos <87> (ByVal index As Long) As Long
  Property Get ColPos <88> (ByVal index As Long) As Long
  Property Get GridLineWidth <89> () As Integer
  Property Set GridLineWidth <89> (ByVal GridLineWidth As Integer)
  Property Get FixedAlignment <90> (ByVal index As Long) As Integer
  Property Set FixedAlignment <90> (ByVal index As Long, ByVal FixedAlignment As Integer)
  Property Get FontName <91> () As WString
  Property Set FontName <91> (ByVal FontName As WString)
  Property Get FontSize <92> () As Single
  Property Set FontSize <92> (ByVal FontSize As Single)
  Property Get FontBold <93> () As Integer
  Property Set FontBold <93> (ByVal FontBold As Integer)
  Property Get FontItalic <94> () As Integer
  Property Set FontItalic <94> (ByVal FontItalic As Integer)
  Property Get FontStrikethru <95> () As Integer
  Property Set FontStrikethru <95> (ByVal FontStrikethru As Integer)
  Property Get FontUnderline <96> () As Integer
  Property Set FontUnderline <96> (ByVal FontUnderline As Integer)
  Property Get RightToLeft <-611> () As Integer
  Property Set RightToLeft <-611> (ByVal RightToLeft As Integer)
  Property Get OLEDropMode <1551> () As Long
  Property Set OLEDropMode <1551> (ByVal psOLEDropMode As Long)
  Method OLEDrag <1552> ()
End Interface

' Interface Name  : DMSFlexGridEvents
' Description     : Event interface for Microsoft FlexGrid Control
' ClassID         : $CLSID_Event_DMSFlexGridEvents
' ProgID          : $PROGID_MSFlexGrid
' Version ProgID  : $PROGID_MSFlexGrid1
Class Class_DMSFlexGridEvents $CLSID_Event_DMSFlexGridEvents As Event
  Interface DMSFlexGridEvents $IID_DMSFlexGridEvents
    Inherit IDispatch

    Method Click <-600> ()
      ' Insert your code here
    End Method

    Method KeyDown <-602> (ByRef KeyCode As Integer, ByVal PB_Shift As Integer)
      ' Insert your code here
    End Method

    Method DblClick <-601> ()
      MsgBox("You Double Clicked In The Grid!")
    End Method

    Method KeyPress <-603> (ByRef KeyAscii As Integer)
      MsgBox("You Pressed The " & Chr$(KeyAscii) & " Key!")
    End Method

    Method KeyUp <-604> (ByRef KeyCode As Integer, ByVal PB_Shift As Integer)
      ' Insert your code here
    End Method

    Method MouseDown <-605> (ByVal Button As Integer, ByVal PB_Shift As Integer, ByVal x As Long, ByVal y As Long)
      ' Insert your code here
    End Method

    Method MouseMove <-606> (ByVal Button As Integer, ByVal PB_Shift As Integer, ByVal x As Long, ByVal y As Long)
      ' Insert your code here
    End Method

    Method MouseUp <-607> (ByVal Button As Integer, ByVal PB_Shift As Integer, ByVal x As Long, ByVal y As Long)
      ' Insert your code here
    End Method

    Method SelChange <69> ()
      ' Insert your code here
    End Method

    Method RowColChange <70> ()
      ' Insert your code here
    End Method

    Method EnterCell <71> ()
      ' Insert your code here
    End Method

    Method LeaveCell <72> ()
      ' Insert your code here
    End Method

    Method Scroll <73> ()
      ' Insert your code here
    End Method

    Method Compare <74> (ByVal Row1 As Long, ByVal Row2 As Long, ByRef Cmp As Integer)
      ' Insert your code here
    End Method

    Method OLEStartDrag <1550> (ByRef InOut GridData As IDispatch, ByRef InOut AllowedEffects As Long)
      ' Insert your code here
    End Method

    Method OLEGiveFeedback <1551> (ByRef InOut Effect As Long, ByRef InOut DefaultCursors As Integer)
      ' Insert your code here
    End Method

    Method OLESetData <1552> (ByRef InOut GridData As IDispatch, ByRef InOut DataFormat As Integer)
      ' Insert your code here
    End Method

    Method OLECompleteDrag <1553> (ByRef InOut Effect As Long)
      ' Insert your code here
    End Method

    Method OLEDragOver <1554> (ByRef InOut GridData As IDispatch, ByRef InOut Effect As Long, ByRef InOut Button As Integer, ByRef InOut iShift As Integer, ByRef InOut x As Single, ByRef InOut y As Single, ByRef InOut _
    State As Integer)
      ' Insert your code here
    End Method

    Method OLEDragDrop <1555> (ByRef InOut GridData As IDispatch, ByRef InOut Effect As Long, ByRef InOut Button As Integer, ByRef InOut iShift As Integer, ByRef InOut x As Single, ByRef InOut y As Single)
      ' Insert your code here
    End Method

  End Interface
End Class


     To get the above program working for you all you need to do - so far as I know, is use your license key on your 'Machine Licensed' Workstation instead of mine up in fnWndProc_OnCreate(), have the MSFlxGrd.OCX ActiveX Control registered on your system, and have Atl71.dll somewhere in your path.  If you've done that, I expect an executable produced by you should be able to be run on another machine if MSFlxGrd is copied and registered there.  Here would be the dependencies for the above program ...


MSFlexGrid1.exe     22 K
Atl71.dll           87 K
MSFlxGrd.ocx       255 K
========================
                   364 K


Frederick J. Harris

#2
... continued...

     In terms of alterations made by me to the include file above, other than the 'data' and Shift' reserved keyword issue previously mentioned, I added a MsgBox to the KepPress() and DblClick() Event Procedures so you can see that they are working.

     The last thing I'll mention about the above code is that there are three declares up top.  These are for Atl71.dll.  I changed an argument in AtlAxCreateControlLic().  Its the 3rd one.  That's actually supposed to be 'pStream As IStream', not pStream As IUnknown.  But I wanted this to work with the PowerBASIC includes and the IStream interface isn't defined there.  The argument can be left NULL in the function if it isn't used, so changing it from IStream to IUnknown was workable in this instance.  Like with the IClassFactory2 interface, it is correctly defined in Jose Roca's includes.  Which is our next stop!

     This next version of the above program is exactly the same as the last in terms of what it looks like at runtime, but its coding is considerably different.  Jose Roca coded an Active X Control Container in PowerBASIC implemented in "OleCon.inc".  With this, you won't need Atl71.dll or the declares for those functions.  Download Jose's extended include file set and you'll have it.  I include the files in a directory next to my PowerBASIC installation's WinApi directory, and I name the directory the files are in WinApiEx.  In the PowerBASIC IDE go to ...

Window >>>> Options ...

...and when the tabbed dialog comes up click on the 'Compiler' tab.  Delete the directory there and use the choose folder dialog to highlight the folder in which you unpacked Jose's includes.  Then you are ready to go.  You can easily undo this when you want to return to the PowerBASIC includes.   With Jose's coding, you can forego all those strange Atl functions, and simply create the control with a call to CreateWindowEx() ...


'MSFlexGrid2.bas
#Compile              Exe  "MSFlexGrid2"
%UNICODE              = 1
#If %Def(%UNICODE)
    Macro ZStr        = WStringz
    Macro BStr        = WString
    %SIZEOF_CHAR      = 2
#Else
    Macro ZStr        = Asciiz
    Macro BStr        = String
    %SIZEOF_CHAR      = 1
#EndIf
#Include              "Windows.inc"
#Include              "OleCon.inc"
#Include Once         "MSFlexGridLib2.inc"
#Include Once         "MSFlexGridLibEvents2.inc"
%ID_CONTAINER         = 2000

Macro  CObj           (pUnk, dwAddr) = Poke Dword, Varptr(pUnk), dwAddr

Type WndEventArgs
  wParam              As Long
  lParam              As Long
  hWnd                As Dword
  hInst               As Dword
End Type


Sub GridSetup(Byref pGrid As IMSFlexGrid)
  pGrid.FontName      = "Times New Roman"
  pGrid.FontSize      = 10
  pGrid.Cols          = 4
  pGrid.Rows          = 20
  pGrid.ColWidth(0)   = 200
  pGrid.ColWidth(1)   = 1400
  pGrid.ColWidth(2)   = 1400
  pGrid.ColWidth(3)   = 1400
  pGrid.Col           = 1
  pGrid.Row           = 0
  pGrid.Text          = "Column 1"
  pGrid.Col           = 2
  pGrid.Text          = "Column 2"
  pGrid.Col           = 3
  pGrid.Text          = "Column 3"
End Sub


Function fnWndProc_OnCreate(Wea As WndEventArgs) As Long
  Local lpCreateStruct As CREATESTRUCT Ptr
  Local pEvents As DMSFlexGridEventsImpl
  Local pGrid As IMSFlexGrid
  Local hCtl As Dword

  lpCreateStruct=Wea.lParam : Wea.hInst=@lpCreateStruct.hInstance
  Call OC_WinInit()
  hCtl=CreateWindowEx _
  ( _
    0, _
    $OC_ClassNAME, _
    "MSFlexGridLib.MSFlexGrid;RTLKEY:72E67120-5959-11cf-91F6-C2863C385E30", _
    %WS_CHILD OR %WS_VISIBLE, _
    10, _
    10, _
    280, _
    250, _
    Wea.hWnd, _
    %ID_CONTAINER, _
    Wea.hInst, _
    Byval %NULL _
  )
  pGrid=OC_GetDispatch(hCtl)
  pGrid.AddRef()
  SetWindowLong(Wea.hWnd,0,Objptr(pGrid))
  If IsObject(pGrid) Then
     pEvents = Class "CDMSFlexGridEvents"
     If IsObject(pEvents) Then
        SetWindowLong(Wea.hWnd,4,Objptr(pEvents))
        Events From pGrid Call pEvents
        Call GridSetup(pGrid)
     Else
        pGrid=Nothing
     End If
  End If

  fnWndProc_OnCreate=0
End Function


Function fnWndProc_OnDestroy(Wea As WndEventArgs) As Long
  Local pEvents As DMSFlexGridEventsImpl
  Local pGrid As IMSFlexGrid
  Local dwObj As Dword

  dwObj=GetWindowLong(Wea.hWnd,4)
  CObj(pEvents,dwObj)
  If dwObj Then
     Events End pEvents
     Set pEvents=Nothing
     dwObj=0
  End If
  dwObj=GetWindowLong(Wea.hWnd,0)
  If dwObj Then
     CObj(pGrid,dwObj)
     Set pGrid=Nothing
  End If
  Call PostQuitMessage(0)

  fnWndProc_OnDestroy=0
End Function


Function fnWndProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  Local Wea As WndEventArgs

  Select Case As Long wMsg
    Case %WM_CREATE
      Wea.hWnd=hWnd : Wea.wParam=wParam : Wea.lParam=lParam
      fnWndProc=fnWndProc_OnCreate(Wea)
      Exit Function
    Case %WM_DESTROY
      Call PostQuitMessage(0)
      fnWndProc=fnWndProc_OnDestroy(Wea)
      Exit Function
  End Select

  fnWndProc=DefWindowProc(hWnd,wMsg,wParam,lParam)
End Function


Function WinMain(ByVal hInstance As Long, ByVal hPrevIns As Long, ByVal lpCmdLn As WStringz Ptr, ByVal iShow As Long) As Long
  Local szAppName As WStringz*16
  Local wc As WNDCLASSEX
  Local Msg As tagMsg
  Local hWnd As Dword

  szAppName="OCX Test"
  wc.lpszClassName=VarPtr(szAppName)                : wc.lpfnWndProc=CodePtr(fnWndProc)
  wc.cbSize=SizeOf(wc)                              : wc.cbWndExtra=8
  wc.hInstance=hInstance                            : wc.hIcon=LoadIcon(%NULL,ByVal %IDI_APPLICATION)
  wc.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW)    : wc.hbrBackground=%COLOR_BTNFACE+1
  Call RegisterClassEx(wc)
  hWnd=CreateWindow(szAppName,"Jose's MSFlexGrid",%WS_OVERLAPPEDWINDOW Xor %WS_MAXIMIZEBOX,200,100,310,310,0,0,hInstance,ByVal 0)
  Call ShowWindow(hWnd,iShow)
  While GetMessage(Msg,%NULL,0,0)
    TranslateMessage Msg
    DispatchMessage Msg
  Wend

  Function=msg.wParam
End Function


Jose's TypeLib Browser produces these two include files.  Jose seperates the 'incoming' and 'outgoing' interfaces...

Frederick J. Harris

#3
This is so massive I can't get it all in one post.  So I'm breaking MSFlexGridLib.inc into four posts...


'MSFlexGridLib.inc
' ########################################################################################
' Library name: MSFlexGridLib
' Version: 1.0, Locale ID = 0
' Description: Microsoft FlexGrid Control 6.0 (SP6)
' Path: C:\Windows\SysWow64\MSFLXGRD.OCX
' Library GUID: {5E9E78A0-531B-11CF-91F6-C2863C385E30}
' Help file: C:\Windows\HELP\MSHFlx98.chm
' License key: 72E67120-5959-11cf-91F6-C2863C385E30
' Code generated by the TypeLib Browser 5.0.1 (c) 2011 by José Roca
' Date: 05 Sep 2014   Time: 09:16:28
' Options used to generate the code:
' - Use METHOD and PROPERTY GET/SET statements
' - Use SET_ instead of PUT_ as prefix
' - Use parameter names in interface declarations
' - Add prefix in parameter names
' - Use interface names with external objects
' - Use enumeration names as prefix in constants
' - Include dispatch only interfaces
' - Retrieve license key
' ########################################################################################

' ========================================================================================
' CoClass name: DataObject
' ========================================================================================
' CLSID (Class identifier): {2334D2B2-713E-11CF-8AE5-00AA00C00905}
' Default interface: IVBDataObject
' Default interface IID: {2334D2B1-713E-11CF-8AE5-00AA00C00905}
' Implemented interfaces:
'  IVBDataObject (default interface)
' ========================================================================================

' ========================================================================================
' CoClass name: DataObjectFiles
' ========================================================================================
' CLSID (Class identifier): {2334D2B4-713E-11CF-8AE5-00AA00C00905}
' Default interface: IVBDataObjectFiles
' Default interface IID: {2334D2B3-713E-11CF-8AE5-00AA00C00905}
' Implemented interfaces:
'  IVBDataObjectFiles (default interface)
' ========================================================================================

' ========================================================================================
' CoClass name: MSFlexGrid
' ========================================================================================
' CLSID (Class identifier): {6262D3A0-531B-11CF-91F6-C2863C385E30}
' Help string: Microsoft FlexGrid Control 6.0 (SP6)
' Attributes: 38 [&H00000026] [Cancreate] [Licensed] [Control]
' ProgID (Program identifier): MSFlexGridLib.MSFlexGrid.1
' Version independent ProgID: MSFlexGridLib.MSFlexGrid
' Default interface: IMSFlexGrid
' Default interface IID: {5F4DF280-531B-11CF-91F6-C2863C385E30}
' Default events interface: DMSFlexGridEvents
' Default events interface IID: {609602E0-531B-11CF-91F6-C2863C385E30}
' Implemented interfaces:
'  IMSFlexGrid (default interface)
'  DMSFlexGridEvents (default events interface)
' ========================================================================================

' ========================================================================================
' ProgIDs (Program identifiers)
' ========================================================================================

' CLSID = {6262D3A0-531B-11CF-91F6-C2863C385E30}
$PROGID_MSFlexGrid1 = "MSFlexGridLib.MSFlexGrid.1"

' ========================================================================================
' Version independent ProgIDs
' ========================================================================================

' CLSID = {6262D3A0-531B-11CF-91F6-C2863C385E30}
$PROGID_MSFlexGrid = "MSFlexGridLib.MSFlexGrid"

' ========================================================================================
' ClsIDs (Class identifiers)
' ========================================================================================

$CLSID_DataObject = GUID$("{2334D2B2-713E-11CF-8AE5-00AA00C00905}")
$CLSID_DataObjectFiles = GUID$("{2334D2B4-713E-11CF-8AE5-00AA00C00905}")
$CLSID_MSFlexGrid = GUID$("{6262D3A0-531B-11CF-91F6-C2863C385E30}")

' ========================================================================================
' IIDs (Interface identifiers)
' ========================================================================================

$IID_DMSFlexGridEvents = GUID$("{609602E0-531B-11CF-91F6-C2863C385E30}")
$IID_IMSFlexGrid = GUID$("{5F4DF280-531B-11CF-91F6-C2863C385E30}")
$IID_IRowCursor = GUID$("{9F6AA700-D188-11CD-AD48-00AA003C9CB6}")
$IID_IVBDataObject = GUID$("{2334D2B1-713E-11CF-8AE5-00AA00C00905}")
$IID_IVBDataObjectFiles = GUID$("{2334D2B3-713E-11CF-8AE5-00AA00C00905}")

' ========================================================================================
' OLEDragConstants enum
' IID: {D8898460-742F-11CF-8AEA-00AA00C00905}
' Constants for the OLEDragMode property (but not the DragMode or OLEDropMode properties).
' ========================================================================================

ENUM OLEDragConstants
   flexOLEDragManual                                    = 0            ' &H00000000
   flexOLEDragAutomatic                                 = 1            ' &H00000001
END ENUM

' ========================================================================================
' OLEDropConstants enum
' IID: {D8898461-742F-11CF-8AEA-00AA00C00905}
' Constants for the OLEDropMode property (but not the DragMode or OLEDragMode properties).
' ========================================================================================

ENUM OLEDropConstants
   flexOLEDropNone                                      = 0            ' &H00000000
   flexOLEDropManual                                    = 1            ' &H00000001
END ENUM

' ========================================================================================
' DragOverConstants enum
' IID: {D8898464-742F-11CF-8AEA-00AA00C00905}
' State transition constants for the DragOver and OLEDragOver events.
' ========================================================================================

ENUM DragOverConstants
   flexEnter                                            = 0            ' &H00000000
   flexLeave                                            = 1            ' &H00000001
   flexOver                                             = 2            ' &H00000002
END ENUM

' ========================================================================================
' ClipBoardConstants enum
' IID: {D8898462-742F-11CF-8AEA-00AA00C00905}
' Clipboard format constants.
' ========================================================================================

ENUM ClipBoardConstants
   flexCFText                                           = 1            ' &H00000001
   flexCFBitmap                                         = 2            ' &H00000002
   flexCFMetafile                                       = 3            ' &H00000003
   flexCFDIB                                            = 8            ' &H00000008
   flexCFPalette                                        = 9            ' &H00000009
   flexCFEMetafile                                      = 14           ' &H0000000E
   flexCFFiles                                          = 15           ' &H0000000F
   flexCFRTF                                            = -16639       ' &HFFFFBF01
END ENUM

' ========================================================================================
' OLEDropEffectConstants enum
' IID: {D8898463-742F-11CF-8AEA-00AA00C00905}
' Drop effect constants for OLE drag and drop events.
' ========================================================================================

ENUM OLEDropEffectConstants
   flexOLEDropEffectNone                                = 0            ' &H00000000
   flexOLEDropEffectCopy                                = 1            ' &H00000001
   flexOLEDropEffectMove                                = 2            ' &H00000002
   flexOLEDropEffectScroll                              = -2147483648  ' &H80000000
END ENUM

' ========================================================================================
' ErrorConstants enum
' Error constants
' ========================================================================================

ENUM ErrorConstants
   flexerrIllegaFunctionCall                            = 5            ' &H00000005
   flexerrObjIllegalUse                                 = 425          ' &H000001A9
   flexerrClipInvalidFormat                             = 461          ' &H000001CD
   flexerrDataObjectLocked                              = 672          ' &H000002A0
   flexerrExpectedAnArgument                            = 673          ' &H000002A1
   flexerrRecursiveOLEDrag                              = 674          ' &H000002A2
   flexerrUserFormatNotBinArray                         = 675          ' &H000002A3
   flexerrDataNotSetForFormat                           = 676          ' &H000002A4
   flexerrUnknownError                                  = 600          ' &H00000258
   flexerrSubscript                                     = 381          ' &H0000017D
   flexerrBadValue                                      = 380          ' &H0000017C
   flexerrGetNotSupported                               = 394          ' &H0000018A
   flexerrSetNotPermitted                               = 387          ' &H00000183
   flexerrOutOfMemory                                   = 7            ' &H00000007
   flexerrVB30000                                       = 30000        ' &H00007530
   flexerrVB30001                                       = 30001        ' &H00007531
   flexerrVB30002                                       = 30002        ' &H00007532
   flexerrVB30004                                       = 30004        ' &H00007534
   flexerrVB30005                                       = 30005        ' &H00007535
   flexerrVB30006                                       = 30006        ' &H00007536
   flexerrVB30008                                       = 30008        ' &H00007538
   flexerrVB30009                                       = 30009        ' &H00007539
   flexerrVB30010                                       = 30010        ' &H0000753A
   flexerrVB30011                                       = 30011        ' &H0000753B
   flexerrVB30013                                       = 30013        ' &H0000753D
   flexerrVB30014                                       = 30014        ' &H0000753E
   flexerrVB30015                                       = 30015        ' &H0000753F
   flexerrVB30016                                       = 30016        ' &H00007540
   flexerrVB30017                                       = 30017        ' &H00007541
END ENUM

' ========================================================================================
' AppearanceSettings enum
' Appearance Constants
' ========================================================================================

ENUM AppearanceSettings
   flexFlat                                             = 0            ' &H00000000
   flex3D                                               = 1            ' &H00000001
END ENUM

' ========================================================================================
' BorderStyleSettings enum
' BorderStyle Constants
' ========================================================================================

ENUM BorderStyleSettings
   flexBorderNone                                       = 0            ' &H00000000
   flexBorderSingle                                     = 1            ' &H00000001
END ENUM

' ========================================================================================
' FocusRectSettings enum
' FocusRect Constants
' ========================================================================================

ENUM FocusRectSettings
   flexFocusNone                                        = 0            ' &H00000000
   flexFocusLight                                       = 1            ' &H00000001
   flexFocusHeavy                                       = 2            ' &H00000002
END ENUM

' ========================================================================================
' HighLightSettings enum
' Highlight Constants
' ========================================================================================

ENUM HighLightSettings
   flexHighlightNever                                   = 0            ' &H00000000
   flexHighlightAlways                                  = 1            ' &H00000001
   flexHighlightWithFocus                               = 2            ' &H00000002
END ENUM

' ========================================================================================
' ScrollBarsSettings enum
' ScrollBars Constants
' ========================================================================================

ENUM ScrollBarsSettings
   flexScrollBarNone                                    = 0            ' &H00000000
   flexScrollBarHorizontal                              = 1            ' &H00000001
   flexScrollBarVertical                                = 2            ' &H00000002
   flexScrollBarBoth                                    = 3            ' &H00000003
END ENUM

' ========================================================================================
' TextStyleSettings enum
' TextStyle Constants
' ========================================================================================

ENUM TextStyleSettings
   flexTextFlat                                         = 0            ' &H00000000
   flexTextRaised                                       = 1            ' &H00000001
   flexTextInset                                        = 2            ' &H00000002
   flexTextRaisedLight                                  = 3            ' &H00000003
   flexTextInsetLight                                   = 4            ' &H00000004
END ENUM

' ========================================================================================
' FillStyleSettings enum
' FillStyle Constants
' ========================================================================================

ENUM FillStyleSettings
   flexFillSingle                                       = 0            ' &H00000000
   flexFillRepeat                                       = 1            ' &H00000001
END ENUM

' ========================================================================================
' GridLineSettings enum
' GridLines Constants
' ========================================================================================

ENUM GridLineSettings
   flexGridNone                                         = 0            ' &H00000000
   flexGridFlat                                         = 1            ' &H00000001
   flexGridInset                                        = 2            ' &H00000002
   flexGridRaised                                       = 3            ' &H00000003
END ENUM

' ========================================================================================
' SelectionModeSettings enum
' SelectionMode Constants
' ========================================================================================

ENUM SelectionModeSettings
   flexSelectionFree                                    = 0            ' &H00000000
   flexSelectionByRow                                   = 1            ' &H00000001
   flexSelectionByColumn                                = 2            ' &H00000002
END ENUM

' ========================================================================================
' MergeCellsSettings enum
' MergeCells Constants
' ========================================================================================

ENUM MergeCellsSettings
   flexMergeNever                                       = 0            ' &H00000000
   flexMergeFree                                        = 1            ' &H00000001
   flexMergeRestrictRows                                = 2            ' &H00000002
   flexMergeRestrictColumns                             = 3            ' &H00000003
   flexMergeRestrictAll                                 = 4            ' &H00000004
END ENUM

' ========================================================================================
' PictureTypeSettings enum
' PictureType Constants
' ========================================================================================

ENUM PictureTypeSettings
   flexPictureColor                                     = 0            ' &H00000000
   flexPictureMonochrome                                = 1            ' &H00000001
END ENUM

' ========================================================================================
' AllowUserResizeSettings enum
' AllowUserResizing Constants
' ========================================================================================

ENUM AllowUserResizeSettings
   flexResizeNone                                       = 0            ' &H00000000
   flexResizeColumns                                    = 1            ' &H00000001
   flexResizeRows                                       = 2            ' &H00000002
   flexResizeBoth                                       = 3            ' &H00000003
END ENUM

' ========================================================================================
' MousePointerSettings enum
' MousePointer Constants
' ========================================================================================

ENUM MousePointerSettings
   flexDefault                                          = 0            ' &H00000000
   flexArrow                                            = 1            ' &H00000001
   flexCross                                            = 2            ' &H00000002
   flexIBeam                                            = 3            ' &H00000003
   flexIcon                                             = 4            ' &H00000004
   flexSize                                             = 5            ' &H00000005
   flexSizeNESW                                         = 6            ' &H00000006
   flexSizeNS                                           = 7            ' &H00000007
   flexSizeNWSE                                         = 8            ' &H00000008
   flexSizeEW                                           = 9            ' &H00000009
   flexUpArrow                                          = 10           ' &H0000000A
   flexHourglass                                        = 11           ' &H0000000B
   flexNoDrop                                           = 12           ' &H0000000C
   flexArrowHourGlass                                   = 13           ' &H0000000D
   flexArrowQuestion                                    = 14           ' &H0000000E
   flexSizeAll                                          = 15           ' &H0000000F
   flexCustom                                           = 99           ' &H00000063
END ENUM

' ========================================================================================
' SortSettings enum
' Sort Constants
' ========================================================================================

ENUM SortSettings
   flexSortNone                                         = 0            ' &H00000000
   flexSortGenericAscending                             = 1            ' &H00000001
   flexSortGenericDescending                            = 2            ' &H00000002
   flexSortNumericAscending                             = 3            ' &H00000003
   flexSortNumericDescending                            = 4            ' &H00000004
   flexSortStringNoCaseAscending                        = 5            ' &H00000005
   flexSortStringNoCaseDescending                       = 6            ' &H00000006
   flexSortStringAscending                              = 7            ' &H00000007
   flexSortStringDescending                             = 8            ' &H00000008
END ENUM

' ========================================================================================
' AlignmentSettings enum
' Alignment Constants
' ========================================================================================

ENUM AlignmentSettings
   flexAlignLeftTop                                     = 0            ' &H00000000
   flexAlignLeftCenter                                  = 1            ' &H00000001
   flexAlignLeftBottom                                  = 2            ' &H00000002
   flexAlignCenterTop                                   = 3            ' &H00000003
   flexAlignCenterCenter                                = 4            ' &H00000004
   flexAlignCenterBottom                                = 5            ' &H00000005
   flexAlignRightTop                                    = 6            ' &H00000006
   flexAlignRightCenter                                 = 7            ' &H00000007
   flexAlignRightBottom                                 = 8            ' &H00000008
   flexAlignGeneral                                     = 9            ' &H00000009
END ENUM

' ########################################################################################
' Interface name = IVBDataObject
' IID = {2334D2B1-713E-11CF-8AE5-00AA00C00905}
' Attributes = 4304 [&H000010D0] [Hidden] [Dual] [Nonextensible] [Dispatchable]
' Inherited interface = IDispatch
' ########################################################################################

#IF NOT %DEF(%IVBDataObject_INTERFACE_DEFINED)
    %IVBDataObject_INTERFACE_DEFINED = 1

INTERFACE IVBDataObject $IID_IVBDataObject

   INHERIT IDispatch

   ' =====================================================================================
   METHOD Clear <1> ( _                                 ' VTable offset = 28
   )                                                    ' void
   ' =====================================================================================
   METHOD GetData <2> ( _                               ' VTable offset = 32
     BYVAL prm_sFormat AS INTEGER _                     ' [in] sFormat VT_I2 <Integer>
   ) AS VARIANT                                         ' [retval][out] *pvData VT_VARIANT <Variant>
   ' =====================================================================================
   METHOD GetFormat <3> ( _                             ' VTable offset = 36
     BYVAL prm_sFormat AS INTEGER _                     ' [in] sFormat VT_I2 <Integer>
   ) AS INTEGER                                         ' [retval][out] *pbFormatSupported VT_BOOL <Integer>
   ' =====================================================================================
   METHOD SetData <4> ( _                               ' VTable offset = 40
     OPTIONAL BYVAL prm_vValue AS VARIANT _             ' [opt][in] vValue VT_VARIANT <Variant>
   , OPTIONAL BYVAL prm_vFormat AS VARIANT _            ' [opt][in] vFormat VT_VARIANT <Variant>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET Files <5> ( _                           ' VTable offset = 44
   ) AS IVBDataObjectFiles                              ' [retval][out] **pFiles IVBDataObjectFiles <dispinterface>
   ' =====================================================================================

END INTERFACE

#ENDIF   ' /* __IVBDataObject_INTERFACE_DEFINED__ */

' ########################################################################################
' Interface name = IVBDataObjectFiles
' IID = {2334D2B3-713E-11CF-8AE5-00AA00C00905}
' Attributes = 4304 [&H000010D0] [Hidden] [Dual] [Nonextensible] [Dispatchable]
' Inherited interface = IDispatch
' ########################################################################################

#IF NOT %DEF(%IVBDataObjectFiles_INTERFACE_DEFINED)
    %IVBDataObjectFiles_INTERFACE_DEFINED = 1

INTERFACE IVBDataObjectFiles $IID_IVBDataObjectFiles

   INHERIT IDispatch

   ' =====================================================================================
   PROPERTY GET Item <0> ( _                            ' VTable offset = 28
     BYVAL prm_lIndex AS LONG _                         ' [in] lIndex VT_I4 <Long>
   ) AS WSTRING                                         ' [retval][out] *bstrItem VT_BSTR
   ' =====================================================================================
   PROPERTY GET Count <1> ( _                           ' VTable offset = 32
   ) AS LONG                                            ' [retval][out] *plCount VT_I4 <Long>
   ' =====================================================================================
   METHOD Add <2> ( _                                   ' VTable offset = 36
     BYVAL prm_bstrFilename AS WSTRING _                ' [in] bstrFilename VT_BSTR
   , OPTIONAL BYVAL prm_vIndex AS VARIANT _             ' [opt][in] vIndex VT_VARIANT <Variant>
   )                                                    ' void
   ' =====================================================================================
   METHOD Clear <3> ( _                                 ' VTable offset = 40
   )                                                    ' void
   ' =====================================================================================
   METHOD Remove <4> ( _                                ' VTable offset = 44
     BYVAL prm_vIndex AS VARIANT _                      ' [in] vIndex VT_VARIANT <Variant>
   )                                                    ' void
   ' =====================================================================================
   METHOD NewEnum_ <-4> ( _                             ' VTable offset = 48
   ) AS IUnknown                                        ' [retval][out] **ppUnk VT_UNKNOWN <IUnknown>
   ' =====================================================================================

END INTERFACE

#ENDIF   ' /* __IVBDataObjectFiles_INTERFACE_DEFINED__ */

' ########################################################################################
' Interface name = IRowCursor
' IID = {9F6AA700-D188-11CD-AD48-00AA003C9CB6}
' Attributes = 4176 [&H00001050] [Hidden] [Dual] [Dispatchable]
' Inherited interface = IDispatch
' ########################################################################################

#IF NOT %DEF(%IRowCursor_INTERFACE_DEFINED)
    %IRowCursor_INTERFACE_DEFINED = 1

INTERFACE IRowCursor $IID_IRowCursor

   INHERIT IDispatch

END INTERFACE

#ENDIF   ' /* __IRowCursor_INTERFACE_DEFINED__ */


MSFlexGridLib.inc continued .....

Frederick J. Harris

#4
...MSFlexGridLib.inc continued - part 2 ...


' ########################################################################################
' Interface name = IMSFlexGrid
' IID = {5F4DF280-531B-11CF-91F6-C2863C385E30}
' Dispatch interface for Microsoft FlexGrid Control
' Attributes = 4304 [&H000010D0] [Hidden] [Dual] [Nonextensible] [Dispatchable]
' Inherited interface = IDispatch
' ########################################################################################

#IF NOT %DEF(%IMSFlexGrid_INTERFACE_DEFINED)
    %IMSFlexGrid_INTERFACE_DEFINED = 1

INTERFACE IMSFlexGrid $IID_IMSFlexGrid

   INHERIT IDispatch

   ' =====================================================================================
   PROPERTY GET Rows <4> ( _                            ' VTable offset = 28
   ) AS LONG                                            ' [retval][out] *Rows VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET Rows <4> ( _                            ' VTable offset = 32
     BYVAL prm_Rows AS LONG _                           ' [in] Rows VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET Cols <5> ( _                            ' VTable offset = 36
   ) AS LONG                                            ' [retval][out] *Cols VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET Cols <5> ( _                            ' VTable offset = 40
     BYVAL prm_Cols AS LONG _                           ' [in] Cols VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET FixedRows <6> ( _                       ' VTable offset = 44
   ) AS LONG                                            ' [retval][out] *FixedRows VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET FixedRows <6> ( _                       ' VTable offset = 48
     BYVAL prm_FixedRows AS LONG _                      ' [in] FixedRows VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET FixedCols <7> ( _                       ' VTable offset = 52
   ) AS LONG                                            ' [retval][out] *FixedCols VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET FixedCols <7> ( _                       ' VTable offset = 56
     BYVAL prm_FixedCols AS LONG _                      ' [in] FixedCols VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET Version <1> ( _                         ' VTable offset = 60
   ) AS INTEGER                                         ' [retval][out] *Version VT_I2 <Integer>
   ' =====================================================================================
   PROPERTY GET FormatString <2> ( _                    ' VTable offset = 64
   ) AS WSTRING                                         ' [retval][out] *FormatString VT_BSTR
   ' =====================================================================================
   PROPERTY SET FormatString <2> ( _                    ' VTable offset = 68
     BYVAL prm_FormatString AS WSTRING _                ' [in] FormatString VT_BSTR
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET TopRow <8> ( _                          ' VTable offset = 72
   ) AS LONG                                            ' [retval][out] *TopRow VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET TopRow <8> ( _                          ' VTable offset = 76
     BYVAL prm_TopRow AS LONG _                         ' [in] TopRow VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET LeftCol <9> ( _                         ' VTable offset = 80
   ) AS LONG                                            ' [retval][out] *LeftCol VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET LeftCol <9> ( _                         ' VTable offset = 84
     BYVAL prm_LeftCol AS LONG _                        ' [in] LeftCol VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET Row <10> ( _                            ' VTable offset = 88
   ) AS LONG                                            ' [retval][out] *Row VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET Row <10> ( _                            ' VTable offset = 92
     BYVAL prm_Row AS LONG _                            ' [in] Row VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET Col <11> ( _                            ' VTable offset = 96
   ) AS LONG                                            ' [retval][out] *Col VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET Col <11> ( _                            ' VTable offset = 100
     BYVAL prm_Col AS LONG _                            ' [in] Col VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET RowSel <12> ( _                         ' VTable offset = 104
   ) AS LONG                                            ' [retval][out] *RowSel VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET RowSel <12> ( _                         ' VTable offset = 108
     BYVAL prm_RowSel AS LONG _                         ' [in] RowSel VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET ColSel <13> ( _                         ' VTable offset = 112
   ) AS LONG                                            ' [retval][out] *ColSel VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET ColSel <13> ( _                         ' VTable offset = 116
     BYVAL prm_ColSel AS LONG _                         ' [in] ColSel VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET Text <0> ( _                            ' VTable offset = 120
   ) AS WSTRING                                         ' [retval][out] *Text VT_BSTR
   ' =====================================================================================
   PROPERTY SET Text <0> ( _                            ' VTable offset = 124
     BYVAL prm_Text AS WSTRING _                        ' [in] Text VT_BSTR
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET BackColor <-501> ( _                    ' VTable offset = 128
   ) AS DWORD                                           ' [retval][out] *BackColor OLE_COLOR <alias> <VT_UI4>
   ' =====================================================================================
   PROPERTY SET BackColor <-501> ( _                    ' VTable offset = 132
     BYVAL prm_BackColor AS DWORD _                     ' [in] BackColor OLE_COLOR <alias> <VT_UI4>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET ForeColor <-513> ( _                    ' VTable offset = 136
   ) AS DWORD                                           ' [retval][out] *ForeColor OLE_COLOR <alias> <VT_UI4>
   ' =====================================================================================
   PROPERTY SET ForeColor <-513> ( _                    ' VTable offset = 140
     BYVAL prm_ForeColor AS DWORD _                     ' [in] ForeColor OLE_COLOR <alias> <VT_UI4>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET BackColorFixed <14> ( _                 ' VTable offset = 144
   ) AS DWORD                                           ' [retval][out] *BackColorFixed OLE_COLOR <alias> <VT_UI4>
   ' =====================================================================================
   PROPERTY SET BackColorFixed <14> ( _                 ' VTable offset = 148
     BYVAL prm_BackColorFixed AS DWORD _                ' [in] BackColorFixed OLE_COLOR <alias> <VT_UI4>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET ForeColorFixed <15> ( _                 ' VTable offset = 152
   ) AS DWORD                                           ' [retval][out] *ForeColorFixed OLE_COLOR <alias> <VT_UI4>
   ' =====================================================================================
   PROPERTY SET ForeColorFixed <15> ( _                 ' VTable offset = 156
     BYVAL prm_ForeColorFixed AS DWORD _                ' [in] ForeColorFixed OLE_COLOR <alias> <VT_UI4>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET BackColorSel <16> ( _                   ' VTable offset = 160
   ) AS DWORD                                           ' [retval][out] *BackColorSel OLE_COLOR <alias> <VT_UI4>
   ' =====================================================================================
   PROPERTY SET BackColorSel <16> ( _                   ' VTable offset = 164
     BYVAL prm_BackColorSel AS DWORD _                  ' [in] BackColorSel OLE_COLOR <alias> <VT_UI4>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET ForeColorSel <17> ( _                   ' VTable offset = 168
   ) AS DWORD                                           ' [retval][out] *ForeColorSel OLE_COLOR <alias> <VT_UI4>
   ' =====================================================================================
   PROPERTY SET ForeColorSel <17> ( _                   ' VTable offset = 172
     BYVAL prm_ForeColorSel AS DWORD _                  ' [in] ForeColorSel OLE_COLOR <alias> <VT_UI4>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET BackColorBkg <18> ( _                   ' VTable offset = 176
   ) AS DWORD                                           ' [retval][out] *BackColorBkg OLE_COLOR <alias> <VT_UI4>
   ' =====================================================================================
   PROPERTY SET BackColorBkg <18> ( _                   ' VTable offset = 180
     BYVAL prm_BackColorBkg AS DWORD _                  ' [in] BackColorBkg OLE_COLOR <alias> <VT_UI4>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET WordWrap <19> ( _                       ' VTable offset = 184
   ) AS INTEGER                                         ' [retval][out] *WordWrap VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET WordWrap <19> ( _                       ' VTable offset = 188
     BYVAL prm_WordWrap AS INTEGER _                    ' [in] WordWrap VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET Font <-512> ( _                         ' VTable offset = 192
   ) AS IFontDisp                                       ' [retval][out] **Font IFontDisp <alias> Font
   ' =====================================================================================
   PROPERTY SET putref_Font <-512> ( _                  ' VTable offset = 196
     BYVAL prm_Font AS IFontDisp _                      ' [in] *Font IFontDisp <alias> Font
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET FontWidth <84> ( _                      ' VTable offset = 200
   ) AS SINGLE                                          ' [retval][out] *FontWidth VT_R4 <Single>
   ' =====================================================================================
   PROPERTY SET FontWidth <84> ( _                      ' VTable offset = 204
     BYVAL prm_FontWidth AS SINGLE _                    ' [in] FontWidth VT_R4 <Single>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET CellFontName <77> ( _                   ' VTable offset = 208
   ) AS WSTRING                                         ' [retval][out] *CellFontName VT_BSTR
   ' =====================================================================================
   PROPERTY SET CellFontName <77> ( _                   ' VTable offset = 212
     BYVAL prm_CellFontName AS WSTRING _                ' [in] CellFontName VT_BSTR
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET CellFontSize <78> ( _                   ' VTable offset = 216
   ) AS SINGLE                                          ' [retval][out] *CellFontSize VT_R4 <Single>
   ' =====================================================================================
   PROPERTY SET CellFontSize <78> ( _                   ' VTable offset = 220
     BYVAL prm_CellFontSize AS SINGLE _                 ' [in] CellFontSize VT_R4 <Single>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET CellFontBold <79> ( _                   ' VTable offset = 224
   ) AS INTEGER                                         ' [retval][out] *CellFontBold VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET CellFontBold <79> ( _                   ' VTable offset = 228
     BYVAL prm_CellFontBold AS INTEGER _                ' [in] CellFontBold VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET CellFontItalic <80> ( _                 ' VTable offset = 232
   ) AS INTEGER                                         ' [retval][out] *CellFontItalic VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET CellFontItalic <80> ( _                 ' VTable offset = 236
     BYVAL prm_CellFontItalic AS INTEGER _              ' [in] CellFontItalic VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET CellFontUnderline <81> ( _              ' VTable offset = 240
   ) AS INTEGER                                         ' [retval][out] *CellFontUnderline VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET CellFontUnderline <81> ( _              ' VTable offset = 244
     BYVAL prm_CellFontUnderline AS INTEGER _           ' [in] CellFontUnderline VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET CellFontStrikeThrough <82> ( _          ' VTable offset = 248
   ) AS INTEGER                                         ' [retval][out] *CellFontStrikeThrough VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET CellFontStrikeThrough <82> ( _          ' VTable offset = 252
     BYVAL prm_CellFontStrikeThrough AS INTEGER _       ' [in] CellFontStrikeThrough VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET CellFontWidth <83> ( _                  ' VTable offset = 256
   ) AS SINGLE                                          ' [retval][out] *CellFontWidth VT_R4 <Single>
   ' =====================================================================================
   PROPERTY SET CellFontWidth <83> ( _                  ' VTable offset = 260
     BYVAL prm_CellFontWidth AS SINGLE _                ' [in] CellFontWidth VT_R4 <Single>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET TextStyle <20> ( _                      ' VTable offset = 264
   ) AS LONG                                            ' [retval][out] *TextStyle TextStyleSettings <enum>
   ' =====================================================================================
   PROPERTY SET TextStyle <20> ( _                      ' VTable offset = 268
     BYVAL prm_TextStyle AS LONG _                      ' [in] TextStyle TextStyleSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET TextStyleFixed <21> ( _                 ' VTable offset = 272
   ) AS LONG                                            ' [retval][out] *TextStyleFixed TextStyleSettings <enum>
   ' =====================================================================================
   PROPERTY SET TextStyleFixed <21> ( _                 ' VTable offset = 276
     BYVAL prm_TextStyleFixed AS LONG _                 ' [in] TextStyleFixed TextStyleSettings <enum>
   )                                                    ' void
   ' =====================================================================================



Frederick J. Harris

#5
...continued MSFlexGridLib.inc - part 3 ...


PROPERTY GET ScrollTrack <22> ( _                    ' VTable offset = 280
   ) AS INTEGER                                         ' [retval][out] *ScrollTrack VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET ScrollTrack <22> ( _                    ' VTable offset = 284
     BYVAL prm_ScrollTrack AS INTEGER _                 ' [in] ScrollTrack VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET FocusRect <23> ( _                      ' VTable offset = 288
   ) AS LONG                                            ' [retval][out] *FocusRect FocusRectSettings <enum>
   ' =====================================================================================
   PROPERTY SET FocusRect <23> ( _                      ' VTable offset = 292
     BYVAL prm_FocusRect AS LONG _                      ' [in] FocusRect FocusRectSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET HighLight <24> ( _                      ' VTable offset = 296
   ) AS LONG                                            ' [retval][out] *HighLight HighLightSettings <enum>
   ' =====================================================================================
   PROPERTY SET HighLight <24> ( _                      ' VTable offset = 300
     BYVAL prm_HighLight AS LONG _                      ' [in] HighLight HighLightSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET Redraw <25> ( _                         ' VTable offset = 304
   ) AS INTEGER                                         ' [retval][out] *Redraw VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET Redraw <25> ( _                         ' VTable offset = 308
     BYVAL prm_Redraw AS INTEGER _                      ' [in] Redraw VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET ScrollBars <26> ( _                     ' VTable offset = 312
   ) AS LONG                                            ' [retval][out] *ScrollBars ScrollBarsSettings <enum>
   ' =====================================================================================
   PROPERTY SET ScrollBars <26> ( _                     ' VTable offset = 316
     BYVAL prm_ScrollBars AS LONG _                     ' [in] ScrollBars ScrollBarsSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET MouseRow <27> ( _                       ' VTable offset = 320
   ) AS LONG                                            ' [retval][out] *MouseRow VT_I4 <Long>
   ' =====================================================================================
   PROPERTY GET MouseCol <28> ( _                       ' VTable offset = 324
   ) AS LONG                                            ' [retval][out] *MouseCol VT_I4 <Long>
   ' =====================================================================================
   PROPERTY GET CellLeft <29> ( _                       ' VTable offset = 328
   ) AS LONG                                            ' [retval][out] *CellLeft VT_I4 <Long>
   ' =====================================================================================
   PROPERTY GET CellTop <30> ( _                        ' VTable offset = 332
   ) AS LONG                                            ' [retval][out] *CellTop VT_I4 <Long>
   ' =====================================================================================
   PROPERTY GET CellWidth <31> ( _                      ' VTable offset = 336
   ) AS LONG                                            ' [retval][out] *CellWidth VT_I4 <Long>
   ' =====================================================================================
   PROPERTY GET CellHeight <32> ( _                     ' VTable offset = 340
   ) AS LONG                                            ' [retval][out] *CellHeight VT_I4 <Long>
   ' =====================================================================================
   PROPERTY GET RowHeightMin <33> ( _                   ' VTable offset = 344
   ) AS LONG                                            ' [retval][out] *RowHeightMin VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET RowHeightMin <33> ( _                   ' VTable offset = 348
     BYVAL prm_RowHeightMin AS LONG _                   ' [in] RowHeightMin VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET FillStyle <-511> ( _                    ' VTable offset = 352
   ) AS LONG                                            ' [retval][out] *FillStyle FillStyleSettings <enum>
   ' =====================================================================================
   PROPERTY SET FillStyle <-511> ( _                    ' VTable offset = 356
     BYVAL prm_FillStyle AS LONG _                      ' [in] FillStyle FillStyleSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET GridLines <34> ( _                      ' VTable offset = 360
   ) AS LONG                                            ' [retval][out] *GridLines GridLineSettings <enum>
   ' =====================================================================================
   PROPERTY SET GridLines <34> ( _                      ' VTable offset = 364
     BYVAL prm_GridLines AS LONG _                      ' [in] GridLines GridLineSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET GridLinesFixed <35> ( _                 ' VTable offset = 368
   ) AS LONG                                            ' [retval][out] *GridLinesFixed GridLineSettings <enum>
   ' =====================================================================================
   PROPERTY SET GridLinesFixed <35> ( _                 ' VTable offset = 372
     BYVAL prm_GridLinesFixed AS LONG _                 ' [in] GridLinesFixed GridLineSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET GridColor <36> ( _                      ' VTable offset = 376
   ) AS DWORD                                           ' [retval][out] *GridColor OLE_COLOR <alias> <VT_UI4>
   ' =====================================================================================
   PROPERTY SET GridColor <36> ( _                      ' VTable offset = 380
     BYVAL prm_GridColor AS DWORD _                     ' [in] GridColor OLE_COLOR <alias> <VT_UI4>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET GridColorFixed <37> ( _                 ' VTable offset = 384
   ) AS DWORD                                           ' [retval][out] *GridColorFixed OLE_COLOR <alias> <VT_UI4>
   ' =====================================================================================
   PROPERTY SET GridColorFixed <37> ( _                 ' VTable offset = 388
     BYVAL prm_GridColorFixed AS DWORD _                ' [in] GridColorFixed OLE_COLOR <alias> <VT_UI4>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET CellBackColor <38> ( _                  ' VTable offset = 392
   ) AS DWORD                                           ' [retval][out] *CellBackColor OLE_COLOR <alias> <VT_UI4>
   ' =====================================================================================
   PROPERTY SET CellBackColor <38> ( _                  ' VTable offset = 396
     BYVAL prm_CellBackColor AS DWORD _                 ' [in] CellBackColor OLE_COLOR <alias> <VT_UI4>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET CellForeColor <39> ( _                  ' VTable offset = 400
   ) AS DWORD                                           ' [retval][out] *CellForeColor OLE_COLOR <alias> <VT_UI4>
   ' =====================================================================================
   PROPERTY SET CellForeColor <39> ( _                  ' VTable offset = 404
     BYVAL prm_CellForeColor AS DWORD _                 ' [in] CellForeColor OLE_COLOR <alias> <VT_UI4>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET CellAlignment <40> ( _                  ' VTable offset = 408
   ) AS INTEGER                                         ' [retval][out] *CellAlignment VT_I2 <Integer>
   ' =====================================================================================
   PROPERTY SET CellAlignment <40> ( _                  ' VTable offset = 412
     BYVAL prm_CellAlignment AS INTEGER _               ' [in] CellAlignment VT_I2 <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET CellTextStyle <41> ( _                  ' VTable offset = 416
   ) AS LONG                                            ' [retval][out] *CellTextStyle TextStyleSettings <enum>
   ' =====================================================================================
   PROPERTY SET CellTextStyle <41> ( _                  ' VTable offset = 420
     BYVAL prm_CellTextStyle AS LONG _                  ' [in] CellTextStyle TextStyleSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET CellPictureAlignment <43> ( _           ' VTable offset = 424
   ) AS INTEGER                                         ' [retval][out] *CellPictureAlignment VT_I2 <Integer>
   ' =====================================================================================
   PROPERTY SET CellPictureAlignment <43> ( _           ' VTable offset = 428
     BYVAL prm_CellPictureAlignment AS INTEGER _        ' [in] CellPictureAlignment VT_I2 <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET Clip <45> ( _                           ' VTable offset = 432
   ) AS WSTRING                                         ' [retval][out] *Clip VT_BSTR
   ' =====================================================================================
   PROPERTY SET Clip <45> ( _                           ' VTable offset = 436
     BYVAL prm_Clip AS WSTRING _                        ' [in] Clip VT_BSTR
   )                                                    ' void
   ' =====================================================================================
   PROPERTY SET Sort <46> ( _                           ' VTable offset = 440
     BYVAL prm_prm1 AS INTEGER _                        ' [in] VT_I2 <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET SelectionMode <47> ( _                  ' VTable offset = 444
   ) AS LONG                                            ' [retval][out] *SelectionMode SelectionModeSettings <enum>
   ' =====================================================================================
   PROPERTY SET SelectionMode <47> ( _                  ' VTable offset = 448
     BYVAL prm_SelectionMode AS LONG _                  ' [in] SelectionMode SelectionModeSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET MergeCells <48> ( _                     ' VTable offset = 452
   ) AS LONG                                            ' [retval][out] *MergeCells MergeCellsSettings <enum>
   ' =====================================================================================
   PROPERTY SET MergeCells <48> ( _                     ' VTable offset = 456
     BYVAL prm_MergeCells AS LONG _                     ' [in] MergeCells MergeCellsSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET AllowBigSelection <51> ( _              ' VTable offset = 460
   ) AS INTEGER                                         ' [retval][out] *AllowBigSelection VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET AllowBigSelection <51> ( _              ' VTable offset = 464
     BYVAL prm_AllowBigSelection AS INTEGER _           ' [in] AllowBigSelection VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET AllowUserResizing <52> ( _              ' VTable offset = 468
   ) AS LONG                                            ' [retval][out] *AllowUserResizing AllowUserResizeSettings <enum>
   ' =====================================================================================
   PROPERTY SET AllowUserResizing <52> ( _              ' VTable offset = 472
     BYVAL prm_AllowUserResizing AS LONG _              ' [in] AllowUserResizing AllowUserResizeSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET BorderStyle <-504> ( _                  ' VTable offset = 476
   ) AS LONG                                            ' [retval][out] *BorderStyle BorderStyleSettings <enum>
   ' =====================================================================================
   PROPERTY SET BorderStyle <-504> ( _                  ' VTable offset = 480
     BYVAL prm_BorderStyle AS LONG _                    ' [in] BorderStyle BorderStyleSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET hWnd <-515> ( _                         ' VTable offset = 484
   ) AS LONG                                            ' [retval][out] *hWnd VT_I4 <Long>
   ' =====================================================================================
   PROPERTY GET Enabled <-514> ( _                      ' VTable offset = 488
   ) AS INTEGER                                         ' [retval][out] *Enabled VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET Enabled <-514> ( _                      ' VTable offset = 492
     BYVAL prm_Enabled AS INTEGER _                     ' [in] Enabled VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================

Frederick J. Harris


   PROPERTY GET Appearance <-520> ( _                   ' VTable offset = 496
   ) AS LONG                                            ' [retval][out] *Appearance AppearanceSettings <enum>
   ' =====================================================================================
   PROPERTY SET Appearance <-520> ( _                   ' VTable offset = 500
     BYVAL prm_Appearance AS LONG _                     ' [in] Appearance AppearanceSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET MousePointer <53> ( _                   ' VTable offset = 504
   ) AS LONG                                            ' [retval][out] *MousePointer MousePointerSettings <enum>
   ' =====================================================================================
   PROPERTY SET MousePointer <53> ( _                   ' VTable offset = 508
     BYVAL prm_MousePointer AS LONG _                   ' [in] MousePointer MousePointerSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET MouseIcon <54> ( _                      ' VTable offset = 512
   ) AS IPictureDisp                                    ' [retval][out] **MouseIcon IPictureDisp <alias> Picture
   ' =====================================================================================
   PROPERTY SET putref_MouseIcon <54> ( _               ' VTable offset = 516
     BYVAL prm_MouseIcon AS IPictureDisp _              ' [in] *MouseIcon IPictureDisp <alias> Picture
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET PictureType <50> ( _                    ' VTable offset = 520
   ) AS LONG                                            ' [retval][out] *PictureType PictureTypeSettings <enum>
   ' =====================================================================================
   PROPERTY SET PictureType <50> ( _                    ' VTable offset = 524
     BYVAL prm_PictureType AS LONG _                    ' [in] PictureType PictureTypeSettings <enum>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET Picture <49> ( _                        ' VTable offset = 528
   ) AS IPictureDisp                                    ' [retval][out] **Picture IPictureDisp <alias> Picture
   ' =====================================================================================
   PROPERTY GET CellPicture <42> ( _                    ' VTable offset = 532
   ) AS IPictureDisp                                    ' [retval][out] **CellPicture IPictureDisp <alias> Picture
   ' =====================================================================================
   PROPERTY SET putref_CellPicture <42> ( _             ' VTable offset = 536
     BYVAL prm_CellPicture AS IPictureDisp _            ' [in] *CellPicture IPictureDisp <alias> Picture
   )                                                    ' void
   ' =====================================================================================
   METHOD AboutBox <-552> ( _                           ' VTable offset = 540
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET TextArray <55> ( _                      ' VTable offset = 544
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS WSTRING                                         ' [retval][out] *TextArray VT_BSTR
   ' =====================================================================================
   PROPERTY SET TextArray <55> ( _                      ' VTable offset = 548
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   , BYVAL prm_TextArray AS WSTRING _                   ' [in] TextArray VT_BSTR
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET ColAlignment <56> ( _                   ' VTable offset = 552
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS INTEGER                                         ' [retval][out] *ColAlignment VT_I2 <Integer>
   ' =====================================================================================
   PROPERTY SET ColAlignment <56> ( _                   ' VTable offset = 556
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   , BYVAL prm_ColAlignment AS INTEGER _                ' [in] ColAlignment VT_I2 <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET ColWidth <57> ( _                       ' VTable offset = 560
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS LONG                                            ' [retval][out] *ColWidth VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET ColWidth <57> ( _                       ' VTable offset = 564
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   , BYVAL prm_ColWidth AS LONG _                       ' [in] ColWidth VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET RowHeight <58> ( _                      ' VTable offset = 568
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS LONG                                            ' [retval][out] *RowHeight VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET RowHeight <58> ( _                      ' VTable offset = 572
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   , BYVAL prm_RowHeight AS LONG _                      ' [in] RowHeight VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET MergeRow <59> ( _                       ' VTable offset = 576
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS INTEGER                                         ' [retval][out] *MergeRow VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET MergeRow <59> ( _                       ' VTable offset = 580
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   , BYVAL prm_MergeRow AS INTEGER _                    ' [in] MergeRow VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET MergeCol <60> ( _                       ' VTable offset = 584
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS INTEGER                                         ' [retval][out] *MergeCol VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET MergeCol <60> ( _                       ' VTable offset = 588
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   , BYVAL prm_MergeCol AS INTEGER _                    ' [in] MergeCol VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY SET RowPosition <61> ( _                    ' VTable offset = 592
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   , BYVAL prm_prm2 AS LONG _                           ' [in] VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY SET ColPosition <62> ( _                    ' VTable offset = 596
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   , BYVAL prm_prm2 AS LONG _                           ' [in] VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET RowData <63> ( _                        ' VTable offset = 600
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS LONG                                            ' [retval][out] *RowData VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET RowData <63> ( _                        ' VTable offset = 604
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   , BYVAL prm_RowData AS LONG _                        ' [in] RowData VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET ColData <64> ( _                        ' VTable offset = 608
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS LONG                                            ' [retval][out] *ColData VT_I4 <Long>
   ' =====================================================================================
   PROPERTY SET ColData <64> ( _                        ' VTable offset = 612
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   , BYVAL prm_ColData AS LONG _                        ' [in] ColData VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET TextMatrix <65> ( _                     ' VTable offset = 616
     BYVAL prm_Row AS LONG _                            ' [in] Row VT_I4 <Long>
   , BYVAL prm_Col AS LONG _                            ' [in] Col VT_I4 <Long>
   ) AS WSTRING                                         ' [retval][out] *TextMatrix VT_BSTR
   ' =====================================================================================
   PROPERTY SET TextMatrix <65> ( _                     ' VTable offset = 620
     BYVAL prm_Row AS LONG _                            ' [in] Row VT_I4 <Long>
   , BYVAL prm_Col AS LONG _                            ' [in] Col VT_I4 <Long>
   , BYVAL prm_TextMatrix AS WSTRING _                  ' [in] TextMatrix VT_BSTR
   )                                                    ' void
   ' =====================================================================================
   METHOD AddItem <66> ( _                              ' VTable offset = 624
     BYVAL prm_Item AS WSTRING _                        ' [in] Item VT_BSTR
   , OPTIONAL BYVAL prm_index AS VARIANT _              ' [opt][in] index VT_VARIANT <Variant>
   )                                                    ' void
   ' =====================================================================================
   METHOD RemoveItem <67> ( _                           ' VTable offset = 628
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   )                                                    ' void
   ' =====================================================================================
   METHOD Clear <68> ( _                                ' VTable offset = 632
   )                                                    ' void
   ' =====================================================================================
   METHOD Refresh <-550> ( _                            ' VTable offset = 636
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET DataSource <76> ( _                     ' VTable offset = 640
   ) AS IRowCursor                                      ' [retval][out] **DataSource IRowCursor <dispinterface>
   ' =====================================================================================
   PROPERTY SET DataSource <76> ( _                     ' VTable offset = 644
     BYVAL prm_DataSource AS IRowCursor _               ' [in] *DataSource IRowCursor <dispinterface>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET RowIsVisible <85> ( _                   ' VTable offset = 648
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS INTEGER                                         ' [retval][out] *RowIsVisible VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY GET ColIsVisible <86> ( _                   ' VTable offset = 652
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS INTEGER                                         ' [retval][out] *ColIsVisible VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY GET RowPos <87> ( _                         ' VTable offset = 656
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS LONG                                            ' [retval][out] *RowPos VT_I4 <Long>
   ' =====================================================================================
   PROPERTY GET ColPos <88> ( _                         ' VTable offset = 660
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS LONG                                            ' [retval][out] *ColPos VT_I4 <Long>
   ' =====================================================================================
   PROPERTY GET GridLineWidth <89> ( _                  ' VTable offset = 664
   ) AS INTEGER                                         ' [retval][out] *GridLineWidth VT_I2 <Integer>
   ' =====================================================================================
   PROPERTY SET GridLineWidth <89> ( _                  ' VTable offset = 668
     BYVAL prm_GridLineWidth AS INTEGER _               ' [in] GridLineWidth VT_I2 <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET FixedAlignment <90> ( _                 ' VTable offset = 672
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   ) AS INTEGER                                         ' [retval][out] *FixedAlignment VT_I2 <Integer>
   ' =====================================================================================
   PROPERTY SET FixedAlignment <90> ( _                 ' VTable offset = 676
     BYVAL prm_index AS LONG _                          ' [in] index VT_I4 <Long>
   , BYVAL prm_FixedAlignment AS INTEGER _              ' [in] FixedAlignment VT_I2 <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET FontName <91> ( _                       ' VTable offset = 680
   ) AS WSTRING                                         ' [retval][out] *FontName VT_BSTR
   ' =====================================================================================
   PROPERTY SET FontName <91> ( _                       ' VTable offset = 684
     BYVAL prm_FontName AS WSTRING _                    ' [in] FontName VT_BSTR
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET FontSize <92> ( _                       ' VTable offset = 688
   ) AS SINGLE                                          ' [retval][out] *FontSize VT_R4 <Single>
   ' =====================================================================================
   PROPERTY SET FontSize <92> ( _                       ' VTable offset = 692
     BYVAL prm_FontSize AS SINGLE _                     ' [in] FontSize VT_R4 <Single>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET FontBold <93> ( _                       ' VTable offset = 696
   ) AS INTEGER                                         ' [retval][out] *FontBold VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET FontBold <93> ( _                       ' VTable offset = 700
     BYVAL prm_FontBold AS INTEGER _                    ' [in] FontBold VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET FontItalic <94> ( _                     ' VTable offset = 704
   ) AS INTEGER                                         ' [retval][out] *FontItalic VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET FontItalic <94> ( _                     ' VTable offset = 708
     BYVAL prm_FontItalic AS INTEGER _                  ' [in] FontItalic VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET FontStrikethru <95> ( _                 ' VTable offset = 712
   ) AS INTEGER                                         ' [retval][out] *FontStrikethru VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET FontStrikethru <95> ( _                 ' VTable offset = 716
     BYVAL prm_FontStrikethru AS INTEGER _              ' [in] FontStrikethru VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET FontUnderline <96> ( _                  ' VTable offset = 720
   ) AS INTEGER                                         ' [retval][out] *FontUnderline VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET FontUnderline <96> ( _                  ' VTable offset = 724
     BYVAL prm_FontUnderline AS INTEGER _               ' [in] FontUnderline VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET RightToLeft <-611> ( _                  ' VTable offset = 728
   ) AS INTEGER                                         ' [retval][out] *RightToLeft VT_BOOL <Integer>
   ' =====================================================================================
   PROPERTY SET RightToLeft <-611> ( _                  ' VTable offset = 732
     BYVAL prm_RightToLeft AS INTEGER _                 ' [in] RightToLeft VT_BOOL <Integer>
   )                                                    ' void
   ' =====================================================================================
   PROPERTY GET OLEDropMode <1551> ( _                  ' VTable offset = 736
   ) AS LONG                                            ' [retval][out] *psOLEDropMode OLEDropConstants <enum>
   ' =====================================================================================
   PROPERTY SET OLEDropMode <1551> ( _                  ' VTable offset = 740
     BYVAL prm_psOLEDropMode AS LONG _                  ' [in] psOLEDropMode OLEDropConstants <enum>
   )                                                    ' void
   ' =====================================================================================
   METHOD OLEDrag <1552> ( _                            ' VTable offset = 744
   )                                                    ' void
   ' =====================================================================================

END INTERFACE

#ENDIF   ' /* __IMSFlexGrid_INTERFACE_DEFINED__ */


Frederick J. Harris

Dear God that was a struggle to get in! :)  No more posting Jose's includes for me!!!

And here is the events code...


'MSFlexGridLibEvents.inc
' ########################################################################################
' Class CDMSFlexGridEvents
' Interface name = DMSFlexGridEvents
' IID = {609602E0-531B-11CF-91F6-C2863C385E30}
' Event interface for Microsoft FlexGrid Control
' Attributes = 4112 [&H1010] [Hidden] [Dispatchable]
' Code generated by the TypeLib Browser 5.0.1 (c) 2011 by José Roca
' Date: 05 Sep 2014   Time: 09:17:50
' ########################################################################################

CLASS CDMSFlexGridEvents GUID$("{16980577-F116-4460-85AD-71B208AD9996}") AS EVENT
  INTERFACE DMSFlexGridEventsImpl GUID$("{609602E0-531B-11CF-91F6-C2863C385E30}") AS EVENT : INHERIT IDispatch

     ' =====================================================================================
     METHOD Click <-600>

       ' *** Insert your code here ***

     END METHOD
     ' =====================================================================================

     ' =====================================================================================
     METHOD KeyDown <-602> ( _
       BYREF prm_KeyCode AS INTEGER _                     ' *KeyCode VT_I2 <Integer>
       , BYVAL prm_Shift AS INTEGER _                     ' Shift VT_I2 <Integer>
       )                                                      ' void

       ' *** Insert your code here ***

     END METHOD
     ' =====================================================================================

     ' =====================================================================================
   METHOD DblClick <-601>
     MsgBox("You Double Clicked In A Grid Cell!")
   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   Method KeyPress <-603> (Byref KeyAscii As Integer)
     MsgBox("You Pressed The Key " & Chr$(KeyAscii) & "!")
   End Method
   ' =====================================================================================

   ' =====================================================================================
   METHOD KeyUp <-604> ( _
     BYREF prm_KeyCode AS INTEGER _                     ' *KeyCode VT_I2 <Integer>
   , BYVAL prm_Shift AS INTEGER _                       ' Shift VT_I2 <Integer>
   )                                                    ' void

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD MouseDown <-605> ( _
     BYVAL prm_Button AS INTEGER _                      ' Button VT_I2 <Integer>
   , BYVAL prm_Shift AS INTEGER _                       ' Shift VT_I2 <Integer>
   , BYVAL prm_x AS LONG _                              ' x OLE_XPOS_PIXELS <alias> <VT_I4>
   , BYVAL prm_y AS LONG _                              ' y OLE_YPOS_PIXELS <alias> <VT_I4>
   )                                                    ' void

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD MouseMove <-606> ( _
     BYVAL prm_Button AS INTEGER _                      ' Button VT_I2 <Integer>
   , BYVAL prm_Shift AS INTEGER _                       ' Shift VT_I2 <Integer>
   , BYVAL prm_x AS LONG _                              ' x OLE_XPOS_PIXELS <alias> <VT_I4>
   , BYVAL prm_y AS LONG _                              ' y OLE_YPOS_PIXELS <alias> <VT_I4>
   )                                                    ' void

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD MouseUp <-607> ( _
     BYVAL prm_Button AS INTEGER _                      ' Button VT_I2 <Integer>
   , BYVAL prm_Shift AS INTEGER _                       ' Shift VT_I2 <Integer>
   , BYVAL prm_x AS LONG _                              ' x OLE_XPOS_PIXELS <alias> <VT_I4>
   , BYVAL prm_y AS LONG _                              ' y OLE_YPOS_PIXELS <alias> <VT_I4>
   )                                                    ' void

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD SelChange <69>

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD RowColChange <70>

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD EnterCell <71>

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD LeaveCell <72>

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD Scroll <73>

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD Compare <74> ( _
     BYVAL prm_Row1 AS LONG _                           ' Row1 VT_I4 <Long>
   , BYVAL prm_Row2 AS LONG _                           ' Row2 VT_I4 <Long>
   , BYREF prm_Cmp AS INTEGER _                         ' *Cmp VT_I2 <Integer>
   )                                                    ' void

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD OLEStartDrag <1550> ( _
     BYREF prm_Data AS IDispatch _                      ' [in][out] **Data DataObject <coclass>
   , BYREF prm_AllowedEffects AS LONG _                 ' [in][out] *AllowedEffects VT_I4 <Long>
   )                                                    ' void

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD OLEGiveFeedback <1551> ( _
     BYREF prm_Effect AS LONG _                         ' [in][out] *Effect VT_I4 <Long>
   , BYREF prm_DefaultCursors AS INTEGER _              ' [in][out] *DefaultCursors VT_BOOL <Integer>
   )                                                    ' void

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD OLESetData <1552> ( _
     BYREF prm_Data AS IDispatch _                      ' [in][out] **Data DataObject <coclass>
   , BYREF prm_DataFormat AS INTEGER _                  ' [in][out] *DataFormat VT_I2 <Integer>
   )                                                    ' void

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD OLECompleteDrag <1553> ( _
     BYREF prm_Effect AS LONG _                         ' [in][out] *Effect VT_I4 <Long>
   )                                                    ' void

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD OLEDragOver <1554> ( _
     BYREF prm_Data AS IDispatch _                      ' [in][out] **Data DataObject <coclass>
   , BYREF prm_Effect AS LONG _                         ' [in][out] *Effect VT_I4 <Long>
   , BYREF prm_Button AS INTEGER _                      ' [in][out] *Button VT_I2 <Integer>
   , BYREF prm_Shift AS INTEGER _                       ' [in][out] *Shift VT_I2 <Integer>
   , BYREF prm_x AS SINGLE _                            ' [in][out] *x VT_R4 <Single>
   , BYREF prm_y AS SINGLE _                            ' [in][out] *y VT_R4 <Single>
   , BYREF prm_State AS INTEGER _                       ' [in][out] *State VT_I2 <Integer>
   )                                                    ' void

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

   ' =====================================================================================
   METHOD OLEDragDrop <1555> ( _
     BYREF prm_Data AS IDispatch _                      ' [in][out] **Data DataObject <coclass>
   , BYREF prm_Effect AS LONG _                         ' [in][out] *Effect VT_I4 <Long>
   , BYREF prm_Button AS INTEGER _                      ' [in][out] *Button VT_I2 <Integer>
   , BYREF prm_Shift AS INTEGER _                       ' [in][out] *Shift VT_I2 <Integer>
   , BYREF prm_x AS SINGLE _                            ' [in][out] *x VT_R4 <Single>
   , BYREF prm_y AS SINGLE _                            ' [in][out] *y VT_R4 <Single>
   )                                                    ' void

     ' *** Insert your code here ***

   END METHOD
   ' =====================================================================================

END INTERFACE

END CLASS


Frederick J. Harris

Specifically, in fnWndProc_OnCreate(), this creates the ActiveX Control ...


hCtl=CreateWindowEx _
( _
  0, _
  $OC_ClassNAME, _
  "MSFlexGridLib.MSFlexGrid;RTLKEY:72E67120-5959-11cf-91F6-C2863C385E30", _
  %WS_CHILD OR %WS_VISIBLE, _
  10, _
  10, _
  280, _
  250, _
  Wea.hWnd, _
  %ID_CONTAINER, _
  Wea.hInst, _
  Byval %NULL _
)


The 2nd parameter of the call is the string equate $OC_ClassName, which is defined in OleCon.inc.  The 3rd parameter ...

"MSFlexGridLib.MSFlexGrid;RTLKEY:72E67120-5959-11cf-91F6-C2863C385E30",

...is a string which Jose parses in the WM_CREATE handler of the Container Control based on the ';' character.  The 1st substring, i.e., the left one, is the Program ID for the MSFlexGrid.  The 2nd sub-string, i.e., "RTLKEY:72E67120-5959-11cf-91F6-C2863C385E30", is my Run Time License Key.  You will need yours as I previously discussed.  The dependency and size information for the above binary package is as follows ...


MSFlexGrid2.exe     64 K
MSFlxGrd.ocx       255 K
========================
                   319 K


So we have 319 K in two files as opposed to 364 K in three files with the Atl approach.  But we can even do better - at least size wise.  The last grid I will show you is my own - FHGrid9.dll.  It is posted here at ...

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

Its also a COM based dll, but its considerably different from MSFlxGrd.ocx.  Its only 22 K and doesn't require an Active X Control Container.  You can use native PowerBASIC COM calls to instantiate it, i.e., NewCom.  Here is the above program but using my grid ...

Frederick J. Harris


'FHGrid1.bas
#Compile                     Exe  "FHGrid1.exe"
#Dim                         All
%UNICODE                     = 1
#If %Def(%UNICODE)
    Macro ZStr               = WStringz
    Macro BStr               = WString
    %SIZEOF_CHAR             = 2
#Else
    Macro ZStr               = Asciiz
    Macro BStr               = String
    %SIZEOF_CHAR             = 1
#EndIf
$CLSID_FHGrid                = GUID$("{20000000-0000-0000-0000-000000000088}")
$IID_IFHGrid                 = GUID$("{20000000-0000-0000-0000-000000000089}")
$IID_IGridEvents             = GUID$("{20000000-0000-0000-0000-00000000008A}")
%NUMBER_ROWS                 = 25
%NUMBER_COLUMNS              = 3

#Include                     "Windows.inc"
#Include                     "ObjBase.inc"

Type GridInterfaces
  pGrid                      As Dword Ptr
  pSink                      As Dword Ptr
End Type

Type WndEventArgs
  wParam                     As Long
  lParam                     As Long
  hWnd                       As Dword
  hInst                      As Dword
End Type

Declare Function FnPtr(wea As WndEventArgs) As Long

Type MessageHandler
  wMessage                   As Long
  dwFnPtr                    As Dword
End Type

Macro  CObj(pUnk, dwAddr)    = Poke Dword, Varptr(pUnk), dwAddr


Interface IGrid $IID_IFHGrid : Inherit IAutomation
  Method CreateGrid _
  ( _
    Byval hParent             As Long, _
    Byval strSetup            As BStr, _
    Byval x                   As Long, _
    Byval y                   As Long, _
    Byval cx                  As Long, _
    Byval cy                  As Long, _
    Byval iRows               As Long, _
    Byval iCols               As Long, _
    Byval iRowHt              As Long, _
    Byval iSelectionBackColor As Long, _
    Byval iSelectionTextColor As Long, _
    Byval strFontName         As BStr, _
    Byval iFontSize           As Long, _
    Byval iFontWeight         As Long _
  )
  Method SetRowCount(Byval iRowCount As Long, Byval blnForce As Long)
  Method GetRowCount() As Long
  Method SetData(Byval iRow As Long, Byval iCol As Long, Byval strData As WString)
  Method GetData(Byval iRow As Long, Byval iCol As Long) As WString
  Method FlushData()
  Method Refresh()
  Method GetVisibleRows() As Long
  Method GethGrid() As Long
  Method GethCell(Byval iRow As Long, Byval iCol As Long) As Long
  Method GethComboBox(Byval iCol As Long) As Long
  Method SetCellAttributes(Byval iRow As Long, Byval iCol As Long, Byval iBackColor As Long, Byval iTextColor As Long) As Long
  Method DeleteRow(Byval iRow As Long)
End Interface


Class CGridEvents  As Event
  Instance hMain As Dword

  Interface IGridEvents $IID_IGridEvents : Inherit IAutomation
    Method Grid_OnKeyPress(Byval iKeyCode As Long, Byval iKeyData As Long, Byval iRow As Long, Byval iCol As Long, Byref blnCancel As Long)
      MsgBox("You Pressed A Key!")
    End Method

    Method Grid_OnKeyDown(Byval iKeyCode As Long, Byval iKeyData As Long, Byval iCellRow As Long, Byval iGridRow As Long, Byval iCol As Long, Byref blnCancel As Long)
      ' Insert your code here
     End Method

    Method Grid_OnLButtonDown(Byval iCellRow As Long, Byval iGridRow As Long, Byval iCol As Long)
      ' Insert your code here
    End Method

    Method Grid_OnLButtonDblClk(Byval iCellRow As Long, Byval iGridRow As Long, Byval iCol As Long)
      MsgBox("You Double Clicked In The Grid!")
    End Method

    Method Grid_OnPaste(Byval iCellRow As Long, Byval iGridRow As Long, Byval iCol As Long)
      ' Insert your code here
    End Method

    Method Grid_OnRowSelection(Byval iRow As Long, Byval iAction As Long)
      ' Insert Code Here
    End Method

    Method Grid_OnDelete(Byval iRow As Long)
      ' Insert Code Here
    End Method
  End Interface
End Class


Function fnWndProc_OnCreate(Wea As WndEventArgs) As Long
  Local pGridInterfaces As GridInterfaces Ptr
  Local pCreateStruct As CREATESTRUCT Ptr
  Local pSink As IGridEvents
  Local strSetup As BStr
  Local pGrid As IGrid

  pCreateStruct=wea.lParam : wea.hInst=@pCreateStruct.hInstance
  pGridInterfaces=HeapAlloc(GetProcessHeap(),%HEAP_ZERO_MEMORY,sizeof(GridInterfaces))
  If pGridInterfaces=0 Then
     MsgBox("Memory Allocation Failure")
     Function=-1 : Exit Function
  End If
  Call SetWindowLong(Wea.hWnd,0,pGridInterfaces)
  Let pGrid = NewCom "FHGrid9.Grid"
  If IsObject(pGrid) Then
     @pGridInterfaces.pGrid=Objptr(pGrid)
     pGrid.AddRef()
     strSetup="100:Column 1:^:edit,100:Column 2:^:edit,100:Column 3:^:edit"
     pGrid.CreateGrid(Wea.hWnd,strSetup,10,10,300,300,%NUMBER_ROWS,%NUMBER_COLUMNS,20,0,0,"Times New Roman",10,%FW_LIGHT) 'was 218
     If ObjResult=%S_OK Then
        pSink = Class "CGridEvents"
        Events From pGrid Call pSink
        @pGridInterfaces.pSink=Objptr(pSink)
      End If
  End If

  fnWndProc_OnCreate=0
End Function


Function fnWndProc_OnDestroy(Wea As WndEventArgs) As Long
  Local pGridInterfaces As GridInterfaces Ptr
  Local pSink As IGridEvents
  Local pGrid As IGrid
  Local hHeap As Dword

  pGridInterfaces=GetWindowLong(Wea.hWnd,0)
  If pGridInterfaces Then
     hHeap=GetProcessHeap()
     If @pGridInterfaces.pSink Then
        CObj(pSink,@pGridInterfaces.pSink)
        Events End pSink : Set pSink=Nothing
     End If
     If @pGridInterfaces.pGrid Then
        CObj(pGrid,@pGridInterfaces.pGrid)
        Set pGrid=Nothing
     End If
     HeapFree(hHeap,0,pGridInterfaces)
  End If
  Call CoFreeUnusedLibraries()
  Call PostQuitMessage(0)

  Function=0
End Function


Function fnWndProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  Local Wea As WndEventArgs

  Select Case As Long wMsg
    Case %WM_CREATE
      Wea.hWnd=hWnd: Wea.wParam=wParam: Wea.lParam=lParam
      Function=fnWndProc_OnCreate(Wea) : Exit Function
    Case %WM_DESTROY
      Wea.hWnd=hWnd: Wea.wParam=wParam: Wea.lParam=lParam
      Function=fnWndProc_OnDestroy(Wea): Exit Function
  End Select

  fnWndProc=DefWindowProc(hWnd,wMsg,wParam,lParam)
End Function


Function WinMain(ByVal hInstance As Long, ByVal hPrevIns As Long, ByVal lpCmdLn As ZStr Ptr, ByVal iShow As Long) As Long
  Local szAppName As ZStr*16
  Local wc As WndClassEx
  Local hWnd As Dword
  Local Msg As tagMsg

  szAppName="Test My Grid"
  wc.lpszClassName=VarPtr(szAppName)              : wc.lpfnWndProc=CodePtr(fnWndProc)
  wc.cbWndExtra=4                                 : wc.hInstance=hInstance
  wc.cbSize=SizeOf(wc)                            : wc.hIcon=LoadIcon(%NULL, ByVal %IDI_APPLICATION)
  wc.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW)  : wc.hbrBackground=%COLOR_BTNFACE+1
  Call RegisterClassEx(wc)
  hWnd=CreateWindowEx(0,szAppName,szAppName,%WS_OVERLAPPEDWINDOW,200,100,350,360,0,0,hInstance,ByVal 0)
  Call ShowWindow(hWnd,iShow)
  While GetMessage(Msg,%NULL,0,0)
    Call TranslateMessage(Msg)
    Call DispatchMessage(Msg)
  Wend

  Function=msg.wParam
End Function


     Believe it or not, that's it.  You can use either the PowerBASIC COM Browser or Jose's Type Lib Browser if you want to generate includes for it, but the interface definitions for the incoming and outgoing interfaces are inline just above.  You don't need an Active X Control Container to instantiate the grid, and you can just use PowerBASIC's NewCom.  And it can be compiled exactly 'as is' using either the PowerBASIC includes or Jose's.  Other than compiling the above code, all you need to do to get this working is download my FHGrid9.dll and register it with Windows like so ...

C:\Your_Project_Directory\>RegSvr32.exe FHGrid9.dll

That will add Registry entries to allow the COM subsystem of Windows to load it.  Alternately, you can do Registry Free COM work by just including the dll in your project directory and using PowerBASIC's NewCom syntax to load the file directory.  See NewCom in Help.  You might be interested in the file sizes...


FHGrid1.exe    16 K
FHGrid9.dll    22 K
===================
               38 K


Those would be using the PowerBASIC includes.  Using Jose's the host is a couple K larger.  Here's what you end up with if you put an MSFlxGrd.ocx on a Visual Basic 6 Form, configure it as above, and make a setup project out of it ...


MSFlexGrid2.cab   1421 K
Setup.exe          137 K
Setup.lst            4 K
========================
                  1562 K


So using my grid and the program above its 41 times smaller than the VB6 counterpart!  Moving on, lets add code to all three of these programs I've presented so far to complete the rest of the job though.  And the rest of the job is to load the Titles Table from Biblio.mdb and have the program automatically persist changes/edits back to the database.  I'll work backwards from here and we'll start with the program just above using my grid, then we'll try to tackle the MSFlexGrid cases.  Here again is the list of necessary steps to complete from the beginning of this tutorial ...

1) Open a database and table;
2) Determine schematics of table such as number rows, columns, column names, data types, etc;
3) Configure grid to accept this data;
4) Retrieve data from database table and populate grid;
5) Persist user edits/changes in grid back to database and table.

And just below is the modified FHGrid1.bas from just above, with the necessary changes to accomplish this.  It can be compiled with either PowerBASIC's or Jose's includes.  I'll discusss it in detail afterwards...


Frederick J. Harris


'FHGrid2.bas                  'Compiles With Either PowerBASIC Or Jose Roca's Includes. 
'                             'Needs PB Win 10 and FHGrid9.dll, i.e., "FHGrid9.Grid"
#Compile                      Exe  "FHGrid2"
#Dim                          All
#Register                     None
%UNICODE                      = 1
'%DEBUG                       = 1
#If %Def(%UNICODE)
    Macro ZStr                = WStringz
    Macro BStr                = WString
    %SIZEOF_CHAR              = 2
#Else
    Macro ZStr                = Asciiz
    Macro BStr                = String
    %SIZEOF_CHAR              = 1
#EndIf
'$DB_PATH                     = "C:\Program Files (x86)\Microsoft Visual Studio\VB98\Biblio.mdb"
$DB_PATH                      = "C:\Program Files\Microsoft Visual Studio\VB98\Biblio.mdb"
$DB_DRIVER                    = "Microsoft Access Driver (*.mdb)"
$CLSID_FHGrid                 = GUID$("{20000000-0000-0000-0000-000000000088}")
$IID_IFHGrid                  = GUID$("{20000000-0000-0000-0000-000000000089}")
$IID_IGridEvents              = GUID$("{20000000-0000-0000-0000-00000000008A}")

#Include                      "Windows.inc"
#Include                      "SqlIncs.inc"
#Include                      "CSql.inc"

Type GridInterfaces
  pGrid                       As Dword Ptr
  pSink                       As Dword Ptr
End Type

Type EditFlags
  iRecords                    As Long
  pEdits                      As Byte Ptr
End Type

Type WndEventArgs
  wParam                      As Long
  lParam                      As Long
  hWnd                        As Dword
  hInst                       As Dword
End Type

Declare Function FnPtr(wea As WndEventArgs) As Long

Type MessageHandler
  wMessage                    As Long
  dwFnPtr                     As Dword
End Type

Global MsgHdlr()              As MessageHandler
Macro  CObj(pUnk, dwAddr) = Poke Dword, Varptr(pUnk), dwAddr

#If %Def(%Debug)
Sub Prnt(strLn As BStr)
  Local iLen, iWritten As Long
  Local hStdOutput As Dword
  Local strNew As BStr
  hStdOutput=GetStdHandle(%STD_OUTPUT_HANDLE)
  strNew=strLn + $CrLf
  iLen = Len(strNew)
  WriteConsole(hStdOutput, Byval Strptr(strNew), iLen, iWritten, Byval 0)
End Sub
#EndIf

Interface IGrid $IID_IFHGrid : Inherit IAutomation
  Method CreateGrid _
  ( _
    Byval hParent             As Long, _
    Byval strSetup            As BStr, _
    Byval x                   As Long, _
    Byval y                   As Long, _
    Byval cx                  As Long, _
    Byval cy                  As Long, _
    Byval iRows               As Long, _
    Byval iCols               As Long, _
    Byval iRowHt              As Long, _
    Byval iSelectionBackColor As Long, _
    Byval iSelectionTextColor As Long, _
    Byval strFontName         As BStr, _
    Byval iFontSize           As Long, _
    Byval iFontWeight         As Long _
  )
  Method SetRowCount(Byval iRowCount As Long, Byval blnForce As Long)
  Method GetRowCount() As Long
  Method SetData(Byval iRow As Long, Byval iCol As Long, Byval strData As WString)
  Method GetData(Byval iRow As Long, Byval iCol As Long) As WString
  Method FlushData()
  Method Refresh()
  Method GetVisibleRows() As Long
  Method GethGrid() As Long
  Method GethCell(Byval iRow As Long, Byval iCol As Long) As Long
  Method GethComboBox(Byval iCol As Long) As Long
  Method SetCellAttributes(Byval iRow As Long, Byval iCol As Long, Byval iBackColor As Long, Byval iTextColor As Long) As Long
  Method DeleteRow(Byval iRow As Long)
End Interface


Class CGridEvents  As Event
  Instance hMain As Dword

  Class Method Create()
    hMain=FindWindow("Test My Grid","Test My Grid")
  End Method

  Interface IGridEvents $IID_IGridEvents : Inherit IAutomation
    Method Grid_OnKeyPress(Byval iKeyCode As Long, Byval iKeyData As Long, Byval iRow As Long, Byval iCol As Long, Byref blnCancel As Long)
       Local pEditFlags As EditFlags Ptr
       pEditFlags=GetWindowLong(hMain,4)
       If pEditFlags And @pEditFlags.pEdits Then
          @pEditFlags.@pEdits[iRow] = @pEditFlags.@pEdits[iRow] Or 2^(iCol-1)
       End If
     End Method

     Method Grid_OnKeyDown(Byval iKeyCode As Long, Byval iKeyData As Long, Byval iCellRow As Long, Byval iGridRow As Long, Byval iCol As Long, Byref blnCancel As Long)
      ' Insert your code here
     End Method

    Method Grid_OnLButtonDown(Byval iCellRow As Long, Byval iGridRow As Long, Byval iCol As Long)
      ' Insert your code here
    End Method

    Method Grid_OnLButtonDblClk(Byval iCellRow As Long, Byval iGridRow As Long, Byval iCol As Long)
      ' Insert Your Code Here
    End Method

    Method Grid_OnPaste(Byval iCellRow As Long, Byval iGridRow As Long, Byval iCol As Long)
      ' Insert your code here
    End Method

    Method Grid_OnRowSelection(Byval iRow As Long, Byval iAction As Long)
      ' Insert Code Here
    End Method

    Method Grid_OnDelete(Byval iRow As Long)
      Local pGridInterfaces As GridInterfaces Ptr
      Local pEditFlags As EditFlags Ptr
      Local strQuery As BStr
      Local strISBN As BStr
      Local pGrid As IGrid
      Local hStmt As Dword
      Local pSql As ISql

      #If %Def(%Debug)
      Prnt "Entering Grid_OnDelete()"
      Prnt "  iRow = " & Str$(iRow)
      #EndIf
      MousePtr 11
      pGridInterfaces=GetWindowLong(hMain,0)
      If pGridInterfaces Then
         If @pGridInterfaces.pGrid Then
            CObj(pGrid,@pGridInterfaces.pGrid)
            Call pGrid.AddRef()
            pEditFlags=GetWindowLong(hMain,4)
            If pEditFlags Then
               Call UpdateDatabase(@pEditFlags.iRecords, @pEditFlags.pEdits, pGrid)
               pSql=Class "CSql"
               pSql.strDBQ=$DB_PATH
               pSql.strDriver=$DB_DRIVER
               Call pSql.ODBCConnect()
               If pSql.blnConnected Then
                  #If %Def(%Debug)
                  Prnt "  Got In Where pSQl.blnConnected = True!"
                  #EndIf
                  Call SQLAllocHandle(%SQL_HANDLE_STMT,pSql.hConn(),hStmt)
                  strISBN=pGrid.GetData(iRow,3)
                  strQuery="DELETE FROM Titles Where ISBN=" & Chr$(39) & strISBN & Chr$(39) & ";"
                  #If %Def(%Debug)
                  Prnt "  " & strQuery
                  #EndIf
                  Call SQLExecDirect(hStmt,Byval Strptr(strQuery),%SQL_NTS)
                  Call SQLFreeHandle(%SQL_HANDLE_STMT,hStmt)
                  Call pSQL.ODBCDisconnect()
                  Call pGrid.DeleteRow(iRow)
                  Call pGrid.Refresh()
               End If
            End If
         End If
      End If
      MousePtr 1
      #If %Def(%Debug)
      Prnt "Leaving Grid_OnDelete()"
      #EndIf
    End Method
  End Interface
End Class


Function blnGetRecordCount(Byref Sql As ISql, Byref iRecCt As Long) As Long
  Local szQuery As ZStr*64
  Local hStmt As Dword
  Local iJnk As Long

  szQuery="SELECT Count(*) As RecordCount FROM Titles"
  Call SQLAllocHandle(%SQL_HANDLE_STMT,Sql.hConn(),hStmt)
  Call SQLBindCol(hStmt,1,%SQL_C_ULONG,iRecCt,0,iJnk)
  Call SQLExecDirect(hStmt,szQuery,%SQL_NTS)
  Call SQLFetch(hStmt)
  Call SQLFreeHandle(%SQL_HANDLE_STMT,hStmt)
  If iRecCt Then
     Function=%True
  Else
     Function=%False
  End If
End Function


Function blnLoadTitles(Byref Sql As ISql, Byref pGrid As IGrid) As Long
  Local szQuery        As ZStr * 256
  Local szTitle        As ZStr * 256
  Local szISBN         As ZStr * 24
  Local iYrPub         As Integer
  Local iPubID         As Long
  Local szDescription  As ZStr * 56
  Local szNotes        As ZStr * 56
  Local szSubject      As ZStr * 56
  Local szComments     As ZStr * 256
  Local iReturn        As Long
  Local hStmt          As Dword
  Local iLen()         As Long
  Register i           As Long

  #If %Def(%Debug)
  Prnt "  Entering blnLoadTitles()"
  #Endif
  Redim iLen(8) As Long
  szQuery = "SELECT Title, [Year Published], ISBN, PubID, Description, Notes, Subject, Comments FROM Titles;
  Call SQLAllocHandle(%SQL_HANDLE_STMT,Sql.hConn(),hStmt)
  Call SQLBindCol(hStmt,1,%SQL_C_WCHAR,szTitle,510,iLen(1))       ' In using ODBC one declares a variable for
  Call SQLBindCol(hStmt,2,%SQL_C_SHORT,iYrPub,0,iLen(2))          ' each field being retrieved from the data
  Call SQLBindCol(hStmt,3,%SQL_C_WCHAR,szISBN,46,iLen(3))         ' source.  The address of this variable is
  Call SQLBindCol(hStmt,4,%SQL_C_LONG,iPubID,0,iLen(4))           ' given to the db driver in SQLBindCol()
  Call SQLBindCol(hStmt,5,%SQL_C_WCHAR,szDescription,110,iLen(5)) ' calls - one for each field/column.  Then
  Call SQLBindCol(hStmt,6,%SQL_C_WCHAR,szNotes,110,iLen(6))       ' one calls SQLExecDirect() to retrieve a
  Call SQLBindCol(hStmt,7,%SQL_C_WCHAR,szSubject,110,iLen(7))     ' database cursor.  It is through this data-
  Call SQLBindCol(hStmt,8,%SQL_C_WCHAR,szComments,510,iLen(8))    ' base cursor one loops with calls of
  iReturn=SQLExecDirect(hStmt,szQuery,%SQL_NTS)                   ' SQLFetch() to retrieve a row of data into
  If iReturn=%SQL_SUCCESS Or iReturn=%SQL_SUCCESS_WITH_INFO Then  ' the bound variables bound with SQLBindCol().
     i=1                                                          ' When the SQLFetch() call is made, those
     Do While SQLFetch(hStmt)<>%SQL_NO_DATA                       ' iLen() variables seen in the last para-
        If iLen(1) Then pGrid.SetData(i,1,szTitle)        ' meter of the SQLBindCol() calls receive the byte
        If iLen(2) Then pGrid.SetData(i,2,Str$(iYrPub))   ' count of data read out of the row from the database
        If iLen(3) Then pGrid.SetData(i,3,szISBN)         ' cursor.  If a zero ends up in there it means that
        If iLen(4) Then pGrid.SetData(i,4,Str$(iPubID))   ' for the respective field that field was NULL.  How-
        If iLen(5) Then pGrid.SetData(i,5,szDescription)  ' ever, that variable may and almost certainly is
        If iLen(6) Then pGrid.SetData(i,6,szNotes)        ' holding whatever was put there from a previous call
        If iLen(7) Then pGrid.SetData(i,7,szSubject)      ' of SQLFetch().  So if you use that data from the
        If iLen(8) Then pGrid.SetData(i,8,szComments)     ' bound variable when the corresponding iLen(i)
        Incr i                                            ' variable is telling you nothing was read, you are
     Loop                                                 ' going to get yourself into trouble.  That's why
     Call SQLFreeHandle(%SQL_HANDLE_STMT,hStmt)           ' I'm checking every iLen(i) before I write the
  Else                                                    ' bound variable's data into the grid.
     Call SQLFreeHandle(%SQL_HANDLE_STMT,hStmt)
     Erase iLen()
     Function=%False : Exit Function
  End If
  pGrid.Refresh()
  Erase iLen()
  #If %Def(%Debug)
  Prnt "    " & szQuery
  Prnt "  Leaving blnLoadTitles()"
  #Endif

  Function=%True
End Function


Function fnWndProc_OnCreate(Wea As WndEventArgs) As Long   ' Offset     What's Stored There
  Local pGridInterfaces As GridInterfaces Ptr              ' ===============================
  Local pCreateStruct As CREATESTRUCT Ptr                  ' 0  -  3    pGridInterfaces
  Local pEditFlags As EditFlags Ptr                        ' 4  -  7    pEditFlags
  Local pSink As IGridEvents
  Local iRecordCount As Long
  Local strSetup As BStr
  Local pGrid As IGrid
  Local hHeap As Dword
  Local pSql As ISql

  #If %Def(%Debug)
  Call AllocConsole()
  Prnt "Entering fnWndProc_OnCreate()"
  #EndIf
  pCreateStruct=wea.lParam : wea.hInst=@pCreateStruct.hInstance
  hHeap=GetProcessHeap()
  pGridInterfaces=HeapAlloc(hHeap,%HEAP_ZERO_MEMORY,sizeof(GridInterfaces))
  If pGridInterfaces Then
     Call SetWindowLong(Wea.hWnd,0,pGridInterfaces)
     pGrid = NewCom "FHGrid9.Grid"
     If IsObject(pGrid) Then
        @pGridInterfaces.pGrid=Objptr(pGrid)
        pGrid.AddRef()
        pSql=Class "CSql"
        pSql.strDBQ=$DB_PATH
        pSql.strDriver=$DB_DRIVER
        Call pSql.ODBCConnect()
        If pSql.blnConnected Then
           If blnGetRecordCount(pSql, iRecordCount) Then
              #If %Def(%Debug)
              Prnt "  iRecordCount         = " & Str$(iRecordCount)
              #EndIf
              iRecordCount=iRecordCount*1.01
              hHeap=GetProcessHeap()
              pEditFlags=HeapAlloc(hHeap,%HEAP_ZERO_MEMORY,sizeof(EditFlags))
              #If %Def(%Debug)
              Prnt "  iRecordCount         = " & Str$(iRecordCount)
              Prnt "  pEditFlags           = " & Str$(pEditFlags)
              #EndIf
              If pEditFlags Then
                 @pEditFlags.iRecords=iRecordCount
                 @pEditFlags.pEdits=HeapAlloc(hHeap,%HEAP_ZERO_MEMORY,iRecordCount+1)
                 #If %Def(%Debug)
                 Prnt "  @pEditFlags.iRecords = " & Str$(@pEditFlags.iRecords)
                 Prnt "  @pEditFlags.pEdits   = " & Str$(@pEditFlags.pEdits)
                 #EndIf
                 If @pEditFlags.pEdits Then
                    SetWindowLong(Wea.hWnd,4,pEditFlags)
                    strSetup= _
                    "300:Title:^:edit," & _
                    "200:Year Published:^:edit," & _
                    "150:ISBN:^:edit," & _
                    "90:PubID:^:edit," & _
                    "200:Description:^:edit," & _
                    "90:Notes:^:edit," & _
                    "100:Subject:^:edit," & _
                    "110:Comments:^:edit"
                    pGrid.CreateGrid(Wea.hWnd,strSetup,10,10,850,500,iRecordCount,8,20,0,0,"Times New Roman",12,%FW_LIGHT)
                    If ObjResult=%S_OK Then
                       pSink = Class "CGridEvents"
                       Events From pGrid Call pSink
                       @pGridInterfaces.pSink=Objptr(pSink)
                       Call blnLoadTitles(pSql, pGrid)
                    End If
                 End If
              End If
           End If
           pSql.ODBCDisconnect()
        End If
     Else
        MsgBox("Couldn't Create FHGrid9!")
        Function=-1 : Exit Function   
     End If
  Else
     MsgBox("Memory Allocation Failure")
     Function=-1 : Exit Function
  End If
  #If %Def(%Debug)
  Prnt "Leaving fnWndProc_OnCreate()" & $CrLf
  #EndIf

  fnWndProc_OnCreate=0
End Function


Function blnUpdateRecord(Byval iRecord As Long, Byval pRecord As Byte Ptr, Byref Sql As ISql, Byref pGrid As IGrid) As Long
  Local strQuery, strField, strPrimaryKey As BStr
  Local iReturn As Long
  Local hStmt As Dword
  Register i As Long

  #If %Def(%Debug)
  Prnt ""
  Prnt "  Entering blnUpdateRecord()"
  Prnt "    Record #" & Str$(iRecord) & " Was Edited"
  Prnt "    @pRecord = " & Str$(@pRecord)
  Prnt ""
  #EndIf
  strQuery="UPDATE Titles SET "                        ' In this code we loop through the bits at @pRecord looking
  For i=0 To 7                                         ' for any that have been set in Grid_OnKeyPress().  We use
    If IsTrue(@pRecord And 2^i) Then                   ' the bitwise And operator for that.  An And operation against
       Select Case As Long i                           ' a set bit will return true.  So the loop will And 1 against
         Case 0                                        ' @pRecord, then 2, then 4, then 8, then 16, etc.  When we
           strField=pGrid.GetData(iRecord,1)           ' make a hit we concatenate that respective string into
           If InStr(1,strField,Chr$(39)) Then          ' strQuery, and collect the data from the grid cell for that
              Replace Chr$(39) With "''" In strField   ' column and row.
           End If
           strQuery = strQuery & "Title=" & Chr$(39) & strField & Chr$(39) & ","
         Case 1
           strField=pGrid.GetData(iRecord,2)
           strQuery = strQuery & "[Year Published]=" & strField & ","
         Case 3
           strField=pGrid.GetData(iRecord,4)
           strQuery = strQuery & "PubID=" & strField & ","
         Case 4
           strField=pGrid.GetData(iRecord,5)
           If InStr(1,strField,Chr$(39)) Then
              Replace Chr$(39) With "''" In strField
           End If
           strQuery = strQuery & "Description=" & Chr$(39) & strField & Chr$(39) & ","
         Case 5
           strField=pGrid.GetData(iRecord,6)
           If InStr(1,strField,Chr$(39)) Then
              Replace Chr$(39) With "''" In strField
           End If
           strQuery = strQuery & "Notes=" & Chr$(39) & strField & Chr$(39) & ","
         Case 6
           strField=pGrid.GetData(iRecord,7)
           If InStr(1,strField,Chr$(39)) Then
              Replace Chr$(39) With "''" In strField
           End If
           strQuery = strQuery & "Subject=" & Chr$(39) & strField & Chr$(39) & ","
         Case 7
           strField=pGrid.GetData(iRecord,8)
           If InStr(1,strField,Chr$(39)) Then
              Replace Chr$(39) With "''" In strField
           End If
           strQuery = strQuery & "Comments=" & Chr$(39) & strField & Chr$(39) & ","
       End Select
    End If
  Next i
  strQuery=Left$(strQuery,Len(strQuery)-1)
  strPrimaryKey=" WHERE ISBN=" & Chr$(39) & pGrid.GetData(iRecord,3) & Chr$(39) & ";"
  strQuery=strQuery+strPrimaryKey
  #If %Def(%Debug)
  Prnt "    strQuery = " & strQuery
  #EndIf
  Call SQLAllocHandle(%SQL_HANDLE_STMT,Sql.hConn(),hStmt)
  iReturn=SQLExecDirect(hStmt,Byval Strptr(strQuery),%SQL_NTS)
  If iReturn<>%SQL_SUCCESS And iReturn<>%SQL_SUCCESS_WITH_INFO Then
     Sql.ODBCGetDiagRec(hStmt)
     #If %Def(%Debug)
     Prnt "    iReturn                = " & Str$(iReturn)
     Prnt "    %SQL_SUCCESS           = " & Str$(%SQL_SUCCESS)
     Prnt "    %SQL_SUCCESS_WITH_INFO = " & Str$(%SQL_SUCCESS_WITH_INFO)
     Prnt "    Sql.iNativeErrCode     = " & Str$(Sql.iNativeErrCode)
     Prnt "    Sql.strErrMsg          = " & Sql.strErrMsg
     Prnt "    Sql.strErrCode         = " & Sql.strErrCode
     #EndIf
     Call SQLFreeHandle(%SQL_HANDLE_STMT,hStmt)
     #If %Def(%Debug)
     Prnt "  Leaving blnUpdateRecord()"
     #EndIf
     Function=%False : Exit Function
  End If
  Call SQLFreeHandle(%SQL_HANDLE_STMT,hStmt)
  #If %Def(%Debug)
  Prnt "  Leaving blnUpdateRecord()"
  #EndIf

  Function=%True
End Function


Function blnInsertRecord(Byval iRecord As Long, Byval pRecord As Byte Ptr, Byref Sql As ISql, Byref pGrid As IGrid) As Long
  Local strQuery, strField As BStr
  Local iReturn As Long
  Local hStmt As Dword
  Register i As Long

  #If %Def(%Debug)
  Prnt $CrLf
  Prnt "  Entering blnInsertRecord()"
  Prnt "    Record #" & Str$(iRecord) & " Was Edited"
  Prnt "    @pRecord = " & Str$(@pRecord)
  Prnt $CrLf
  #EndIf
  strQuery="INSERT INTO Titles ("                 ' This is exactly like blnUpdateRecord() above in its logic, but
  For i=0 To 7                                    ' we're constructing an SQL INSERT statement here.  We loop through
    If IsTrue(@pRecord And 2^i) Then              ' all the bits in the record passed in as a parameter and search for
       Select Case As Long i                      ' dirty bits.  When we find one we add the field name to the INSERT
         Case 0                                   ' statement, and get the associated data from the grid for whatever
           strQuery=strQuery+"Title,"             ' column/field we made the 'hit'.  When we're done we call
         Case 1                                   ' SQLExecDirect() to see if we can get the record in.
           strQuery=strQuery+"[Year Published],"
         Case 2
           strQuery=strQuery+"ISBN,"
         Case 3
           strQuery=strQuery+"PubID,"
         Case 4
           strQuery=strQuery+"Description,"
         Case 5
           strQuery=strQuery+"Notes,"
         Case 6
           strQuery=strQuery+"Subject,"
         Case 7
           strQuery=strQuery+"Comments,"
       End Select
    End If
  Next i
  strQuery=Left$(strQuery,Len(strQuery)-1)+") VALUES ("
  For i=0 To 7
    If IsTrue(@pRecord And 2^i) Then
       Select Case As Long i
         Case 0
           strField=pGrid.GetData(iRecord,1)
           If InStr(1,strField,Chr$(39)) Then
              Replace Chr$(39) With "''" In strField
           End If
           strQuery = strQuery & Chr$(39) & strField & Chr$(39) & ","
         Case 1
           strField=pGrid.GetData(iRecord,2)
           strQuery = strQuery & strField & ","
         Case 2
           strField=pGrid.GetData(iRecord,3)
           If InStr(1,strField,Chr$(39)) Then
              Replace Chr$(39) With "''" In strField
           End If
           strQuery = strQuery & Chr$(39) & strField & Chr$(39) & ","
         Case 3
           strField=pGrid.GetData(iRecord,4)
           strQuery = strQuery & strField & ","
         Case 4
           strField=pGrid.GetData(iRecord,5)
           If InStr(1,strField,Chr$(39)) Then
              Replace Chr$(39) With "''" In strField
           End If
           strQuery = strQuery & Chr$(39) & strField & Chr$(39) & ","
         Case 5
           strField=pGrid.GetData(iRecord,6)
           If InStr(1,strField,Chr$(39)) Then
              Replace Chr$(39) With "''" In strField
           End If
           strQuery = strQuery & Chr$(39) & strField & Chr$(39) & ","
         Case 6
           strField=pGrid.GetData(iRecord,7)
           If InStr(1,strField,Chr$(39)) Then
              Replace Chr$(39) With "''" In strField
           End If
           strQuery = strQuery & Chr$(39) & strField & Chr$(39) & ","
         Case 7
           strField=pGrid.GetData(iRecord,8)
           If InStr(1,strField,Chr$(39)) Then
              Replace Chr$(39) With "''" In strField
           End If
           strQuery = strQuery & Chr$(39) & strField & Chr$(39) & ","
       End Select
    End If
  Next i
  strQuery=Left$(strQuery,Len(strQuery)-1) & ");"
  #If %Def(%Debug)
  Prnt "    strQuery = " & strQuery
  #EndIf
  Call SQLAllocHandle(%SQL_HANDLE_STMT,Sql.hConn(),hStmt)
  iReturn=SQLExecDirect(hStmt,Byval Strptr(strQuery),%SQL_NTS)
  If iReturn<>%SQL_SUCCESS And iReturn<>%SQL_SUCCESS_WITH_INFO Then
     Sql.ODBCGetDiagRec(hStmt)
     #If %Def(%Debug)
     Prnt "    iReturn                = " & Str$(iReturn)
     Prnt "    %SQL_SUCCESS           = " & Str$(%SQL_SUCCESS)
     Prnt "    %SQL_SUCCESS_WITH_INFO = " & Str$(%SQL_SUCCESS_WITH_INFO)
     Prnt "    Sql.iNativeErrCode     = " & Str$(Sql.iNativeErrCode)
     Prnt "    Sql.strErrMsg          = " & Sql.strErrMsg
     Prnt "    Sql.strErrCode         = " & Sql.strErrCode
     #Else
         iReturn=MsgBox(Sql.strErrMsg, %MB_ICONERROR, "I Don't Want To Sugar Coat It ...")
     #EndIf
     Call SQLFreeHandle(%SQL_HANDLE_STMT,hStmt)
     Function=%False : Exit Function
  End If
  Call SQLFreeHandle(%SQL_HANDLE_STMT,hStmt)
  #If %Def(%Debug)
  Prnt "  Leaving blnInsertRecord()"
  Prnt $CrLf
  #EndIf

  Function=%True
End Function


Sub UpdateDatabase(Byval iRecords As Long, Byval pEdits As Byte Ptr, Byref pGrid As IGrid)
  Local blnDataEdited, iReturn As Long
  Register i As Long
  Local Sql As ISql

  #If %Def(%Debug)
  Prnt "  Entering UpdateDatabase()"
  Prnt "    iRecords = " & Str$(iRecords)
  Prnt "    pEdits   = " & Str$(pEdits)
  #EndIf
  For i = 1 To iRecords      ' If @pEdit[i] is anything other than zero, we know the user
    If @pEdits[i] Then       ' pressed a key while the caret was in some cell.  Therefore,
       blnDataEdited=%True   ' something was edited or inserted.  In that case we're going
       Exit For              ' to have to get inside the If just below and see just what
    End If                   ' the user did.  Every record (byte at @pEdits[i]) will have
  Next i                     ' to be tested for a 'dirty' bit or bits.  When we find a
  If blnDataEdited Then      ' non-zero byte, we'll pass that byte and record number to
     Sql=Class "CSql"        ' blnUpdateRecord() to see if an UPDATE Query will update
     Sql.strDBQ=$DB_PATH          ' that record.  It might fail.  For example, it would
     Sql.strDriver=$DB_DRIVER     ' fail if the user added a new record to the end of the
     Call Sql.ODBCConnect()       ' grid's pre-existing data.  In that case an INSERT Query
     If Sql.blnConnected Then     ' might do the trick.  So we then try blnInsertRecord().
        #If %Def(%Debug)   
        Prnt "    Sql.blnConnected  = True!"
        #Endif
        For i=1 To iRecords       ' If that fails we simply give up and notify the user that
          If @pEdits[i] Then      ' his money will be refunded and we give up.
             If IsFalse(blnUpdateRecord(i,Varptr(@pEdits[i]),Sql,pGrid)) Then
                If IsFalse(blnInsertRecord(i,Varptr(@pEdits[i]),Sql,pGrid)) Then
                   iReturn=MsgBox _
                   ( _
                     "Failed To Update/Insert Record #" & Str$(i) & "!", _
                     %MB_ICONERROR, _
                     "I Don't Want To Sugar Coat It!" _
                   )
                End If            ' What blnUpdateRecord() and blnInsertRecord() do is construct
             End If               ' either an UPDATE or INSERT Query from the 'dirty' bits
             @pEdits[i]=0         ' found at @pEdit[i].  So its basically a string concat-
          End If                  ' enation job.  Note that Sql was passed to there from here,
        Next i                    ' and whatever the outcome was, we close it here.
        Sql.ODBCDisconnect()
     End If
  End If
  #If %Def(%Debug)
  Prnt "  Leaving UpdateDatabase()"
  #EndIf
End Sub


Function fnWndProc_OnDestroy(Wea As WndEventArgs) As Long
  Local pGridInterfaces As GridInterfaces Ptr
  Local pEditFlags As EditFlags Ptr
  Local pSink As IGridEvents
  Local pGrid As IGrid
  Local hHeap As Dword
  Local bFree As Long

  #If %Def(%Debug)
  Prnt "Entering fnWndProc_OnDestroy()"
  #EndIf
  pGridInterfaces=GetWindowLong(Wea.hWnd,0)
  If pGridInterfaces Then
     If @pGridInterfaces.pSink Then
        CObj(pSink,@pGridInterfaces.pSink)
        Events End pSink : Set pSink=Nothing
     End If
     If @pGridInterfaces.pGrid Then
        CObj(pGrid,@pGridInterfaces.pGrid)
        pGrid.FlushData()
        hHeap=GetProcessHeap()
        pEditFlags=GetWindowLong(Wea.hWnd,4)
        If pEditFlags Then
           #If %Def(%Debug)
           Prnt "  pEditFlags           = " & Str$(pEditFlags)
           Prnt "  @pEditFlags.iRecords = " & Str$(@pEditFlags.iRecords)
           #EndIf
           If @pEditFlags.pEdits Then
              #If %Def(%Debug)
              Prnt "  @pEditFlags.pEdits   = " & Str$(@pEditFlags.pEdits)
              #EndIf
              Call UpdateDatabase(@pEditFlags.iRecords, @pEditFlags.pEdits,pGrid)
              bFree=HeapFree(hHeap,0,@pEditFlags.pEdits)
              #If %Def(%Debug)
              Prnt "  bFree(@pEditFlags.pEdits) = " & Str$(bFree)
              #EndIf
           End If
           bFree=HeapFree(hHeap,0,pEditFlags)
           #If %Def(%Debug)
           Prnt "  bFree(pEditFlags)         = " & Str$(bFree)
           #EndIf
        End If
        Set pGrid=Nothing
     End If   
     bFree=HeapFree(hHeap,0,pGridInterfaces)
  End If
  Call CoFreeUnusedLibraries()
  Call PostQuitMessage(0)
  #If %Def(%Debug)
  Prnt "Leaving fnWndProc_OnDestroy()"
  #EndIf

  Function=0
End Function


Function fnWndProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
  Local wea As WndEventArgs
  Register iReturn As Long
  Register i As Long

  For i=0 To 1
    If wMsg=MsgHdlr(i).wMessage Then
       wea.hWnd=hWnd: wea.wParam=wParam: wea.lParam=lParam
       Call Dword MsgHdlr(i).dwFnPtr Using FnPtr(wea) To iReturn
       fnWndProc=iReturn
       Exit Function
    End If
  Next i

  fnWndProc=DefWindowProc(hWnd,wMsg,wParam,lParam)
End Function


Sub AttachMessageHandlers()
  ReDim MsgHdlr(1) As MessageHandler  'Associate Windows Message With Message Handlers
  MsgHdlr(0).wMessage=%WM_CREATE   :   MsgHdlr(0).dwFnPtr=CodePtr(fnWndProc_OnCreate)
  MsgHdlr(1).wMessage=%WM_DESTROY  :   MsgHdlr(1).dwFnPtr=CodePtr(fnWndProc_OnDestroy)
End Sub


Function WinMain(ByVal hInstance As Long, ByVal hPrevIns As Long, ByVal lpCmdLn As ZStr Ptr, ByVal iShow As Long) As Long
  Local szAppName As ZStr*16
  Local wc As WndClassEx
  Local hWnd As Dword
  Local Msg As tagMsg

  szAppName="Test My Grid"                        : Call AttachMessageHandlers()
  wc.lpszClassName=VarPtr(szAppName)              : wc.lpfnWndProc=CodePtr(fnWndProc)
  wc.cbWndExtra=8                                 : wc.hInstance=hInstance
  wc.cbSize=SizeOf(wc)                            : wc.hIcon=LoadIcon(%NULL, ByVal %IDI_APPLICATION)
  wc.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW)  : wc.hbrBackground=%COLOR_BTNFACE+1
  Call RegisterClassEx(wc)
  hWnd=CreateWindowEx(0,szAppName,szAppName,%WS_OVERLAPPEDWINDOW,200,100,880,570,0,0,hInstance,ByVal 0)
  Call ShowWindow(hWnd,iShow)
  While GetMessage(Msg,%NULL,0,0)
    Call TranslateMessage(Msg)
    Call DispatchMessage(Msg)
  Wend
  #If %Def(%Debug)
  MsgBox("Come And Get It Before I Throw It Out!")
  #EndIf

  Function=msg.wParam
End Function


Frederick J. Harris

Here would be SqlIncs.inc...


'SqlIncs.inc

%SQL_HANDLE_ENV                      = 1
%SQL_HANDLE_DBC                      = 2
%SQL_HANDLE_STMT                     = 3
%SQL_NULL_HANDLE                     = 0&
%SQL_ATTR_ODBC_VERSION               = 200
%SQL_OV_ODBC3                        = 3???
%SQL_IS_POINTER                      = -4
%SQL_IS_UINTEGER                     = -5
%SQL_IS_INTEGER                      = -6
%SQL_IS_USMALLINT                    = -7
%SQL_IS_SMALLINT                     = -8
%SQL_DRIVER_NOPROMPT                 = 0
%SQL_DRIVER_COMPLETE                 = 1
%SQL_DRIVER_PROMPT                   = 2
%SQL_SUCCESS                         = 0
%SQL_SUCCESS_WITH_INFO               = 1
%SQL_NO_DATA                         = 100
%SQL_ERROR                           = -1
%SQL_INVALID_HANDLE                  = -2
%SQL_STILL_EXECUTING                 = 2
%SQL_NEED_DATA                       = 99
%SQL_NTS                             = -3
%SQL_CHAR                            = 1              'sql.h
%SQL_NUMERIC                         = 2              'sql.h
%SQL_DECIMAL                         = 3              'sql.h
%SQL_INTEGER                         = 4              'sql.h
%SQL_SMALLINT                        = 5              'sql.h
%SQL_FLOAT                           = 6              'sql.h
%SQL_REAL                            = 7              'sql.h
%SQL_DOUBLE                          = 8              'sql.h
%SQL_C_CHAR                          = %SQL_CHAR      'sqlext.h
%SQL_C_LONG                          = %SQL_INTEGER   'sqlext.h
%SQL_C_SHORT                         = %SQL_SMALLINT  'sqlext.h
%SQL_C_FLOAT                         = %SQL_REAL      'sqlext.h
%SQL_C_DOUBLE                        = %SQL_DOUBLE    'sqlext.h
%SQL_TINYINT                         = -6
%SQL_WCHAR                           = -8             'sqlucode.h
%SQL_WVARCHAR                        = -9             'sqlucode.h
%SQL_WLONGVARCHAR                    = -10            'sqlucode.h
%SQL_C_WCHAR                         = %SQL_WCHAR     'sqlucode.h
%SQL_SIGNED_OFFSET                   = -20            'sqlext.h
%SQL_UNSIGNED_OFFSET                 = -22            'sqlext.h
%SQL_PARAM_INPUT                     = 1              'sqlext.h  for SQLBindParameter
%SQL_C_TINYINT                       = %SQL_TINYINT
%SQL_C_SLONG                         = (%SQL_C_LONG+%SQL_SIGNED_OFFSET)
%SQL_C_SSHORT                        = (%SQL_C_SHORT+%SQL_SIGNED_OFFSET)
%SQL_C_STINYINT                      = (%SQL_TINYINT+%SQL_SIGNED_OFFSET)
%SQL_C_ULONG                         = (%SQL_C_LONG+%SQL_UNSIGNED_OFFSET)
%SQL_C_USHORT                        = (%SQL_C_SHORT+%SQL_UNSIGNED_OFFSET)
%SQL_C_UTINYINT                      = (%SQL_TINYINT+%SQL_UNSIGNED_OFFSET)
%SQL_TYPE_DATE                       = 91
%SQL_TYPE_TIME                       = 92
%SQL_TYPE_TIMESTAMP                  = 93
%SQL_C_TYPE_DATE                     = %SQL_TYPE_DATE
                                                             

'SQLInstallerError code
%ODBC_ERROR_GENERAL_ERR              = 1
%ODBC_ERROR_INVALID_BUFF_LEN         = 2
%ODBC_ERROR_INVALID_HWND             = 3
%ODBC_ERROR_INVALID_STR              = 4
%ODBC_ERROR_INVALID_REQUEST_TYPE     = 5
%ODBC_ERROR_COMPONENT_NOT_FOUND      = 6
%ODBC_ERROR_INVALID_NAME             = 7
%ODBC_ERROR_INVALID_KEYWORD_VALUE    = 8
%ODBC_ERROR_INVALID_DSN              = 9
%ODBC_ERROR_INVALID_INF              = 10
%ODBC_ERROR_REQUEST_FAILED           = 11
%ODBC_ERROR_INVALID_PATH             = 12
%ODBC_ERROR_LOAD_LIB_FAILED          = 13
%ODBC_ERROR_INVALID_PARAM_SEQUENCE   = 14
%ODBC_ERROR_INVALID_LOG_FILE         = 15
%ODBC_ERROR_USER_CANCELED            = 16
%ODBC_ERROR_USAGE_UPDATE_FAILED      = 17
%ODBC_ERROR_CREATE_DSN_FAILED        = 18
%ODBC_ERROR_WRITING_SYSINFO_FAILED   = 19
%ODBC_ERROR_REMOVE_DSN_FAILED        = 20
%ODBC_ERROR_OUT_OF_MEM               = 21
%ODBC_ERROR_OUTPUT_STRING_TRUNCATED  = 22

'SQLConfigDataSource request flags
%ODBC_ADD_DSN                        = 1
%ODBC_CONFIG_DSN                     = 2
%ODBC_REMOVE_DSN                     = 3
%ODBC_ADD_SYS_DSN                    = 4
%ODBC_CONFIG_SYS_DSN                 = 5
%ODBC_REMOVE_SYS_DSN                 = 6

#If %Def(%UNICODE)
    %SQL_C_TCHAR                      = %SQL_C_WCHAR
#else
    %SQL_C_TCHAR                      = %SQL_C_CHAR
#EndIf

Type tagDATE_STRUCT
  year                                As Integer
  month                               As Word
  day                                 As Word
End Type

Type tagTIMESTAMP_STRUCT
  year                                As Integer
  month                               As Word
  day                                 As Word
  hour                                As Word
  minute                              As Word
  second                              As Word
  fraction                            As Dword
End Type                                     

Declare Function SQLConfigDataSourceA Import "Odbccp32.dll" Alias "SQLConfigDataSource" _
( _
  ByVal hParnt                        As Dword, _
  ByVal iReqst                        As Word, _
  szDriver                            As Asciiz, _
  szAttr                              As Asciiz _
) As Integer

Declare Function SQLConfigDataSourceW Import "Odbccp32.dll" Alias "SQLConfigDataSourceW" _
( _
  ByVal hParnt                        As Dword, _
  ByVal iReqst                        As Word, _
  szDriver                            As WStringz, _
  szAttr                              As WStringz _
) As Integer

Declare Function SQLInstallerErrorA Lib "Odbccp32.dll" Alias "SQLInstallerError" _
( _
  ByVal iErr                          As Word, _
  ByRef pErrCode                      As Dword, _
  ByRef szErrMsg                      As Asciiz, _
  ByVal cbMsgBuffer                   As Word, _
  ByRef cbRet                         As Word _
) As Integer

Declare Function SQLInstallerErrorW Lib "ODBCCP32.DLL" Alias "SQLInstallerErrorW" _
( _
  ByVal iErr As Word, _
  ByRef pErrCode As Dword, _
  ByRef szErrMsg As WStringz, _
  ByVal cbMsgBuffer As Word, _
  ByRef cbRet As Word _
) As Integer

Declare Function SQLAllocHandle Import "Odbc32.dll" Alias "SQLAllocHandle" _
( _
  Byval HandleType                    As Integer, _              ' SQLSMALLINT   HandleType
  Byval InputHandle                   As Dword, _                ' SQLHANDLE     InputHandle
  Byref OutputHandle                  As Dword _                 ' SQLHANDLE*    OutputHandle
) As Integer                                                     ' SQLRETURN

Declare Function SQLSetEnvAttr Import "Odbc32.dll" Alias "SQLSetEnvAttr" _
( _
  Byval EnvironmentHandle             As Dword, _                ' SQLHENV       EnvironmentHandle
  Byval Attribute                     As Long, _                 ' SQLINTEGER    Attribute
  Byref Value                         As Any, _                  ' SQLPOINTER    Value
  Byval StringLength                  As Long _                  ' SQLINTEGER    StringLength
) As Integer                                                     ' SQLRETURN

Declare Function SQLDriverConnectA Import "Odbc32.dll" Alias "SQLDriverConnect" _
( _
  Byval hdbc                          As Dword, _                ' SQLHDBC       hdbc
  Byval hWnd                          As Dword,_                 ' SQLHWND       hwnd
  Byref szConnStrIn                   As Asciiz, _               ' SQLCHAR*      szConnStrIn
  Byval cbConnStrIn                   As Integer, _              ' SQLSMALLINT   cbConnStrIn
  Byref szConnStrOut                  As Asciiz, _               ' SQLCHAR*      szConnStrOut
  Byval cbConnStrOutMax               As Integer, _              ' SQLSMALLINT   cbConnStrOutMax
  Byref pcbConnStrOut                 As Integer, _              ' SQLSMALLINT*  pcbConnStrOut
  Byval fDriverCompletion             As Word _                  ' SQLUSMALLINT  fDriverCompletion
) As Integer                                                     ' SQLRETURN

Declare Function SQLDriverConnectW Import "Odbc32.dll" Alias "SQLDriverConnectW" _
( _
  Byval hdbc                          As Dword, _                ' SQLHDBC       hdbc
  Byval hwnd                          As Dword, _                ' SQLHWND       hwnd
  Byref szConnStrIn                   As WStringz, _             ' SQLWCHAR*     szConnStrIn
  Byval cbConnStrIn                   As Integer, _              ' SQLSMALLINT   cbConnStrIn
  Byref szConnStrOut                  As WStringz, _             ' SQLWCHAR*     szConnStrOut
  Byval cbConnStrOutMax               As Integer, _              ' SQLSMALLINT   cbConnStrOutMax
  Byref pcbConnStrOut                 As Integer, _              ' SQLSMALLINT*  pcbConnStrOut
  Byval fDriverCompletion             As Word _                  ' SQLUSMALLINT  fDriverCompletion
) As Integer                                                     ' SQLRETURN

Declare Function SQLPrepareA Import "Odbc32.dll" Alias "SQLPrepare" _
( _
  Byval StatementHandle               As Dword, _                ' SQLHSTMT      StatementHandle
  Byref StatementText                 As Asciiz, _               ' SQLCHAR*      StatementText
  Byval TextLength                    As Long _                  ' SQLINTEGER    TextLength
) As Integer                                                     ' SQLRETURN

Declare Function SQLPrepareW Import "Odbc32.dll" Alias "SQLPrepareW" _
( _
  Byval StatementHandle               As Dword, _                ' SQLHSTMT      StatementHandle
  Byref StatementText                 As WStringz, _             ' SQLWCHAR*     szSqlStr
  Byval TextLength                    As Long _                  ' SQLINTEGER    TextLength
) As Integer                                                     ' SQLRETURN

Declare Function SQLBindParameter Import "Odbc32.dll" Alias "SQLBindParameter" _
( _
  Byval hstmt                         As Dword, _                ' SQLHSTMT      hstmt
  Byval ipar                          As Word, _                 ' SQLUSMALLINT  ipar
  Byval fParamType                    As Integer, _              ' SQLSMALLINT   fParamType
  Byval fCType                        As Integer, _              ' SQLSMALLINT   fCType
  Byval fSqlType                      As Integer, _              ' SQLSMALLINT   fSqlType
  Byval cbColDef                      As Dword, _                ' SQLULEN       cbColDef
  Byval ibScale                       As Integer, _              ' SQLSMALLINT   ibScale
  Byref rgbValue                      As Any, _                  ' SQLPOINTER    rgbValue
  Byval cbValueMax                    As Long, _                 ' SQLLEN        cbValueMax
  Byref pcbValue                      As Long _                  ' SQLLEN*       pcbValue
) As Integer                                                     ' SQLRETURN

Declare Function SQLExecute Import "Odbc32.dll" Alias "SQLExecute" _
( _
  Byval StatementHandle               As Dword _                 ' SQLHSTMT      StatementHandle
) As Integer                                                     ' SQLRETURN

Declare Function SQLExecDirectA Import "Odbc32.dll" Alias "SQLExecDirect" _
( _
  Byval StatementHandle               As Dword, _                ' SQLHSTMT      StatementHandle
  Byref StatementText                 As Asciiz, _               ' SQLCHAR*      StatementText
  Byval TextLength                    As Long _                  ' SQLINTEGER    TextLength
) As Integer                                                     ' SQLRETURN

Declare Function SQLExecDirectW Import "Odbc32.dll" Alias "SQLExecDirectW" _
( _
  Byval hstmt                         As Dword, _                ' SQLHSTMT      hstmt
  Byref szSqlStr                      As WStringz, _             ' SQLWCHAR*     szSqlStr
  Byval cbSqlStr                      As Long _                  ' SQLINTEGER    cbSqlStr
) As Integer                                                     ' SQLRETURN

Declare Function SQLBindCol Import "Odbc32.dll" Alias "SQLBindCol" _
( _
  Byval StatementHandle               As Dword, _                ' SQLHSTMT      StatementHandle
  Byval ColumnNumber                  As Integer, _              ' SQLUSMALLINT  ColumnNumber
  Byval TargetType                    As Integer, _              ' SQLSMALLINT   TargetType
  Byref TargetValue                   As Any, _                  ' SQLPOINTER    TargetValue
  Byval BufferLength                  As Long, _                 ' SQLLEN        BufferLength
  Byref StrLen_or_Ind                 As Long _                  ' SQLLEN*       StrLen_or_Ind
) As Integer                                                     ' SQLRETURN

Declare Function SQLFetch Import "Odbc32.dll" Alias "SQLFetch" _
( _
  Byval StatementHandle               As Dword _                 ' SQLHSTMT      StatementHandle
) As Integer                                                     ' SQLRETURN

Declare Function SQLGetDiagRecA Import "Odbc32.dll" Alias "SQLGetDiagRec" _
( _
  Byval HandleType                    As Integer, _              ' SQLSMALLINT   HandleType
  Byval Handle                        As Dword, _                ' SQLHANDLE     Handle
  Byval RecNumber                     As Integer, _              ' SQLSMALLINT   RecNumber
  Byref Sqlstate                      As Asciiz, _               ' SQLCHAR*      Sqlstate
  Byref NativeError                   As Long, _                 ' SQLINTEGER*   NativeError
  Byref MessageText                   As Asciiz, _               ' SQLCHAR*      MessageText
  Byval BufferLength                  As Integer, _              ' SQLSMALLINT   BufferLength
  Byref TextLength                    As Integer _               ' SQLSMALLINT*  TextLength
) As Integer                                                     ' SQLRETURN

Declare Function SQLGetDiagRecW Import "Odbc32.dll" Alias "SQLGetDiagRecW" _
( _
  Byval fHandleType                   As Integer, _              ' SQLSMALLINT   fHandleType
  Byval handle                        As Dword, _                ' SQLHANDLE     handle
  Byval iRecord                       As Integer, _              ' SQLSMALLINT   iRecord
  Byref szSqlState                    As WStringz, _             ' SQLWCHAR*     szSqlState
  Byref pfNativeError                 As Long, _                 ' SQLINTEGER*   pfNativeError
  Byref szErrorMsg                    As WStringz, _             ' SQLWCHAR*     szErrorMsg
  Byval cbErrorMsgMax                 As Integer, _              ' SQLSMALLINT   cbErrorMsgMax
  Byref pcbErrorMsg                   As Integer _               ' SQLSMALLINT*  pcbErrorMsg
) As Integer                                                     ' SQLRETURN

Declare Function SQLDisconnect Import "Odbc32.dll" Alias "SQLDisconnect" _
( _
  Byval ConnectionHandle              As Dword _                 ' SQLHDBC       ConnectionHandle
) As Integer                                                     ' SQLRETURN

Declare Function SQLCloseCursor Import "Odbc32.dll" Alias "SQLCloseCursor" _
( _
  Byval StatementHandle               As Dword _                 ' SQLHSTMT      StatementHandle
) As Integer                                                     ' SQLRETURN

Declare Function SQLFreeHandle Import "Odbc32.dll" Alias "SQLFreeHandle" _
( _
  Byval HandleType                    As Integer, _              ' SQLSMALLINT   HandleType
  Byval Handle                        As Dword _                 ' SQLHANDLE     Handle
) As Integer                                                     ' SQLRETURN

#If %Def(%UNICODE)
    Macro SQLConfigDataSource         = SQLConfigDataSourceW
    Macro SQLInstallerError           = SQLInstallerErrorW
    Macro SQLDriverConnect            = SQLDriverConnectW
    Macro SQLGetDiagRec               = SQLGetDiagRecW
    Macro SQLPrepare                  = SQLPrepareW
    Macro SQLExecDirect               = SQLExecDirectW
#Else
    Macro SQLConfigDataSource         = SQLConfigDataSourceA
    Macro SQLInstallerError           = SQLInstallerErrorA
    Macro SQLDriverConnect            = SQLDriverConnectA
    Macro SQLGetDiagRec               = SQLGetDiagRecA
    Macro SQLPrepare                  = SQLPrepareA
    Macro SQLExecDirect               = SQLExecDirectA
#EndIf


Frederick J. Harris

And CSql.inc


'CSql.inc

Class CSql Common
  Instance m_strConnectionString As BStr
  Instance m_strDatabase         As BStr
  Instance m_strDriver           As BStr
  Instance m_strServer           As BStr
  Instance m_strDBQ              As BStr
  Instance m_szCnStrOut          As ZStr * 512
  Instance iBytes                As Integer
  Instance swStrLen              As Integer
  Instance m_hEnvr               As Dword
  Instance m_hConn               As Dword
  Instance m_iNativeErrPtr       As Long
  Instance m_iTextLenPtr         As Integer
  Instance m_szErrCode           As ZStr * 8
  Instance m_szErrMsg            As ZStr * 512
  Instance m_blnConnected        As Long

  Interface ISql : Inherit IUnknown
    Property Get strDatabase() As BStr
      Property=m_strDatabase
    End Property

    Property Set strDatabase(Byval strName As BStr)
      m_strDatabase=strName
    End Property

    Property Get strDriver() As BStr
      Property=m_strDriver
    End Property

    Property Set strDriver(Byval strName As BStr)
      m_strDriver=strName
    End Property

    Property Get strServer() As BStr
      Property=m_strServer
    End Property

    Property Set strServer(Byval strName As BStr)
      m_strServer=strName
    End Property

    Property Get hConn() As Dword
      Property=m_hConn
    End Property

    Property Get strDBQ() As BStr
      Property=m_strDBQ
    End Property

    Property Set strDBQ(Byval strName As BStr)
      m_strDBQ=strName
    End Property

    Property Get strConnectionString() As BStr
      Property=m_strConnectionString
    End Property

    Property Set strConnectionString(Byval strName As BStr)
      m_strConnectionString=strName
    End Property

    Property Get blnConnected() As Long
      Property=m_blnConnected
    End Property

    Property Set blnConnected(Byval iConnected As Long)
      m_blnConnected=iConnected
    End Property

    Property Get strErrCode() As BStr
      Property=m_szErrCode
    End Property

    Property Get strErrMsg() As BStr
      Property=m_szErrMsg
    End Property

    Property Get iNativeErrCode() As Long
      Property=m_iNativeErrPtr
    End Property

    Method MakeConnectionString()
      If m_strConnectionString="" Then
         Select Case m_strDriver
           Case "SQL Server"
             If m_strDBQ="" Then
                m_strConnectionString= _
                "DRIVER="              & m_strDriver        & ";" & _
                "SERVER="              & m_strServer        & ";"
             Else
                m_strConnectionString= _
                "DRIVER="              & m_strDriver        & ";" & _
                "SERVER="              & m_strServer        & ";" & _
                "DATABASE="            & m_strDatabase      & ";" & _
                "DBQ="                 & m_strDBQ           & ";"
             End If
           Case "Microsoft Access Driver (*.mdb)"
             m_strConnectionString= _
             "DRIVER="                 & m_strDriver        & ";" & _
             "DBQ="                    & m_strDBQ           & ";"
           Case "Microsoft Excel Driver (*.xls)"
             m_strConnectionString= _
             "DRIVER="                 & m_strDriver        & ";" & _
             "DBQ="                    & m_strDBQ           & ";"
         End Select
      End If
    End Method

    Method ODBCConnect()
      Local szCnIn  As ZStr * 512
      Local szCnOut As ZStr * 512
      Local iRet    As Long

      Me.MakeConnectionString()
      Call SQLAllocHandle(%SQL_HANDLE_ENV,%SQL_NULL_HANDLE,m_hEnvr)
      Call SQLSetEnvAttr(m_hEnvr,%SQL_ATTR_ODBC_VERSION,ByVal %SQL_OV_ODBC3,%SQL_IS_INTEGER)
      Call SQLAllocHandle(%SQL_HANDLE_DBC,m_hEnvr,m_hConn)
      szCnIn=m_strConnectionString
      iRet=SQLDriverConnect(m_hConn,0,szCnIn,Len(szCnIn),szCnOut,512,iBytes,%SQL_DRIVER_NOPROMPT)
      If iRet=0 Or iRet=1 Then
         m_blnConnected=%TRUE
      Else
         m_blnConnected=%FALSE
         Call SQLGetDiagRec(%SQL_HANDLE_DBC,m_hConn,1,m_szErrCode,m_iNativeErrPtr,m_szErrMsg,512,m_iTextLenPtr)
      End If
    End Method

    Method ODBCGetDiagRec(Byval hStmt As Dword)
      Call SQLGetDiagRec(%SQL_HANDLE_STMT,hStmt,1,m_szErrCode,m_iNativeErrPtr,m_szErrMsg,512,m_iTextLenPtr)
    End Method

    Method ODBCDisconnect()
      If Me.blnConnected=%TRUE Then
         Call SQLDisconnect(m_hConn)                  'Disconnect From Data Source
         Call SQLFreeHandle(%SQL_HANDLE_DBC,m_hConn)  'Free Connection Handle
         Call SQLFreeHandle(%SQL_HANDLE_ENV,m_hEnvr)  'Free Environment Handle
      End If
    End Method
  End Interface
End Class


Frederick J. Harris

So there you have a full working PowerBASIC program that does, to the best of my knowledge, everything my original Visual Basic 6 program does as first described with an ADO Data Control feeding into a Data Bound Grid Control connecting to the Titles Table of Biblio.mdb.  If compiled with the PowerBASIC includes in a Release Build, i.e., %Debug not defined, it compiles to 36864 bytes.  With Jose's includes it comes to 40,960 bytes.  If we add the 22,016 of the grid dll we have 58,880 bytes or 58 K.  Comparing that to the Visual Basic 6 project with the ADO Data Control and the Data Bound Grid we have this...


DataGrid.cab   9457 K
Setup.exe       137 K
Setup.lst         4 K
=====================
               9598 K


Almost 10 Megabytes.  Dividing it out the PowerBASIC critter is 165 times smaller!  OK, lets get to the details.

     For database access I just used my own simple ODBC wrapper class.  Its primary purpose is to hide the nastiness of SQLDriverConnect(), which can get ugly.  In fnWndProc_OnCreate(), which is VB's Form_Load(), you'll see the code to open the Titles Table of Biblio.mdb.  I used equates there ($DB_PATH and $DB_DRIVER), but it amounts to this...


Local pSql As ISql

pSql           =  Class "CSql"
pSql.strDBQ    =  "C:\Program Files (x86)\Microsoft Visual Studio\VB98\Biblio.mdb"
pSql.strDriver =  "Microsoft Access Driver (*.mdb)"
Call pSql.ODBCConnect()
If pSql.blnConnected Then
   ...
   ... do whatever...

   pSql.ODBCDisconnect()
End If
[CODE]

...anytime you want to read/write database data.  Within the enclosing If in fnWndProc_OnCreate() you'll see a call to blnGetRecordCount(pSql, iRecordCount) which code determines the count of records in the Titles Table, which is around 8600.  Then you'll note I multiply iRecordCount by 1.01.  Reason I did that was to configure the grid to hold an additional 86 rows if somebody is inclined to add more books.  That's how I deal with 'AddNew' functionality.  Quick and dirty I admit.  Now the next several lines of code is definitely going to require some explanation from me!

[CODE]
hHeap = GetProcessHeap()
pEditFlags = HeapAlloc(hHeap, %HEAP_ZERO_MEMORY, sizeof(EditFlags))
If pEditFlags Then
    @pEditFlags.iRecords = iRecordCount
    @pEditFlags.pEdits   = HeapAlloc(hHeap, %HEAP_ZERO_MEMORY, iRecordCount+1)
    ...
    ...


The situation is this.  You've got a grid full of data in row x column format and you've got to track what the user does to the data.  And how in the world would you do that?  Well, look up in my CGridEvents Class.  There are Grid_OnKeyPress() and Grid_OnKeyDown() Event Procedures that fire every time the user presses a key while focus is in a grid cell.  And the row and column of the cell where this occurred is transferred through the parameters!  So that's the key.  So a flag, i.e., a Boolean true/false setup, is going to have to be created to track all this.  Except there's going to be more than one scalar true/false value.  The Titles Table has about 8700 rows and each row comprises 8 columns or fields.  Multiplying that out comes to 68800 Boolean flags!  So one way of doing it would be to create a two dimensional byte array with 8700 rows and 8 columns.  The overhead of doing that would be about 68 K.  Another related issue is the scope of the array.  Any changes a user makes to the data, which would set one of these flags, must persist through the lifetime of the program run.  This suggests global or static storage.  However, I prefer to make life interesting and tackle challenges, and I don't want life to become too easy, so I never use global variables.  Have you noticed there haven't been any in any of the programs I've posted so far?

     So here's what I do.   I don't use byte variables to track each field or column in the grid.  I just use bits.  The Titles Table has 8 fields or columns, so that works out good to just allocate a byte for each row, and set the bit within the byte corresponding to each column.  When the Titles Table is Opened by blnGetRecordCount() and the iRecordCount parameter is initialized to the count of records in the table which actually looks to be 8569, then I do two separate memory allocations with HeapAlloc().  First, I allocate one of these in fnWndProc_OnCreate() ...


Type EditFlags
  iRecords                As Long
  pEdits                  As Byte Ptr
End Type


You'll find that Type near the top of FHGrid2.bas.  Since it contains two elements each of which occupies four bytes on a 32 bit operating system, the whole thing is just eighy bytes in size.  So this function call...


Local pEditFlags As EditFlags Ptr
pEditFlags = HeapAlloc(hHeap, %HEAP_ZERO_MEMORY, sizeof(EditFlags))


...will return to me in pEditFlags the starting address of an 8 byte block of memory where those two variables will live for the duration of a program run.  I store that address in the 2nd four byte 'slot' in the WNDCLASSEX::cbWndExtra bytes of Window Class memory for the "Test My Grid" Window Class (Registered in WinMain())....


SetWindowLong(Wea.hWnd, 4, pEditFlags)


That memory is released in fnWndProc_OnDestroy(), which is about equivalent to Form_Unload() in old VB6. But next in fnWndProc_OnCreate I do this ...


@pEditFlags.iRecords = iRecordCount
@pEditFlags.pEdits   = HeapAlloc(hHeap, %HEAP_ZERO_MEMORY, iRecordCount+1)


I store the number of records or rows that will be allocated in the grid at @pEditFlags.iRecords, and that is something like that 8600 – 8700 number.  Then for ...


@pEditFlags.pEdits  = HeapAlloc(hHeap, %HEAP_ZERO_MEMORY, iRecordCount + 1)


...I do another HeapAlloc() call to get a pointer to another block of memory containing 8600 – 8700 or so bytes – one byte for each row of the grid.  I allocate one more than I need so I can use 1 based indexing instead of zero based indexing.  So I'm wasting one byte!  The grid returns one based index info in those KeyPress()/KeyDown() event procedures.  And related closely to all this is the KeyPress() Event proceure itself in Class CgridEvents...



Class CGridEvents  As Event
  Instance hMain As Dword

  Class Method Create()
    hMain=FindWindow("Test My Grid","Test My Grid")
  End Method

  Interface IGridEvents $IID_IGridEvents : Inherit IAutomation
    Method Grid_OnKeyPress(Byval iKeyCode As Long, Byval iKeyData As Long, Byval iRow As Long, Byval iCol As Long, Byref blnCancel As Long)
      Local pEditFlags As EditFlags Ptr
      pEditFlags=GetWindowLong(hMain,4)
      If pEditFlags And @pEditFlags.pEdits Then
         @pEditFlags.@pEdits[iRow] = @pEditFlags.@pEdits[iRow] Or 2^(iCol-1)
      End If
    End Method     
    ...
    ...
  End Interface
End Class


Let me explain what's taking place there.  In fnWndProc_OnCreate() we have this variable declaration...


Local pSink As IGridEvents


...and later on down when we set up the event sink, we have this...


pSink = Class "CGridEvents"
Events From pGrid Call pSink


     Don't get put off by the terminology.  In the COM documentation code which gets called from within a COM object is sometimes referred to as a 'sink', i.e., the code is 'sinking' the events fired off by the COM object as the user interacts with it. 

     And when the CGridEvents Class is instantiated its Create() Method, i.e., its 'Constructor' in OOP (Object Oriented Programming) speak, is called.  And looking in 'Class Method Create()' above what you can see getting done is a call to the Windows Api function FindWindow(), where its looking for a window of Class "Test My Grid" which has "Test My Grid" for its caption.  Its storing the Window Handle of the Window it finds in its single Instance variable hMain.  That number, whatever it is, will persist for the lifetime of the app's run in that Instance variable.  It will be there when the user interacts with the grid data by pressing a key to modify an existing record, or add a new one.  When that happens I access our stored byte array allocated in fnWndProc_OnCreate(), and I set the zero based bit corresponding to the col parameter passed in from the grid...


Local pEditFlags As EditFlags Ptr
pEditFlags=GetWindowLong(hMain,4)
If pEditFlags And @pEditFlags.pEdits Then
   @pEditFlags.@pEdits[iRow] = @pEditFlags.@pEdits[iRow] Or 2^(iCol-1)
End If


     Of course, the iRow parameter will index us into the correct byte offset from the initial pEditFlags memory allocation.  And we'll 'Or' that bit into place using the expression ...


@pEditFlags.@pEdits[iRow] Or 2^(iCol-1)


     If the first column is edited for example, iCol will come in equaling 1.  1 – 1 equals zero, so 2 or any number for that matter raised to the zeroth power equals 1.  So the zeroth zero based bit will be set to 1, informing the program that the 1st field of the iRow record has been edited.  So on and so forth for all the other bits.  If a new record is entered at the end of the grid data and all eight fields/columns are filled in, that byte will end up with an arithmetic value of 255, i.e.,


1  X  2 ^ 0  =      1
1  X  2 ^ 1  =      2
1  X  2 ^ 2  =      4
1  X  2 ^ 3  =      8
1  X  2 ^ 4  =     16
1  X  2 ^ 5  =     32
1  X  2 ^ 6  =     64
1  X  2 ^ 7  =    128
=====================
                  255


     I might point out there are other ways of going about this that are in some ways simpler.  For example, one might simply allocate iRecordCount + 1 Word variables, and store the iRecordCount number at offset zero something like this ...


Local pEdits As Word Ptr
PEdits = HeapAlloc(GetProcessHeap(), %HEAP_ZERO_MEMORY, (iRecordCount + 1) * Sizeof(Word))


     That way you would be able to do away with the EditFlags Type.  Only thing is it would use double the memory needed, and would be wasting bits 8 through 15 of every Word because we only have 8 columns.  But we can't use bytes and store 8659 at @pEdit[0] if we're accessing bytes because 8659 won't store in a byte.  That's why I used a UDT (User Defined Type) that contained a Long member to store big numbers, and a Byte Pointer member to just store column information where the iCol returned will never exceed 8.  Verstehen Sie?

     About the last thing I might mention in fnWndProc_OnCreate() is how the grid was created.  As I mentioned, we can just use PowerBASIC's NewCom statement, and all the information needed to configure the grid is contained in the FHGrid9::CreateGrid() call..


pGrid = NewCom "FHGrid9.Grid"
...
...
strSetup= _
"300:Title:^:edit," & _
"200:Year Published:^:edit," & _
"150:ISBN:^:edit," & _
"90:PubID:^:edit," & _
"200:Description:^:edit," & _
"90:Notes:^:edit," & _
"100:Subject:^:edit," & _
"110:Comments:^:edit"
pGrid.CreateGrid(Wea.hWnd,strSetup,10,10,850,500,iRecordCount,8,20,0,0,"Times New Roman",12,%FW_LIGHT)


     The column information is a comma delimited string, and each sub-string between the commas is further delimited into sub-strings with the ':' character.  For example, column 1 is 300 pixels wide, the caption is "Title", it is centered in the column label, i.e., '^', and an edit control is used for the cell (the only other choice at this time for my grid is a combo box).  You can look at the CreateGrid() method in the interface definition to see what all the parameters are.  Otherwise, I've added comments to the code here and there explaining things you might be unfamiliar with.

     But I want to discuss deletion a bit.  The way it works in my grid is that it has built into it a concept known as selection.  When you click any of the buttons along the left side of each row it highlights the whole row.  In other words, it selects that row.  Clicking on that button again deselects it.  But while a row is selected, if you hit your [DELETE] key, a Grid_OnDelete(Byval iRow As Long) message is fired at the client's sink.  But that won't cause the row to be deleted.  I didn't want to make it all that automatic, for a foresaw usages in applications where deletions wouldn't be allowed or needed.  So what has to happen in Grid_OnDelete() if you want to indeed delete that row is to call IGrid::DeleteRow(Byval iRow As Long), passing in the same iRow parameter as the one passed into the event procedure.  But you must realize that doing that will only delete the data the grid is storing for that row – it won't delete the data in the underlying data source.  For that you'll need to write additional code.  If the underlying data is from a relational database supporting SQL, then you'll need to execute a DELETE FROM statement.

     I've explained above how I use bits in byte variables to track user edits to data in the grids, and how I create an array of these bytes synchronized with the rows of grid data.  But deletions could desynchronize the alignment of bytes with the rows they are to track.  So in the deletion code quite early on I call UpdateDatabase() to take care of and clean up any updates or insertions the user might have made.  After that a DELETE FROM query is executed to delete the data from the database, and one of the last calls in Grid_OnDelete() is the pGrid.DeleteRow(iRow) call which removes the data from the grid for that row.

Frederick J. Harris

     I'll move on to the MSFlexGrid now.  That defeated me with deletions, so the code I'll present works fine for updates and insertions, but in the couple hours I threw at deletions I failed.  Perhaps you'll have more luck.  I suppose part of the problem is that with my grid I wrote it myself and have full knowledge of how it works.  Some of the behaviors of the MSFlexGrid just mystify me even though I've used it a fair amount in both Visual Basic and PowerBASIC.  For one thing, those little buttons to the left of each row aren't enabled like in my grid.  At least, they don't respond in any way to clicks.  And when I try to select a row, the 1st cell to the right of the button doesn't select.  I've no idea why not.  Another thing about the MSFlxGrd is that the event procedures mostly have few or no parameters.  Here is the KeyPress() event proc from my grid ...


Method Grid_OnKeyPress(Byval iKeyCode As Long, Byval iKeyData As Long, Byval iRow As Long, Byval iCol As Long, Byref blnCancel As Long)


And here it is from the MSFlxGrd...


Method KeyPress <-603> (Byref KeyAscii As Integer)   


So when a KeyPress() comes in, you've got to call dispinterface methods on the IGrid interface to retrieve the row and column where the keypress occurred.  And even more miserably, when the user sets focus to a cell and attempts to type something in, the default behavior of the grid is to do nothing.  At least as far as I know.  Unless there is some setting to cause the text to show up.  What I've always done going all the way back to my VB days in the late 90s was to execute code like so for each keypress ...









Method KeyPress <-603> (Byref KeyAscii As Integer)
  Local pGridInterfaces As GridInterfaces Ptr
  Local pEditFlags As EditFlags Ptr
  Local pFlexGrid As IMSFlexGrid
  Local pDisp As IDispatch
  Local strText As WString
  Local iRow,iCol As Long

  pGridInterfaces=GetWindowLong(hMain,0)
  If pGridInterfaces Then
     If @pGridInterfaces.pGrid Then
        CObj(pFlexGrid,@pGridInterfaces.pGrid)
        pFlexGrid.AddRef()
        pDisp=pFlexGrid
        If IsObject(pDisp) Then
           Object Get pDisp.Row To iRow
           Object Get pDisp.Col To iCol
           pEditFlags=GetWindowLong(hMain,4)
           If pEditFlags And @pEditFlags.pEdits Then
              @pEditFlags.@pEdits[iRow] = @pEditFlags.@pEdits[iRow] Or 2^(iCol-1)
           End If
           If KeyAscii=8 Then
              Object Get pDisp.Text() To strText
              strText=Left$(strText,Len(strText)-1)
              Object Let pDisp.Text()=strText
           Else
              Object Get pDisp.Text() To strText
              strText=strText+Chr$(KeyAscii)
              Object Let pDisp.Text()=strText
           End If
        End If
     End If
  End If
End Method       


But without further adieu here is MSFlexGrid_JRI.bas.  The 'JRI' part stands for Jose Roca Includes.  It uses his OleCon.inc ActiveX Control Container as opposed to the ATL code.  And it uses the COM includes generated by his TypeLib Browser ...