1

我无法使用纯 API 从剪贴板保存图像。

这是我的代码。它会创建 20 个空的 bmp 文件。我已经检查了 dwSize 并且它是正确的,所以看起来我正在正确地检索数据,但我正在错误地写入文件。

  program WebcamTest;
  //cswi

  uses
    Windows;

  const
    WM_CAP_DRIVER_CONNECT = 1034;
    WM_CAP_GRAB_FRAME = 1084;
    //WM_CAP_SAVEDIB = 1049;
    WM_CAP_EDIT_COPY = 1054;
    WM_CAP_DRIVER_DISCONNECT = 1035;

  function SendMessageA(hWnd: Integer;
                        Msg: Integer;
                        wParam: Integer;
                        lParam: Integer): Integer;
                        stdcall;
                        external 'user32.dll' name 'SendMessageA';

  function capGetDriverDescriptionA(DrvIndex: Cardinal;
                                    Name: PAnsiChar;
                                    NameLen: Integer;
                                    Description: PAnsiChar;
                                    DescLen: Integer) : Boolean;
                                    stdcall;
                                    external 'avicap32.dll' name 'capGetDriverDescriptionA';

  function capCreateCaptureWindowA(lpszWindowName: PAnsiChar;
                                   dwStyle: Integer;
                                   x : Integer;
                                   y : Integer;
                                   nWidth : Integer;
                                   nHeight : Integer;
                                   ParentWin: Integer;
                                   nId: Integer): Integer;
                                   stdcall;
                                   external 'avicap32.dll' name 'capCreateCaptureWindowA';

  function IntToStr(i: Integer): String;
  begin
    Str(i, Result);
  end;

  var
    WebCamId : Integer;
    CaptureWindow : Integer;
    x : Integer;
    FileName : PAnsiChar;
    hData:  DWORD;
    pData:  Pointer;
    dwSize: DWORD;
    szText : AnsiString;
    FileHandle, BytesWritten : LongWord;
  begin
    WebcamId := 0;
    CaptureWindow := capCreateCaptureWindowA('CaptureWindow', 0, 0, 0, 0, 0, 0, 0);
    if CaptureWindow <> 0 then
    begin
      if SendMessageA(CaptureWindow, WM_CAP_DRIVER_CONNECT, WebCamId, 0) <> 1 then
      begin
        SendMessageA(CaptureWindow, WM_CAP_DRIVER_DISCONNECT, 0, 0);
      end
      else
      begin
        for x := 1 to 20 do // Take 20 photos.
        begin
          SendMessageA(CaptureWindow, WM_CAP_GRAB_FRAME, 0, 0);
          FileName := PAnsiChar('C:\Test' + IntToStr(x) + '.bmp');
          //SendMessageA(CaptureWindow, WM_CAP_SAVEDIB, 0, LongInt(FileName));
          SendMessageA(CaptureWindow, WM_CAP_EDIT_COPY, 0, LongInt(FileName));
          if OpenClipBoard(0) then
          begin
            hData := GetClipBoardData(CF_DIB);
            if hData <> 0 then
            begin
              pData := GlobalLock(hData);
              if pData <> nil then
              begin
                dwSize := GlobalSize(hData);
                if dwSize <> 0 then
                begin
                  FileHandle := CreateFileA(FileName, GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_NEW, FILE_ATTRIBUTE_HIDDEN, 0);
                  WriteFile(FileHandle, pData, dwSize, BytesWritten, nil);
                  CloseHandle(FileHandle);
                end;
                GlobalUnlock(DWORD(pData));
              end;
            end;
            CloseClipBoard;
          end;
        end;
      end;
      SendMessageA(CaptureWindow, WM_CAP_DRIVER_DISCONNECT, 0, 0);
    end;
  end.
4

2 回答 2

4

(ab)使用剪贴板从捕获窗口传输图像数据只是因为您想获取内存中的数据是一个非常(非常!)坏主意,因为无论如何您都在写入文件我非常热情建议您坚持使用该WM_CAP_SAVEDIB选项。(只是给你两个很好的理由:在剪贴板中,其他进程可以访问它:安全!;它丢弃剪贴板中的任何内容:不方便!)

但是要回答您的问题:WriteFile 将 Buffer 作为无类型参数,因此,如果您将指针传递给它,它将采用指针的,而不是指向的数据,除非您指定它应该这样做,就像这样(插入符号后缀):

WriteFile(FileHandle, pData^, dwSize, BytesWritten, nil);
于 2012-08-28T08:42:08.657 回答
1

由于将剪贴板用于不响应用户交互的事情非常糟糕(非常非常糟糕),我将提供另一种方法来获取抓取的帧数据。如果您将capCreateCaptureWindow句柄传递给窗体的控件,则在发送WM_CAP_GRAB_FRAME消息后,您可以使用窗体和位图上的BitBlt将此数据复制到位图。Canvas.Handle此方法的一个重要缺点是表单需要在屏幕上可见。

于 2012-09-04T10:09:28.350 回答