home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Programmer'…arterly (Limited Edition) / Visual_Basic_Programmers_Journal_VB-CD_Quarterly_Limited_Edition_1995.iso / code / ch27code / exchange.bas next >
Encoding:
BASIC Source File  |  1995-08-01  |  22.7 KB  |  473 lines

  1. Attribute VB_Name = "basExchange"
  2. '*********************************************************************
  3. ' EXCHANGE.BAS: Used to manually exchange data with other windows.
  4. '*********************************************************************
  5. Option Explicit
  6. Option Compare Text
  7. '*********************************************************************
  8. ' The API functions we are using in this module require us to define
  9. ' two new types.
  10. '*********************************************************************
  11. #If Win32 Then
  12. Private Type PointAPI
  13.     x As Long
  14.     y As Long
  15. End Type
  16.  
  17. Private Type RECT
  18.     Left As Long
  19.     Top As Long
  20.     Right As Long
  21.     Bottom As Long
  22. End Type
  23.  
  24. #Else
  25.  
  26. Private Type PointAPI
  27.     x As Integer
  28.     y As Integer
  29. End Type
  30.  
  31. Private Type RECT
  32.     Left As Integer
  33.     Top As Integer
  34.     Right As Integer
  35.     Bottom As Integer
  36. End Type
  37. #End If
  38. '*********************************************************************
  39. ' Mouse Capture
  40. '*********************************************************************
  41. #If Win32 Then
  42. Private Declare Function SetCapture& Lib "user32" (ByVal hWnd As Long)
  43. Public Declare Function GetCapture Lib "user32" () As Long
  44. Private Declare Sub ReleaseCapture Lib "user32" ()
  45. #Else
  46. Private Declare Function SetCapture Lib "User" (ByVal hWnd%) As Integer
  47. Public Declare Function GetCapture Lib "User" () As Integer
  48. Private Declare Sub ReleaseCapture Lib "User" ()
  49. #End If
  50. '*********************************************************************
  51. ' Window Information
  52. '*********************************************************************
  53. #If Win32 Then
  54. Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
  55.     (ByVal hWnd&, ByVal lpClassName$, ByVal nMaxCount As Long) As Long
  56. #Else
  57. Private Declare Function GetClassName Lib "User" (ByVal hWnd%, ByVal _
  58.     lpClassName$, ByVal nMaxCount%) As Integer
  59. #End If
  60. '*********************************************************************
  61. ' Window Coordinates, Points and Handles
  62. '*********************************************************************
  63. #If Win32 Then
  64. Private Declare Sub ClientToScreen Lib "user32" (ByVal hWnd As Long, _
  65.     lpPoint As PointAPI)
  66. Private Declare Sub GetWindowRect Lib "user32" (ByVal hWnd As Long, _
  67.     lpRect As RECT)
  68. Private Declare Function WindowFromPoint Lib "user32" (ByVal _
  69.     ptScreenX As Long, ByVal ptScreenY As Long) As Long
  70. #Else
  71. Private Declare Sub ClientToScreen Lib "User" (ByVal hWnd%, lpPoint _
  72.     As PointAPI)
  73. Private Declare Sub GetWindowRect Lib "User" (ByVal hWnd%, lpRect As RECT)
  74. Private Declare Function WindowFromPoint% Lib "User" (ByVal ptScreen&)
  75. #End If
  76.  
  77. '*********************************************************************
  78. ' Window Device Contexts
  79. '*********************************************************************
  80. #If Win32 Then
  81. Private Declare Function GetWindowDC& Lib "user32" (ByVal hWnd As Long)
  82. Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, _
  83.     ByVal hdc As Long) As Long
  84. #Else
  85. Private Declare Function GetWindowDC Lib "User" (ByVal hWnd%) As Integer
  86. Private Declare Function ReleaseDC% Lib "User" (ByVal hWnd%, ByVal hdc%)
  87. #End If
  88. '*********************************************************************
  89. ' Brushes and Painting
  90. '*********************************************************************
  91. #If Win32 Then
  92. Private Declare Function GetStockObject& Lib "gdi32" (ByVal nIndex&)
  93. Private Declare Function CreatePen Lib "gdi32" (ByVal nPenStyle&, _
  94.     ByVal nWidth&, ByVal crColor&) As Long
  95. Private Declare Function SetROP2 Lib "gdi32" (ByVal hdc As Long, _
  96.     ByVal nDrawMode As Long) As Long
  97. Private Declare Function Rectangle Lib "gdi32" (ByVal hdc&, ByVal X1&, _
  98.     ByVal Y1&, ByVal X2&, ByVal Y2&) As Long
  99. Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, _
  100.     ByVal hObject As Long) As Long
  101. Private Declare Function DeleteObject& Lib "gdi32" (ByVal hObject&)
  102. #Else
  103. Private Declare Function GetStockObject% Lib "GDI" (ByVal nIndex%)
  104. Private Declare Function CreatePen Lib "GDI" (ByVal nPenStyle%, _
  105.     ByVal nWidth%, ByVal crColor&) As Integer
  106. Private Declare Function SetROP2 Lib "GDI" (ByVal hdc As Integer, _
  107.     ByVal nDrawMode As Integer) As Integer
  108. Private Declare Function Rectangle Lib "GDI" (ByVal hdc%, ByVal X1%, _
  109.     ByVal Y1%, ByVal X2%, ByVal Y2%) As Integer
  110. Private Declare Function SelectObject Lib "GDI" (ByVal hdc%, _
  111.     ByVal hObject%) As Integer
  112. Private Declare Function DeleteObject% Lib "GDI" (ByVal hObject%)
  113. #End If
  114. '*********************************************************************
  115. ' Misc. API Functions
  116. '*********************************************************************
  117. #If Win32 Then
  118. Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
  119.     (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
  120.     lParam As Any) As Long
  121. Private Declare Function SetFocusAPI Lib "user32" Alias "SetFocus" _
  122.     (ByVal hWnd As Long) As Long
  123. Private Declare Sub InvalidateRect Lib "user32" (ByVal hWnd&, _
  124.     lpRect As Any, ByVal bErase As Long)
  125. Private Declare Function GetSystemMetrics& Lib "user32" (ByVal nIndex&)
  126. #Else
  127. Private Declare Function GetSystemMetrics% Lib "User" (ByVal nIndex%)
  128. Private Declare Function SendMessage Lib "User" (ByVal hWnd%, ByVal _
  129.     wMsg As Integer, ByVal wParam%, lParam As Any) As Long
  130. Private Declare Function SetFocusAPI Lib "User" Alias "SetFocus" _
  131.     (ByVal hWnd%) As Integer
  132. Private Declare Sub InvalidateRect Lib "User" (ByVal hWnd%, lpRect _
  133.     As Any, ByVal bErase%)
  134. #End If
  135. '*********************************************************************
  136. ' Private API Constants
  137. '*********************************************************************
  138. Private Const WM_USER = &H400
  139. Private Const WM_SETTEXT = &HC
  140. '*********************************************************************
  141. ' This function communicates with the main form to send or receive
  142. ' text to or from a window.
  143. '*********************************************************************
  144. Public Function CaptureWindows(Mode$, FormName As Form, x!, y!, _
  145.                                             ByVal SendText$) As String
  146. #If Win32 Then
  147.     Dim res&, retStr$, pt As PointAPI, wrd&, FormHwnd&, CurHwnd&
  148.     Static PrevScaleMode%, LasthWnd&
  149. #Else
  150.     Dim res%, retStr$, pt As PointAPI, wrd&, FormHwnd%, CurHwnd%
  151.     Static PrevScaleMode%, LasthWnd%
  152. #End If
  153.  
  154.    FormHwnd = FormName.hWnd
  155.    
  156.    Select Case Mode
  157.     Case "Start"
  158.        '*************************************************************
  159.        ' Set the scalemode to pixels.
  160.        '**************************************************************
  161.        PrevScaleMode = FormName.ScaleMode
  162.        FormName.ScaleMode = vbPixels
  163.        '**************************************************************
  164.        ' Turn on the PointMode and mouse capture.
  165.        '**************************************************************
  166.         FormName.Visible = False
  167.         If SetCapture(FormHwnd) Then Screen.MousePointer = vbUpArrow
  168.         CaptureWindows = "Start"
  169.  
  170.     Case "Move"
  171.         If GetCapture() Then
  172.             '**********************************************************
  173.             ' Store the current points into a POINTAPI struct.
  174.             '**********************************************************
  175.             pt.x = x
  176.             pt.y = y
  177.             '**********************************************************
  178.             ' Change coordinates in pt into screen coordinates.
  179.             '**********************************************************
  180.             ClientToScreen FormHwnd, pt
  181.         #If Win32 Then
  182.             '**********************************************************
  183.             ' Get the window that is under the mouse pointer.
  184.             '**********************************************************
  185.             CurHwnd = WindowFromPoint(pt.x, pt.y)
  186.         #Else
  187.             '**********************************************************
  188.             ' Convert the points into a WORD, so they may be used later
  189.             '**********************************************************
  190.             wrd = CLng(pt.y) * &H10000 Or pt.x
  191.             '**********************************************************
  192.             ' Get the window that is under the mouse pointer.
  193.             '**********************************************************
  194.             CurHwnd = WindowFromPoint(wrd)
  195.         #End If
  196.             '**********************************************************
  197.             ' Only redraw if there is a new active window.
  198.             '**********************************************************
  199.             If CurHwnd <> LasthWnd Then
  200.                 '******************************************************
  201.                 ' If there is a LasthWnd, then restore it.
  202.                 '******************************************************
  203.                 If LasthWnd Then InvertTracker LasthWnd
  204.                 '******************************************************
  205.                 ' Draw an border around the current window, and
  206.                 ' remember the last hWnd.
  207.                 '******************************************************
  208.                 InvertTracker CurHwnd
  209.                 LasthWnd = CurHwnd
  210.             End If
  211.         End If
  212.         
  213.     Case "End"
  214.         '**************************************************************
  215.         ' Restore the last window's border, and refresh the screen
  216.         ' to remove any ghosts that may have appeared.
  217.         '**************************************************************
  218.         RefreshScreen
  219.         '**************************************************************
  220.         ' Exchange the data, and return a result.
  221.         '**************************************************************
  222.         CaptureWindows = ExchangeData(LasthWnd, SendText)
  223.         '**************************************************************
  224.         ' Clear the public variable to indicate that there is
  225.         ' no LasthWnd because ALL windows are restored.
  226.         '**************************************************************
  227.         LasthWnd = 0
  228.         '**************************************************************
  229.         ' If the form has the capture, then release it.
  230.         '**************************************************************
  231.         If GetCapture() = FormHwnd Then ReleaseCapture
  232.         '**************************************************************
  233.         ' Restore ScaleMode and the MousePointer.
  234.         '**************************************************************
  235.         FormName.ScaleMode = PrevScaleMode
  236.         FormName.Visible = True
  237.         Screen.MousePointer = vbDefault
  238.    End Select
  239.  
  240. End Function
  241. '*********************************************************************
  242. ' This is the magic cookie of this module. It takes a handle and
  243. ' sends or receives text to and from standard windows controls.
  244. '*********************************************************************
  245. Public Function ExchangeData(ByVal TaskHandle&, PasteText$) As String
  246. #If Win32 Then
  247.     Dim i&, res&, buffer$, retStr$, LastIdx&, CtrlType$
  248.     Const LB_GETTEXT = &H189
  249.     Const LB_GETTEXTLEN = &H18A
  250.     Const LB_GETCOUNT = &H18B
  251.     Const CB_GETLBTEXT = &H148
  252.     Const CB_GETLBTEXTLEN = &H149
  253.     Const CB_GETCOUNT = &H146
  254.     Const WM_GETTEXT = &HD
  255. #Else
  256.     Dim i%, res%, buffer$, retStr$, LastIdx%, CtrlType$
  257.     Const LB_GETTEXT = WM_USER + 10
  258.     Const LB_GETTEXTLEN = WM_USER + 11
  259.     Const LB_GETCOUNT = WM_USER + 12
  260.     Const CB_GETLBTEXT = WM_USER + 8
  261.     Const CB_GETLBTEXTLEN = WM_USER + 9
  262.     Const CB_GETCOUNT = WM_USER + 6
  263.     Const WM_GETTEXT = &HD
  264. #End If
  265.     '*****************************************************************
  266.     ' Find out the class type of the control.
  267.     '*****************************************************************
  268.     CtrlType = GetClass(TaskHandle)
  269.     '*****************************************************************
  270.     ' If it is a combo box, then use combo functions to communciate.
  271.     '*****************************************************************
  272.     If InStr(CtrlType, "Combo") Then
  273.         '*************************************************************
  274.         ' Find out how many items are in the combo box.
  275.         '*************************************************************
  276.         LastIdx = SendMessage(TaskHandle, CB_GETCOUNT, 0, 0&) - 1
  277.         '*************************************************************
  278.         ' Iterate through the combo to retrieve every item.
  279.         '*************************************************************
  280.         For i = 0 To LastIdx
  281.             '*********************************************************
  282.             ' Find out how long the current item is, and build a
  283.             ' buffer large enough to hold it.
  284.             '*********************************************************
  285.             buffer = Space(SendMessage(TaskHandle, CB_GETLBTEXTLEN, _
  286.                                                            i, 0&) + 1)
  287.             '*********************************************************
  288.             ' Prevent overflow errors.
  289.             '*********************************************************
  290.             If Len(retStr) + Len(buffer) - 1 > 32000 Then Exit For
  291.             '*********************************************************
  292.             ' Get the item from the combo box.
  293.             '*********************************************************
  294.             res = SendMessage(TaskHandle, CB_GETLBTEXT, i, ByVal buffer)
  295.             '*********************************************************
  296.             ' Trim the null terminator, and append it to retStr.
  297.             '*********************************************************
  298.             retStr = retStr & Left(buffer, res) & vbCrLf
  299.         Next i
  300.         '*************************************************************
  301.         ' Return your results to the calling proceedure, and exit.
  302.         '*************************************************************
  303.         ExchangeData = retStr
  304.         Exit Function
  305.     '*****************************************************************
  306.     ' If it is a list box, then use list functions.
  307.     '*****************************************************************
  308.     ElseIf InStr(CtrlType, "List") Then
  309.         '*************************************************************
  310.         ' Find out how many items are in the list box.
  311.         '*************************************************************
  312.         LastIdx = SendMessage(TaskHandle, LB_GETCOUNT, 0, 0&) - 1
  313.         '*************************************************************
  314.         ' Iterate through the list to retrieve every item.
  315.         '*************************************************************
  316.         For i = 0 To LastIdx
  317.             '*********************************************************
  318.             ' Find out how long the current item is, and build a
  319.             ' buffer large enough to hold it.
  320.             '*********************************************************
  321.             buffer = Space(SendMessage(TaskHandle, LB_GETTEXTLEN, _
  322.                                                            i, 0&) + 1)
  323.             '*********************************************************
  324.             ' Prevent overflow errors.
  325.             '*********************************************************
  326.             If Len(retStr) + Len(buffer) - 1 > 32000 Then Exit For
  327.             '*********************************************************
  328.             ' Get the item from the list box.
  329.             '*********************************************************
  330.             res = SendMessage(TaskHandle, LB_GETTEXT, i, ByVal buffer)
  331.             '*********************************************************
  332.             ' Trim the null terminator, and append it to retStr.
  333.             '*********************************************************
  334.             retStr = retStr & Left(buffer, res) & vbCrLf
  335.         Next i
  336.         '*************************************************************
  337.         ' Return your results to the calling proceedure, and exit.
  338.         '*************************************************************
  339.         ExchangeData = retStr
  340.         Exit Function
  341.     '*****************************************************************
  342.     ' Otherwise, try WM_GETTEXT and WM_SETTEXT.
  343.     '*****************************************************************
  344.     Else
  345.         '*************************************************************
  346.         ' If paste text is empty, then retrieve text text.
  347.         '*************************************************************
  348.         If PasteText = "" Then
  349.             '*********************************************************
  350.             ' Build a huge buffer, and get it.
  351.             '*********************************************************
  352.             retStr = Space(32000)
  353.             res = SendMessage(TaskHandle, WM_GETTEXT, Len(retStr), _
  354.                                                          ByVal retStr)
  355.             '*********************************************************
  356.             ' Keep all text to the left of the null terminator.
  357.             '*********************************************************
  358.             ExchangeData = Left(retStr, res)
  359.             Exit Function
  360.         '*************************************************************
  361.         ' Otherwise, send text to the window.
  362.         '*************************************************************
  363.         Else
  364.             '*********************************************************
  365.             ' If the window is an edit box, then paste text to it.
  366.             ' Otherwise don't. This prevents you from changing the
  367.             ' captions of labels, buttons, etc...
  368.             '*********************************************************
  369.             If InStr(CtrlType, "Edit") Or InStr(CtrlType, "Text") Then
  370.                 '*****************************************************
  371.                 ' Put the text into the window, and activate it.
  372.                 '*****************************************************
  373.                 SendMessage TaskHandle, WM_SETTEXT, 0, ByVal PasteText
  374.                 SetFocusAPI TaskHandle
  375.                 '*****************************************************
  376.                 ' Return the num of chars pasted.
  377.                 '*****************************************************
  378.                 ExchangeData = Format(Len(PasteText))
  379.             Else
  380.                 ExchangeData = Format(0)
  381.             End If
  382.             Exit Function
  383.         End If
  384.     End If
  385.     '*****************************************************************
  386.     ' If you got here, then this function is unsucessful.
  387.     '*****************************************************************
  388.     ' I use an obscure return string that I'll recognize, to keep my
  389.     ' code from getting confused with valid return values.
  390.     '*****************************************************************
  391.     ExchangeData = "Error:" & String(10, "~")
  392.  
  393. End Function
  394. '*********************************************************************
  395. ' Returns the class name of a window.
  396. '*********************************************************************
  397. Private Function GetClass(ByVal TaskHandle&) As String
  398. Dim res&, Classname$
  399.     '*****************************************************************
  400.     ' Get the class name of the window.
  401.     '*****************************************************************
  402.     Classname = Space$(32000)
  403.     res = GetClassName(TaskHandle, Classname, Len(Classname))
  404.     GetClass = Left$(Classname, res)
  405. End Function
  406. '*********************************************************************
  407. ' Draws an inverted hatched line on two sizes of a window.
  408. '*********************************************************************
  409. #If Win32 Then
  410. Private Sub InvertTracker(hwndDest As Long)
  411.     Dim hdcDest&, hPen&, hOldPen&, hOldBrush&
  412.     Dim cxBorder&, cxFrame&, cyFrame&, cxScreen&, cyScreen&
  413. #Else
  414. Private Sub InvertTracker(hwndDest As Integer)
  415.     Dim hdcDest%, hPen%, hOldPen%, hOldBrush%
  416.     Dim cxBorder%, cxFrame%, cyFrame%, cxScreen%, cyScreen%
  417. #End If
  418. Const NULL_BRUSH = 5
  419. Const R2_NOT = 6
  420. Const PS_INSIDEFRAME = 6
  421. Dim rc As RECT
  422.     '*****************************************************************
  423.     ' Get some windows dimensions.
  424.     '*****************************************************************
  425.     cxScreen = GetSystemMetrics(0)
  426.     cyScreen = GetSystemMetrics(1)
  427.     cxBorder = GetSystemMetrics(5)
  428.     cxFrame = GetSystemMetrics(32)
  429.     cyFrame = GetSystemMetrics(33)
  430.     '*****************************************************************
  431.     ' Get the Device Context for the current window.
  432.     '*****************************************************************
  433.     hdcDest = GetWindowDC(hwndDest)
  434.     '*****************************************************************
  435.     ' Get the size of the window.
  436.     '*****************************************************************
  437.     GetWindowRect hwndDest, rc
  438.     '*****************************************************************
  439.     ' Create a new pen and select it (and a stock brush) into the
  440.     ' device context.
  441.     '*****************************************************************
  442.     SetROP2 hdcDest, R2_NOT
  443.     hPen = CreatePen(PS_INSIDEFRAME, 3 * cxBorder, RGB(0, 0, 0))
  444.     '*****************************************************************
  445.     ' Get the size of the window.
  446.     '*****************************************************************
  447.     hOldPen = SelectObject(hdcDest, hPen)
  448.     hOldBrush = SelectObject(hdcDest, GetStockObject(NULL_BRUSH))
  449.     '*****************************************************************
  450.     ' Draw a box around the selected window.
  451.     '*****************************************************************
  452.     Rectangle hdcDest, 0, 0, rc.Right - rc.Left, rc.Bottom - rc.Top
  453.     '*****************************************************************
  454.     ' Restore the old brush and pen.
  455.     '*****************************************************************
  456.     SelectObject hdcDest, hOldBrush
  457.     SelectObject hdcDest, hOldPen
  458.     '*****************************************************************
  459.     ' Release the Device Context back to its owner.
  460.     '*****************************************************************
  461.     ReleaseDC hwndDest, hdcDest
  462.     '*****************************************************************
  463.     ' Delete the hatched brush.
  464.     '*****************************************************************
  465.     DeleteObject hPen
  466. End Sub
  467. '*********************************************************************
  468. ' Force the entire screen to be repainted immediately.
  469. '*********************************************************************
  470. Private Sub RefreshScreen()
  471.     InvalidateRect 0, 0&, True
  472. End Sub
  473.