|
Have you ever been in a programming situation where you
wanted to be able to have users do an ALT/PrintScreen or CTRL/PrintScreen
to capture information from their desktop and send it up to a database
to be saved?
This is very common in bug-tracking and other types of
reporting software where a user may be entering a bug report, and they
need to be able to store a picture along with the report that shows the
error "in flagrante delicto" (caught in the act). There is nothing
like a picture to tell the whole story to the BugMeister!
The following little Visual Basic project will show how
easy it can be to write an ActiveX usercontrol that can be hosted in a
web page to accomplish this. We will create an ActiveX usercontrol, provide
for capture from the clipboard to a picturebox on the control, then serialize
the picture into a byte array with a little PropertyBag trick. Next, we'll
fire up XMLHTTP and shoot the picture over the wire to our server, where
we'll conveniently store it in an Access database. Finally, as a "Proof
of Concept", we'll retrieve the stored picture from the database
and send it back over the wire to our HTML Page on the client side, and
display it back into the Picture Box in our usercontrol!
First, fire up Visual Basic 6.0 and create a new project
of type ActiveX Control. That's this guy right here:
Drop one PictureBox called Image1 and one TextBox called Text1 on to your
control's visible working surface. Now open the control so you can see
the code area, and past in the following
code:
Option Explicit
Private m_varURL As Variant
Public Property Let URL(myURL As Variant)
m_varURL = Text1.Text
End Property
Public Function CaptureClipboard(oPictureBox
As Object) As Boolean
On Error GoTo Errhandler
Set oPictureBox.Picture = Clipboard.GetData(0)
Clipboard.Clear
CaptureClipboard = True
Exit Function
Errhandler:
Err.Raise Err.Number, "Capture", Err.Description
End Function
Private Sub Image1_Click()
CaptureClipboard Image1
' Convert StdPicture object to byte array using PropertyBag:
Dim pb As New PropertyBag
pb.WriteProperty "pic", Image1.Picture
MsgBox "Click
OK to erase pic before send."
Set Image1.Picture = Nothing
Dim vmypic As Variant
vmypic = pb.ReadProperty("pic")
Dim XMLHTTP As MSXML2.XMLHTTP30
Set XMLHTTP = New MSXML2.XMLHTTP30
m_varURL = Text1.Text
XMLHTTP.open "POST",
m_varURL, False
XMLHTTP.setRequestHeader "PICNAME", "MyPic"
XMLHTTP.send vmypic
vmypic = ""
MsgBox XMLHTTP.statusText
pb.WriteProperty "pic", XMLHTTP.responseBody
Text1.Text = XMLHTTP.getResponseHeader("PICNAME")
Set Image1.Picture
= pb.ReadProperty("pic")
Set XMLHTTP = Nothing
End Sub
What we are
doing here is this:
1)
We set a property so that it can hold a user - entered value for the URL
to send our captured pictures to.
2) Then we create a function Image1_Click() that will copy any image that
the user is holding in the Windows clipboard into our PictureBox when
the user cliicks on the visible surface of our control in their browser
page.
3) We then need to convert this picture to a byte array in order to send
the binary data over the wire. One of the fastest ways to do this is to
simply save it into a VB PropertyBag object, which automatically makes
this conversion for us.
4) Then we show a messagebox that will erase the picture from the picturebox
control so the user will see it's really gone.
5) We then retrieve our byte array from the PropertyBag object and assign
it to a variant suitable for sending over the wire with XMLHTTP.
6)We fire up an instance of XMLHTTP, set the open method to the URL ,
set a custom requestHeader "PICNAME" so that we can identify
this picture when it's saved in our database, and BOOM --before you can
say "W3C six times fast" , - it's outta here!
Now we need to switch gears and jump over
to the webserver where we sent this thing, to look at the neat ASP page
I've whipped up to handle this puppy:
<!--METADATA
NAME="Microsoft ActiveX Data Objects 2.5 Library" TYPE="TypeLib"
UUID="{00000205-0000-0010-8000-00AA006D2EA4}"-->
<%
'receivepic.asp
'Get the name of the image that was sent from the custom request header
so we can save it with the picture
imageName=Request.ServerVariables("HTTP_PICNAME")
' Now binary read the entire request object which represents the entire
image...
mypic =Request.BinaryRead(Request.totalBytes)
' At this point, the variant
"mypic" holds a byte array consisting of the binary image that
was sent.
' We can now save it to a database, etc.
' In this case we'll save it to an Access table, and just turn around,
pull it back out,
' and send it back as a sort of "proof of concept".
Dim strconn
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" &
server.mappath("PICS.MDB") & ";User Id=admin;Password=;"
dim rs
set rs = Server.CreateObject("ADODB.Recordset")
'Note we set the OpenKeyset and LockOptimistic to give ourselves an updatable
recordset ...
rs.Open "Select * from Pictures",strConn ,adOpenKeyset, adLockOptimistic
' Now all we need to do is add a new record, stick our stuff in there,
and call the update method...
rs.AddNew
rs("PICNAME")=imageName
rs("PICDATA")=mypic
rs.Update
rs.close
set rs=nothing
' Now start all over as if
this were a new page, and send the pic and its name right back from out
of the database...
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" &
server.mappath("PICS.MDB") & ";User Id=admin;Password=;"
set rs = Server.CreateObject("ADODB.Recordset")
rs.Open "Select * from Pictures",strConn ,adOpenKeyset, adLockOptimistic
rs.MoveLast
' Let's put the picture name into a custom response header so it can be
read and used by the receiver...
Response.addHeader "PICNAME", rs("PICNAME")
' This is binary image data, so we need to write it out binary
Response.binarywrite rs("PICDATA")
' Outta here!
rs.close
set rs=nothing
%>
Ok! You've got that all memorized, right?
Here's what we are doing:
1) We set a metadata reference to the ADO
type library so we don't have to include or remember all those silly ADO
constants.
2) We get the name of the picture by reading the custom header: imageName=Request.ServerVariables("HTTP_PICNAME")
3) we read our entire picture into a variable, in the same form it was
sent - a binary byte array: mypic =Request.BinaryRead(Request.totalBytes)
4) We save it, and the picture name, into our database by using the convenience
of an updateable recordset (We could also create a new recordset on the
fly if we wanted).
5) As a "Proof of concept", we get the record back out, set
a new Response Header with the picture name, and binary write the picture
data to the receiver. See the inline comments in the ASP page code above
for more.
Now, back to VB, where as you remember,
we've asked XMLHTTP to send out this screen-pop picture. XMLHTTP, also
, on every Send(), will patiently wait for as long as we like (provided
we set the async property to False), to get some return data. When it
does, we simply read the ResponseBody, which by definition is a byte array
- exactly what we need - and we also read the picture name from the header.
All that's left to do is show the picture
name in the Text1.Text and the actual picture we got back out of the database
in the Image1.Picture property, and we're done:
The beauty of this is that in an Intranet
environment or a trusted site environment, you can use the Package and
Deployment wizard to create an Internet CAB download and automatically
download, register and display your control in the users' browsers. Now
obviously this is a pretty simplistic example. But I've kept it that way
so that it would be easy to understand. Now it's up to you to build on
this and create unique solutions that more specifically suit your needs.
The download has all the VB code, the ASP page, the Access Database in
Access 97 format, and even an HTML page with the OBJECT Tag and the CAB
file to self install the control on the client.
Donwload
the code that accompanies this article
Peter Bromberg is an independent consultant specializing in distributed .NET solutionsa Senior Programmer
/Analyst at in Orlando and a co-developer of the EggheadCafe.com
developer website. He can be reached at pbromberg@yahoo.com
|