1

I'm designing a database in Microsoft Access 2013 to store records of faulty parts found in the plant.

I'm trying to implement a button on my form the user can click to access their device's camera, to attach a picture of the fault in the form. The user is using Windows 10 on a Dell latitude 5290 two in one.

I tried code I found online but it is extremely old. https://www.developerfusion.com/thread/46191/how-to-capture-picture-using-webcam-in-vb60/

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Databoy
  • 23
  • 1
  • 6
  • Maybe it is better to use ffmpeg for this https://superuser.com/questions/99743/command-line-tool-to-capture-webcam-video-in-windows-xp – viilpe Jun 25 '19 at 16:10
  • Besides 64-bit compatibility, I don't know why that thread wouldn't work. Compatibility between Windows versions is generally pretty good. – Erik A Jun 25 '19 at 16:55
  • I have the 32 bit version of Access installed on my 64 bit windows if that helps. I apologize I'm fairly new to this software and databases in general. – Databoy Jun 25 '19 at 17:03
  • That's fine, just try the code you've found and report back with any issues – Erik A Jun 25 '19 at 17:14
  • @ErikA do you know what that person means by a "Picture Box" in the link I provided? – Databoy Jun 25 '19 at 17:56
  • Since code in link is VB6, it is referencing objects not in Access. Access has Image control. A CommonDialog Class is located in ActiveX list. So this is not really a webcam, just laptop camera. – June7 Jun 25 '19 at 18:16
  • http://stackoverflow.com/questions/32140725/take-a-snapshot-with-a-webcam-from-ms-access-form/32190141#32190141 or could try 3rd party shareware https://access.bukrek.net/ – June7 Jun 25 '19 at 18:35
  • I'm very lost on how to implement all that on an Access 2013 form. Do you happen to have an example I could go off of? Most links I have found so far are using WIA which apparently is not supported for current generation (for webcams). – Databoy Jun 25 '19 at 18:37
  • @Databoy The picture box is not really relevant there, instead of it, you can use a subform, but be sure to replace `PicWebCam.hWnd` with `PicWebCam.Form.hWnd` and point the subform to a blank form. Really, any control that allows you to get its hWnd will do. I've just checked the code, works fine on Win 10 64-bit with minor adjustments (you need to replace the CommonDialog stuff with a file dialog to indicate where you want to save the file) – Erik A Jun 25 '19 at 19:52
  • @ErikA So I put a "camera" button on my main form that points to a blank form and basically call it "PicWebCam" and at the same time put the code in that link in a module? Can I also make the file destination a default location instead of prompting the user? Lastly, would the image open up if I look at old records with the picture taken? Sorry for dumb questions. – Databoy Jun 25 '19 at 20:34
  • Huh? Just add the buttons as described in your link on the main form. The form the subform points to should be blank, since we really don't use it as a subform, just as a placeholder for the webcam feed. The image would be stored on disk and the form is not bound to records at all. Going afk for a while, so will answer follow-up stuff later – Erik A Jun 25 '19 at 20:42
  • @ErikA Why do we need a subform AND a blank form? what exactly do you mean to point the subform to a blank form? – Databoy Jun 26 '19 at 14:11
  • To use the `Subform.Form` property, the subform needs to display something. Really, anything would do, but a blank form is the most obvious choice. As said, we're not using it as a subform at all, just a blank window. But we can only get the hWnd if it displays something. With _point it to a blank form_, I mean set the subform _source object_ property to the blank form name. – Erik A Jun 26 '19 at 14:18
  • @ErikA You said the you were able to get the code to work with minor adjustments. Can I take a look at that? It would be a lot easier to understand what is going on that way. Thank you! – Databoy Jun 26 '19 at 14:19
  • I don't have it on me atm (on a laptop I rarely use since my main workstation has no webcam). I'll write up a full answer in a few hours when I have access to it. I'll share the database file as well, then you can analyze it while working. – Erik A Jun 26 '19 at 14:23
  • @ErikA You are a life saver. I started using Access/VBA less than 2 weeks ago and this is very confusing. Thank you so much! I will wait for your response. – Databoy Jun 26 '19 at 14:26

1 Answers1

7

I see you've had trouble adjusting the code yourself, so let me walk you through the process of adjusting it for VBA.

First, we're going to create a form that holds the webcam code, and add the required controls to it. The controls are:

4 buttons, called cmd1, cmd2, cmd3, and cmd4, and 1 subform control, called PicWebCam. We're using a subform to replace the PictureBox object, since that's not available in Access.

Since the subform needs to display something, we create a second form in design view, and set record selectors and navigation buttons to No. We add no controls to the form, and make it small enough so it doesn't have scroll bars. Then, we set our subform control's source object to the form we just created.

Then, the code also uses a CommonDialog control to let us choose a file path to save the picture. While that's available with some combinations of Windows + Access, we can't rely on that, so we'll use a FileDialog instead.

To get a file path, we add the following code to our form module:

Function GetSavePath() As String
    Dim f As Object 'FileDialog
    Set f = Application.FileDialog(2) 'msoFileDialogSaveAs
    If f.Show <> 0 Then GetSavePath = f.SelectedItems(1)
End Function

Then, we copy-paste the initial declarations (types and declare function statements), and make 2 adjustments:

  1. Since we're going to place them in the form module, Public needs to be removed for everything that's private by default, and changed to Private for the stuff that isn't.

  2. Since we want to be compatible with 64-bit Access (you said you didn't need to be, but adding it anyway), we want to add the PtrSafe keyword to all external functions, and change the type for all pointers from Long to LongPtr. This code comes before the function we just created.

Const WS_CHILD As Long = &H40000000
Const WS_VISIBLE As Long = &H10000000

Const WM_USER As Long = &H400
Const WM_CAP_START As Long = WM_USER

Const WM_CAP_DRIVER_CONNECT As Long = WM_CAP_START + 10
Const WM_CAP_DRIVER_DISCONNECT As Long = WM_CAP_START + 11
Const WM_CAP_SET_PREVIEW As Long = WM_CAP_START + 50
Const WM_CAP_SET_PREVIEWRATE As Long = WM_CAP_START + 52
Const WM_CAP_DLG_VIDEOFORMAT As Long = WM_CAP_START + 41
Const WM_CAP_FILE_SAVEDIB As Long = WM_CAP_START + 25

Private Declare PtrSafe Function capCreateCaptureWindow _
    Lib "avicap32.dll" Alias "capCreateCaptureWindowA" _
         (ByVal lpszWindowName As String, ByVal dwStyle As Long _
        , ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long _
        , ByVal nHeight As Long, ByVal hwndParent As LongPtr _
        , ByVal nID As Long) As Long

Private Declare PtrSafe Function SendMessage Lib "user32" _
    Alias "SendMessageA" (ByVal hWnd As LongPtr, ByVal wMsg As Long _
        , ByVal wParam As Long, ByRef lParam As Any) As Long

Dim hCap As LongPtr

Now, we can copy paste the actual functions, and make 2 changes:

  1. Instead of the common dialog control code, we use the GetSavePath function to get the path the user wants to save the file at.
  2. Instead of PicWebCam.hWnd, we use PicWebCam.Form.hWnd to get the hWnd for the frame we want to fill with the webcam feed.
Private Sub cmd4_Click()
Dim sFileName As String
    Call SendMessage(hCap, WM_CAP_SET_PREVIEW, CLng(False), 0&)
    sFileName = GetSavePath
    Call SendMessage(hCap, WM_CAP_FILE_SAVEDIB, 0&, ByVal CStr(sFileName))
DoFinally:
    Call SendMessage(hCap, WM_CAP_SET_PREVIEW, CLng(True), 0&)
End Sub

Private Sub Cmd3_Click()
Dim temp As Long
temp = SendMessage(hCap, WM_CAP_DRIVER_DISCONNECT, 0&, 0&)
End Sub


Private Sub Cmd1_Click()
    hCap = capCreateCaptureWindow("Take a Camera Shot", WS_CHILD Or WS_VISIBLE, 0, 0, PicWebCam.Width, PicWebCam.Height, PicWebCam.Form.hWnd, 0)
    If hCap <> 0 Then
        Call SendMessage(hCap, WM_CAP_DRIVER_CONNECT, 0, 0)
        Call SendMessage(hCap, WM_CAP_SET_PREVIEWRATE, 66, 0&)
        Call SendMessage(hCap, WM_CAP_SET_PREVIEW, CLng(True), 0&)
    End If
End Sub

Private Sub Cmd2_Click()
Dim temp As Long
temp = SendMessage(hCap, WM_CAP_DLG_VIDEOFORMAT, 0&, 0&)
End Sub


Private Sub Form_Load()
cmd1.Caption = "Start &Cam"
cmd2.Caption = "&Format Cam"
cmd3.Caption = "&Close Cam"
cmd4.Caption = "&Save Image"
End Sub

Finally, since we added event handlers for the Form_Load event, we need to make sure the On Load property of the form is set to [Event Procedure]. The same goes for the On Click property of all command buttons we've added.

And, that's it, we've succesfully migrated the webcam code from VB6 to VBA, and recreated the form that was sparsely described in the link you provided. Credits to most of the code go to the author on that link.

You can temporarily download the result here. Note that I recommend you don't, both for educational purposes, and because you shouldn't trust random strangers on the internet giving you unsigned executables. But it's useful if you encounter an error, so you can check if it might be a webcam compatibility issue, or a mistake.

Note that I haven't made any real functional changes to the original code.

Erik A
  • 31,639
  • 12
  • 42
  • 67
  • I cannot describe how much I appreciate your help. I assure you that I will make whole thing from the beginning and not just use your provided database. Thank you so much! – Databoy Jun 26 '19 at 19:47
  • Everything is working perfectly fine but I was wondering if there is a way to set a default resolution instead of opening a dialog box that prompts the user to select it. Thank you! – Databoy Jun 28 '19 at 14:37
  • Yup, using the [WM_CAP_SET_VIDEOFORMAT message](https://learn.microsoft.com/en-us/windows/desktop/Multimedia/wm-cap-set-videoformat). This sample already includes some `SendMessage` calls, you only need to read into how to construct your `psVideoFormat` struct and send that. – Erik A Jun 28 '19 at 14:40
  • I am struggling to understand how to set this format? How would i automatically set it to Resolution 640 x 480, Pixel Depth YUY2, Size 614400? – Shadyjunior Sep 18 '21 at 10:08
  • For my particular setup 64-bit Windows10 Build19044 I am finding that it struggles to launch the camera. After some testing it seems that if I turn my USB camera on and off in a different app (I've been using Discord) and then immediately trigger the Start Cam macro everything works as expected. If I don't do that, the only thing that happens is the camera window subform turns black. – Daniel Piechowski Dec 04 '21 at 20:18