Webcam Anzeigen - PInvoke Fehler

  • VB.NET

Es gibt 18 Antworten in diesem Thema. Der letzte Beitrag () ist von AsdAsd1337.

    Webcam Anzeigen - PInvoke Fehler

    Hallo,
    und zwar möchte ich die Webcam anzeigen lassen in Vb.

    Code:

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Form1
    3. Const WM_CAP As Short = &H400S
    4. Const WM_CAP_DRIVER_CONNECT As Integer = WM_CAP + 10 : Const WM_CAP_DRIVER_DISCONNECT As Integer = WM_CAP + 11
    5. Const WM_CAP_EDIT_COPY As Integer = WM_CAP + 30 : Const WM_CAP_SET_PREVIEW As Integer = WM_CAP + 50
    6. Const WM_CAP_SET_PREVIEWRATE As Integer = WM_CAP + 52 : Const WM_CAP_SET_SCALE As Integer = WM_CAP + 53
    7. Const WS_CHILD As Integer = &H40000000 : Const WS_VISIBLE As Integer = &H10000000
    8. Const SWP_NOMOVE As Short = &H2S : Const SWP_NOSIZE As Short = 1
    9. Const SWP_NOZORDER As Short = &H4S : Const HWND_BOTTOM As Short = 1
    10. Dim iDevice As Integer = 0 : Dim hHwnd As Integer
    11. <DllImport("User32.dll")> Private Shared Function SendMessage(ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Object) As Integer
    12. End Function
    13. <DllImport("User32.dll")> Private Shared Function SetWindowPos(ByVal hwnd As Integer, ByVal hWndInsertAfter As Integer, ByVal x As Integer, ByVal y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal wFlags As Integer) As Integer
    14. End Function
    15. <DllImport("User32.dll")> Private Shared Function DestroyWindow(ByVal hndw As Integer) As Boolean
    16. End Function
    17. <DllImport("Avicap32.dll")> Private Shared Function capCreateCaptureWindowA(ByVal lpszWindowName As String, ByVal dwStyle As Integer, ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, ByVal nHeight As Short, ByVal hWndParent As Integer, ByVal nID As Integer) As Integer
    18. End Function
    19. <DllImport("Avicap32.dll")> Private Shared Function capGetDriverDescriptionA(ByVal wDriver As Short, ByVal lpszName As String, ByVal cbName As Integer, ByVal lpszVer As String, ByVal cbVer As Integer) As Boolean
    20. End Function
    21. Private Sub LoadDeviceList()
    22. Dim strName As String = Space(100) : Dim strVer As String = Space(100) : Dim bReturn As Boolean
    23. Dim x As Integer = 0
    24. Do
    25. bReturn = capGetDriverDescriptionA(x, strName, 100, strVer, 100)
    26. If bReturn Then lstDevices.Items.Add(strName.Trim)
    27. x += 1
    28. Loop Until bReturn = False
    29. End Sub
    30. Private Sub StartCam()
    31. Dim iHeight As Integer = picCapture.Height : Dim iWidth As Integer = picCapture.Width
    32. hHwnd = capCreateCaptureWindowA(iDevice, WS_VISIBLE Or WS_CHILD, 0, 0, 640, 480, picCapture.Handle.ToInt32, 0)
    33. If SendMessage(hHwnd, WM_CAP_DRIVER_CONNECT, iDevice, 0) Then
    34. SendMessage(hHwnd, WM_CAP_SET_SCALE, True, 0) : SendMessage(hHwnd, WM_CAP_SET_PREVIEWRATE, 66, 0) : SendMessage(hHwnd, WM_CAP_SET_PREVIEW, True, 0)
    35. SetWindowPos(hHwnd, HWND_BOTTOM, 0, 0, picCapture.Width, picCapture.Height, SWP_NOMOVE Or SWP_NOZORDER)
    36. btnSave.Enabled = True : btnStop.Enabled = True : btnStart.Enabled = False
    37. Else
    38. DestroyWindow(hHwnd) : btnSave.Enabled = False
    39. End If
    40. End Sub
    41. Private Sub ClosePreviewWindow()
    42. SendMessage(hHwnd, WM_CAP_DRIVER_DISCONNECT, iDevice, 0) : DestroyWindow(hHwnd)
    43. End Sub


    Fehler :
    Spoiler anzeigen
    Ein Aufruf an die PInvoke-Funktion "WebCam ScreenShot!WebCam_ScreenShot.Form1: SendMessage" hat das Gleichgewicht des Stapels gestört. Wahrscheinlich stimmt die verwaltete PInvoke-Signatur nicht mit der nicht verwalteten Zielsignatur überein. Überprüfen Sie, ob die Aufrufkonvention und die Parameter der PInvoke-Signatur mit der nicht verwalteten Zielsignatur übereinstimmen.


    In Codezeile :

    VB.NET-Quellcode

    1. If SendMessage(hHwnd, WM_CAP_DRIVER_CONNECT, iDevice, 0) Then


    Kann mir jemand helfen?
    Deine p/invoke-Deklarationen sind nicht korrekt. Wenn in den Signaturen nicht die passenden Typen stehen, ruft der Marshaller die unverwaltete Funktion falsch auf und es kommt zu Fehlern im Aufrufstack. Verhindern kannst du das nur mit richtigen Deklarationen. Eine Hilfe dabei ist diese Tabelle und allgemein diese Seite.
    Gruß
    hal2000
    Den Code einfügen

    VB.NET-Quellcode

    1. Dim bounds As Rectangle
    2. Dim screenshot As System.Drawing.Bitmap
    3. Dim graph As Graphics
    4. bounds = Screen.PrimaryScreen.Bounds
    5. screenshot = New System.Drawing.Bitmap(bounds.Width, bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
    6. graph = Graphics.FromImage(screenshot)
    7. graph.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy)
    8. PictureBox1.Image = screenshot

    ( bild machen)

    dann zum speichern

    VB.NET-Quellcode

    1. Dim savefiledialog1 As New SaveFileDialog
    2. Try
    3. savefiledialog1.Title = "Save File"
    4. savefiledialog1.FileName = "*.bmp"
    5. savefiledialog1.Filter = "Bitmap |*.bmp"
    6. If savefiledialog1.ShowDialog() = DialogResult.OK Then
    7. PictureBox1.Image.Save(savefiledialog1.FileName, System.Drawing.Imaging.ImageFormat.Bmp)
    8. End If
    9. Catch ex As Exception
    10. 'Do Nothing
    11. End Try



    ??!?!



    Profit!
    problem solved!
    Instant,
    ich möchte nicht den Bildschirm aufnehmen , sonder mit meiner Webcam.

    hal2000 schrieb:

    Deine p/invoke-Deklarationen sind nicht korrekt. Wenn in den Signaturen nicht die passenden Typen stehen, ruft der Marshaller die unverwaltete Funktion falsch auf und es kommt zu Fehlern im Aufrufstack. Verhindern kannst du das nur mit richtigen Deklarationen. Eine Hilfe dabei ist diese Tabelle und allgemein diese Seite.

    Hey,
    Was meinst du mit in den Signaturen nicht die passenden Typen stehen?
    Kannst du das vielleicht mal konkreter erklären?
    Eine C++-Signatur sieht z.B. so aus:

    Quellcode

    1. extern "C" __declspec(dllexport) long Calculate(int a, int b); //Achtung: long = 32 Bit, int ebenso. 64 Bit wäre "long long".


    Für p/invoke;

    VB.NET-Quellcode

    1. 'falsch:
    2. <DllImport("MyLib.dll")> _
    3. Public Function Calculate(a As Int32, b As Int32) As Long 'Long = 64 Bit
    4. End Function
    5. 'richtig:
    6. <DllImport("MyLib.dll")> _
    7. Public Function Calculate(a As Int32, b As Int32) As Int32 'Int32 = 32 bit
    8. End Function


    Für den Rückgabetyp wird bei der falschen Variante mehr Speicher reserviert als nötig --> Fehler. Die Signatur muss typrichtig sein, wie im zweiten Beispiel angegeben.
    Gruß
    hal2000

    hal2000 schrieb:

    Eine C++-Signatur sieht z.B. so aus:

    Quellcode

    1



    extern "C" __declspec(dllexport) long Calculate(int a, int b); //Achtung: long = 32 Bit, int ebenso. 64 Bit wäre "long long".



    Für p/invoke;

    Visual Basic Quellcode

    1
    2
    3
    4
    5
    6
    7
    8
    9



    'falsch:
    _
    Public Function Calculate(a As Int32, b As Int32) As Long 'Long = 64 Bit
    End Function

    'richtig:
    _
    Public Function Calculate(a As Int32, b As Int32) As Int32 'Int32 = 32 bit
    End Function



    Für den Rückgabetyp wird bei der falschen Variante mehr Speicher reserviert als nötig --> Fehler. Die Signatur muss typrichtig sein, wie im zweiten Beispiel angegeben.
    Hey,
    danke für die super Erklärung.
    Kann ich nachvollziehen.

    Aber ich benutze ja nur Integer ?

    Meinst du damit das ich Short benutzen soll?

    SystemUnknow schrieb:

    Was hal2000 sagen will, du sollst APIs/Konstanten Deklarationen von pinvoke.net nemen.

    Nein, das möchte ich damit nicht sagen. Er soll sich die Dokumentation der DLL ansehen und die Signaturen entsprechend der Tabelle interpretieren.

    Dieser Post sollte eigentlich #11 sein und war wohl nicht im eingespielten Backup enthalten. Siehe: 25.12.10: VB-Paradise.de nun wieder online (Kopie der Rundmail) *Update*

    leider kann ich nichts zur Avicap32.dll finden.

    Dann hast du nicht gründlich genug gesucht: google.de/search?q=capCreateCa…official&client=firefox-a
    Gruß
    hal2000
    ich habe eine Frage zu dem fast gleichen Code und wollte jetzt nicht extra ein neues Topic aufmachen...

    Und zwar klappt alles gut aber wenn ich auf den Button klicke um die Cam zu starten kommt dieses Auswahlfenster von Windows:
    "Wählen sie das Videogerät aus..."

    Nur wie kann ich das umgehen ? Gibt es eine Möglichkeit sich per Code gleich für eine der z.B 2 angeschlossenen Kamera's zu entscheiden bzw. beide abzufangen ?

    Wäre über eine Antort sehr dankbar

    COM 2000 schrieb:



    Nur wie kann ich das umgehen ? Gibt es eine Möglichkeit sich per Code gleich für eine der z.B 2 angeschlossenen Kamera's zu entscheiden bzw. beide abzufangen ?


    Möglichkeiten gibt es, aber es ist schwierig.
    Bin auch nicht durchgestiegen. Nimm mal den ersten Link den ich gepostet habe. Da wird nur zwischen EINER unterschieden.

    Wenn du auswählen möchtest welche du benutzten willst oder net, musste das Hardwareseitig bei dir im Geräte-Manager einstellen.
    8-)
    Zur Info nochmal, ich habe nur eine Kamera am PC aber Manycam installiert.
    Wenn ich meine Normale Kamera auswähle stürzt das Programm mit einer Fehlermeldung ab: "Eine externe Komponente hat eine Ausnahme ausgelöst."
    Wenn ich aber Manycam auswähle, heißt es ich muss erst Manycam starten um überhaupt etwas zu sehen.
    Ich würde einfach gerne direkt auf meine Kamera zugreifen.

    Und wie meinst du das mit "Da wird nur zwischen EINER unterschieden."
    Ich muss immer noch auswählen.
    Hallo,

    ich habe mich mal rangesetzt und ausprobiert ohne Ende.

    Ich bekomme es hin , das in 90% der fällen sofort die WebCam angezeigt wird.

    Startet man die Cam jedoch ein 2. Mal , wird der Auswahldialog wieder angezeigt -.-


    Code:

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Cam
    3. Const Start As Short = &H400S
    4. Const Connect As Integer = Start + 10
    5. Const Disconnect As Integer = Start + 11
    6. Const EditCopy As Integer = Start + 30
    7. Const SetPreview As Integer = Start + 50
    8. Const SetPreviewRate As Integer = Start + 52
    9. Const SetScale As Integer = Start + 53
    10. Const Child As Integer = &H40000000
    11. Const Visibl3 As Integer = &H10000000
    12. Const NoMove As Short = &H2S
    13. Const NoSize As Short = 1
    14. Const NozOrder As Short = &H4S
    15. Const Bott0m As Short = 1
    16. Const VideoRec = Start + 62
    17. Const VideoSave = Start + 23
    18. Dim iDevice As Integer = 0 : Dim HwnDD As IntPtr
    19. Private Geräte As New List(Of String)
    20. <DllImport("User32.Dll", SetLastError:=True, CharSet:=CharSet.Auto)> Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
    21. End Function
    22. <DllImport("User32.Dll")> Private Shared Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal wFlags As UInt32) As Boolean
    23. End Function
    24. <DllImport("User32.Dll")> Private Shared Function DestroyWindow(ByVal hWnd As IntPtr) As Boolean
    25. End Function
    26. Declare Function capCreateCaptureWindowA Lib "Avicap32.dll" (ByVal lpszWindowName As String, ByVal dwStyle As Integer, ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, ByVal nHeight As Short, ByVal hWndParent As Integer, ByVal nID As Integer) As Integer
    27. Declare Function capGetDriverDescriptionA Lib "Avicap32.dll" (ByVal wDriver As Short, ByVal lpszName As String, ByVal cbName As Integer, ByVal lpszVer As String, ByVal cbVer As Integer) As Boolean
    28. Private Sub LadeGeräte()
    29. Geräte.Clear()
    30. Try
    31. Dim Name As String = Space(100) : Dim Ver As String = Space(100)
    32. Dim bReturn As Boolean
    33. Dim x As Integer = 0
    34. Do
    35. bReturn = capGetDriverDescriptionA(CShort(x), Name, 100, Ver, 100)
    36. If bReturn Then : Geräte.Add(Name.Trim) : End If
    37. x += 1
    38. Loop Until bReturn = False
    39. Catch
    40. End Try
    41. End Sub
    42. Private Sub StartCam()
    43. Try
    44. HwnDD = CType(capCreateCaptureWindowA(Geräte(0), Visibl3 Or Child, 0, 0, 1200, 1200, PicBox.Handle.ToInt32, 0), IntPtr)
    45. If CBool(SendMessage(HwnDD, Connect, CType(iDevice, IntPtr), CType(0, IntPtr))) Then
    46. SendMessage(HwnDD, SetScale, CType(True, IntPtr), CType(0, IntPtr))
    47. SendMessage(HwnDD, SetPreviewRate, CType(66, IntPtr), CType(0, IntPtr))
    48. SendMessage(HwnDD, SetPreview, CType(True, IntPtr), CType(0, IntPtr))
    49. SetWindowPos(HwnDD, CType(Bott0m, IntPtr), 0, 0, PicBox.Width, PicBox.Height, NoMove Or NozOrder)
    50. Else
    51. DestroyWindow(HwnDD)
    52. End If
    53. Catch
    54. End Try
    55. End Sub
    56. Private Sub StopCam()
    57. Try : SendMessage(HwnDD, Disconnect, CType(iDevice, IntPtr), CType(0, IntPtr)) : DestroyWindow(HwnDD) : Catch : End Try
    58. End Sub
    59. Private Sub SavePic()
    60. Try
    61. Dim Data As IDataObject
    62. SendMessage(HwnDD, EditCopy, CType(0, IntPtr), CType(0, IntPtr)) : Data = Clipboard.GetDataObject()
    63. If Data.GetDataPresent(GetType(System.Drawing.Bitmap)) Then
    64. Dim Bmp As Bitmap : Bmp = CType(CType(Data.GetData(GetType(System.Drawing.Bitmap)), Image), Bitmap)
    65. PicBox.Image = Bmp : StopCam()
    66. Bmp.Save(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) & "\WebCamBild.jpg", Imaging.ImageFormat.Jpeg)
    67. End If
    68. Catch
    69. End Try
    70. End Sub
    71. Private Sub Cam_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    72. StopCam()
    73. Environment.Exit(1)
    74. End Sub
    75. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    76. LadeGeräte()
    77. End Sub


    Ich suche allerdings immernoch einen Code , wo niemals das Auswahlfenster angezeigt wird...
    Es wäre einfach nur gut , wenn man die Standardcam starten könnte direkt.

    Bei Msn z.b. funktioniert das doch auch immer..