Grid Custom Control Project - Converting It To COM

Started by Frederick J. Harris, July 26, 2011, 05:56:21 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Frederick J. Harris

' PBClient6.bas
' Here we'll try setting pGrid and pConnectionPoint to Nothing within DestroyGrid(), to
' reinforce our knowledge of the effects of Release() calls verses the Nothing keyword
' in terms of object destruction.  Here is the console output from making those changes
' in DestroyGrid() ...
' Entering fnWndProc_OnDestroy()
'   Entering DestroyGrid()
'     Entering IGrid_QueryInterface()
'       Trying To Get IConnectionPoint
'       this =  4457760
'       Entering IConnectionPoint_AddRef()
'         @pGrid.m_cRef =  1  << Before
'         @pGrid.m_cRef =  2  << After
'       Leaving IConnectionPoint_AddRef()
'       this =  4457768
'     Leaving IGrid_QueryInterface()
'     Entering IConnectionPoint_Unadvise()
'       this            =  4457768
'       dwCookie        =  0
'       @pGrid.hWndCtrl =  9961994
'       dwPtr           =  4465020
'       IGrid_Events::Release() Succeeded!
'       Release() Returned  0
'     Leaving IConnectionPoint_Unadvise()
'     Entering IGrid_Release()
'       @pGrid.m_cRef =  2  << Before
'       @pGrid.m_cRef =  1  << After
'     Leaving IGrid_Release()
'     Entering IConnectionPoint_Release()
'       @pGrid.m_cRef =  1    << Before
'       0     4189112     0
'       1     4189116     0
'       2     4189120     0
'       3     4189124     0
'       @pGrid.m_cRef = 0 And Will Now Delete pGrid!
'     Leaving IConnectionPoint_Release()
'   Leaving DestroyGrid()
'   Entering DllCanUnloadNow()
'     I'm Outta Here! (dll is unloaded)
'   Leaving DllCanUnloadNow()
' Leaving fnWndProc_OnDestroy()
' If you compare with PBClient5, you'll see the only difference is that Release() calls
' were triggered by setting pGrid and pConnectionPoint to Nothing, and of course these
' Release() calls occurred within the execution of the DestroyGrid() procedure, as
' opposed to their occurrence afterwards through PowerBASIC's stack clean up code.
#Compile                  Exe  "PBClient6.exe"
#Dim                      All
%UNICODE                  = 1
#If %Def(%UNICODE)
    Macro ZStr            = WStringz
    Macro BStr            = WString
    %SIZEOF_CHAR          = 2
    Macro ZStr            = Asciiz
    Macro BStr            = String
    %SIZEOF_CHAR          = 1
$CLSID_FHGrid             = GUID$("{20000000-0000-0000-0000-000000000084}")
$IID_IFHGrid              = GUID$("{20000000-0000-0000-0000-000000000085}")
$IID_IGridEvents          = GUID$("{20000000-0000-0000-0000-000000000086}")
%IDC_RETRIEVE             = 1500
%IDC_COLOR                = 1505
%IDC_UNLOAD_GRID          = 1510
#Include                  ""    ' Uses PowerBASIC Includes

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  ' used to convert an address to an object.  this could
                                                              ' be a new feature suggestion!

Sub Prnt(strLn As BStr)
  Local iLen, iWritten As Long
  Local hStdOutput As Dword
  Local strNew As BStr
  strNew=strLn + $CrLf
  iLen = Len(strNew)
  WriteConsole(hStdOutput, Byval Strptr(strNew), iLen, iWritten, Byval 0)
End Sub

Interface IGrid $IID_IFHGrid : Inherit IAutomation    ' This is the Grid's Interface (a standard incoming Interface, i.e.,
  Method CreateGrid _                                 ' method calls are coming into the grid from the client).
  ( _
    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 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 GetCtrlId() As Long
  Method GethGrid() 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()
    Prnt "  Called Class Method Create()!"
    Prnt "    hMain = " & Str$(hMain)
    Prnt "  Leaving Class Method Create()
  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)
      Prnt "Got KeyPress From CGridEvents1!" & Str$(iKeyCode) & "=" & Chr$(iKeyCode)
    End Method
    Method Grid_OnKeyDown(Byval iKeyCode As Long, Byval iKeyData As Long, Byval iRow As Long, Byval iCol As Long, Byref blnCancel As Long)
      Prnt "Got KeyDown From CGridEvents1!" & Str$(iKeyCode) & "=" & Chr$(iKeyCode)
    End Method
    Method Grid_OnLButtonDown(Byval iCellRow As Long, Byval iGridRow As Long, Byval iCol As Long)
      Prnt "Got WM_LBUTTONDOWN In Grid Cell From CGridEvents1" & "(" & Trim$(Str$(iGridRow)) & "," & Trim$(Str$(iCol)) & ")"
    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)
      Prnt "  Entering Grid_OnRowSelection(GridEvents)"
      Prnt "    iRow    = " & Str$(iRow)
      Prnt "    iAction = " & Str$(iAction)
      If iAction Then
         Call SetWindowLong(hMain,8,iRow)
         Call SetWindowLong(hMain,8,0)
      End If
      Prnt "  Leaving Grid_OnRowSelection(GridEvents)"
    End Method
    Method Grid_OnDelete(Byval iRow As Long)
      Local pGrid As IGrid
      Local dwPtr As Dword

      Prnt "  Entering Grid_OnDelete()"
      Prnt "    iRow = " & Str$(iRow)
      Call pGrid.AddRef()
      Call pGrid.DeleteRow(iRow)
      Call pGrid.Refresh()
      Prnt "  Leaving Grid_OnDelete()"
    End Method
  End Interface
End Class

Function fnWndProc_OnCreate(Wea As WndEventArgs) As Long          'Offset      Item
  Local pConnectionPointContainer As IConnectionPointContainer    '=====================================================================
  Local pConnectionPoint As IConnectionPoint                      '0  -  3     IGrid Ptr - pGrid
  Local pCreateStruct As CREATESTRUCT Ptr                         '4  -  7     dwCookie
  Local strSetup,strCoordinate As BStr                            '8  - 11     iSelectedRow
  Local pSink As IGridEvents
  Local EventGuid As Guid
  Local dwCookie As Dword
  Local szName As ZStr*16
  Local pGrid As IGrid
  Local hCtl As Dword
  Register i As Long
  Register j As Long

  Call AllocConsole()
  Prnt "Entering fnWndProc_OnCreate()"
  pCreateStruct=wea.lParam : wea.hInst=@pCreateStruct.hInstance
  Let pGrid = NewCom "FHGrid8.Grid"
  Prnt "  Objptr(pGrid) = " & Str$(Objptr(pGrid))
  Call SetWindowLong(Wea.hWnd,0,Objptr(pGrid))
  strSetup="120:Column 1:^:edit,130:Column 2:^:edit,140:Column 3:^:edit,150:Column 4:^:edit,160:Column 5:^:combo"
  pGrid.CreateGrid(Wea.hWnd,strSetup,190,10,570,218,12,5,28,0,0,"Times New Roman",18,%FW_DONTCARE)
  pConnectionPointContainer = pGrid
  Call pConnectionPointContainer.FindConnectionPoint(Byval Varptr(EventGuid),Byval Varptr(pConnectionPoint))
  Let pSink = Class  "CGridEvents"
  Prnt "  Objptr(pSink) = " & Str$(Objptr(pSink))
  Call pConnectionPoint.Advise(Byval Objptr(pSink), dwCookie)
  Prnt "  dwCookie      = " & Str$(dwCookie)
  Call SetWindowLong(Wea.hWnd,4,dwCookie)
  For i=1 To 12
    For j=1 To 5
      strCoordinate="(" & Trim$(Str$(i)) & "," & Trim$(Str$(j)) & ")"
      pGrid.SetData(i, j, strCoordinate)
    Next j
  Next i
  hCtl=CreateWindow("button","Retrieve Cell (3,2)",%WS_CHILD Or %WS_VISIBLE,10,20,150,30,Wea.hWnd,%IDC_RETRIEVE,Wea.hInst,ByVal 0)
  hCtl=CreateWindow("button","Color Some Rows",%WS_CHILD Or %WS_VISIBLE,10,70,150,30,Wea.hWnd,%IDC_COLOR,Wea.hInst,ByVal 0)
  hCtl=CreateWindow("button","Get Selected Row",%WS_CHILD Or %WS_VISIBLE,10,120,150,30,Wea.hWnd,%IDC_GET_SELECTED_ROW,Wea.hInst,ByVal 0)
  hCtl=CreateWindow("button","Unload Grid",%WS_CHILD Or %WS_VISIBLE,10,170,150,30,Wea.hWnd,%IDC_UNLOAD_GRID,Wea.hInst,ByVal 0)
  hCtl=pGrid.GethComboBox(5)     ' this line and method gets the handle to the combo box put in the 5th column of the grid
  Prnt "  hCtl = " & Str$(hCtl)
  szName="Frederick" : Call SendMessage(hCtl,%CB_INSERTSTRING,-1,Varptr(szName))     ' put some strings in the combo box
  szName="Elsie"     : Call SendMessage(hCtl,%CB_INSERTSTRING,-1,Varptr(szName))
  szName="Scott"     : Call SendMessage(hCtl,%CB_INSERTSTRING,-1,Varptr(szName))
  szName="Lorrie"    : Call SendMessage(hCtl,%CB_INSERTSTRING,-1,Varptr(szName))
  szName="Joseph"    : Call SendMessage(hCtl,%CB_INSERTSTRING,-1,Varptr(szName))
  szName="Frank"     : Call SendMessage(hCtl,%CB_INSERTSTRING,-1,Varptr(szName))
  Prnt "Leaving fnWndProc_OnCreate()"

End Function

Sub DestroyGrid(Wea As WndEventArgs)
  Local pConnectionPoint As IConnectionPoint
  Local dwCookie,dwPtr As Dword
  Local pGrid As IGrid

  Prnt "  Entering DestroyGrid()"
  If dwPtr Then
     Call pConnectionPoint.Unadvise(dwCookie)
     Call SetWindowLong(Wea.hWnd,0,0)
     Call SetWindowLong(Wea.hWnd,4,0)
     Let pGrid            = Nothing
     Let pConnectionPoint = Nothing
     Prnt "    pGrid Was Already Released!"
  End If
  Prnt "  Leaving DestroyGrid()"
End Sub

Function fnWndProc_OnCommand(Wea As WndEventArgs) As Long
  Local strData As BStr
  Local pGrid As IGrid
  Local dwPtr As Dword
  Local iCnt As Long
  Register i As Long

  Select Case As Long Lowrd(Wea.wParam)
      Prnt "Entering fnWndProc_OnCommand()"
      Prnt "  Case %IDC_RETRIEVE"
      Prnt "  dwPtr = " & Str$(dwPtr)
      Call pGrid.AddRef() To iCnt
      Prnt "  iCnt = " & Str$(iCnt)
      Prnt "  Cell 3,2 Contains " & strData
      Prnt "Leaving fnWndProc_OnCommand()"
    Case %IDC_COLOR
      If Hiwrd(Wea.wParam)=%BN_CLICKED Then
         Prnt "Entering fnWndProc_OnCommand()"
         Prnt "  Case %IDC_COLOR
         Prnt "  dwPtr = " & Str$(dwPtr)
         Call pGrid.AddRef() To iCnt
         Prnt "  iCnt = " & Str$(iCnt)
         For i=1 To 5
         Next i
         For i=1 To 5
         Next i
         For i=1 To 5
         Next i
         For i=1 To 5
         Next i
         Prnt "Leaving fnWndProc_OnCommand()"
      End If
      If GetWindowLong(Wea.hWnd,8) Then
         MsgBox("Selected Row = " & Str$(GetWindowLong(Wea.hWnd,8)))
         MsgBox("No Row Selected!")
      End If
      Prnt "Entering fnWndProc_OnCommand()"
      Prnt "  Case %IDC_UNLOAD_GRID"
      Call DestroyGrid(Wea)
      Call EnableWindow(GetDlgItem(Wea.hWnd,%IDC_RETRIEVE),%False)
      Call EnableWindow(GetDlgItem(Wea.hWnd,%IDC_UNLOAD_GRID),%False)
      Call EnableWindow(GetDlgItem(Wea.hWnd,%IDC_COLOR),%False)
      Call EnableWindow(GetDlgItem(Wea.hWnd,%IDC_GET_SELECTED_ROW),%False)
      Call InvalidateRect(Wea.hWnd,Byval %Null, %True)
      Prnt "Leaving fnWndProc_OnCommand()"
  End Select

End Function

Function fnWndProc_OnDestroy(Wea As WndEventArgs) As Long
  Prnt "Entering fnWndProc_OnDestroy()"
  Call DestroyGrid(Wea)
  Call CoFreeUnusedLibraries()
  Call PostQuitMessage(0)
  Prnt "Leaving fnWndProc_OnDestroy()"
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 2
    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
       Exit Function
    End If
  Next i

End Function

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

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

  Call AttachMessageHandlers()                    : szAppName="PBClient6"
  wc.lpszClassName=VarPtr(szAppName)              : wc.lpfnWndProc=CodePtr(fnWndProc)
  wc.cbClsExtra=0                                 : wc.cbWndExtra=12 Or %CS_VREDRAW             : wc.hInstance=hIns
  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,790,280,0,0,hIns,ByVal 0)
  Call ShowWindow(hWnd,iShow)
  While GetMessage(Msg,%NULL,0,0)
    TranslateMessage Msg
    DispatchMessage Msg
  Wend : MsgBox("Last Chance To Get What You Can!")

End Function