CPP 到 Delphi 的转换

CPP to Delphi Convertion

**

SOLVED

**

感谢 Rob 解决了我的问题。

在组件单元 fDict 上创建一个全局变量 实现3个方法,一个添加,一个删除,一个检索; 使 main class 创建、清除和销毁全局变量以避免内存泄漏 制作 TDispositivo 的连接函数来提供 fDict 进行回调以检索并继续前进。 使 TDispositivo 的断开连接功能删除 fDict 中的引用保持更新

**

EDIT

**

我发现我的崩溃错误,我在组件 class 中实现 dll 并尝试使用

在 class 中声明回调过程

TSnapRev = 对象标准调用的过程 (XXXXX);

... 私人的 程序回调快照(XXXXX);标准调用; ...

CLIENT_SetSnapRevCallBack(callbackSnapshot,FSDKUSer);

回调快照已触发,但之后引发访问冲突。

O 意识到返回变量的顺序总是错位,然后我改变了我的方法,将 callbacksnapshot 过程移出 class 并像这样更改类型声明:

类型 TSnapRev = 过程(XXXXX);标准调用;

TDispositivo = class 私人的 结束;

过程回调快照(XXXXX);标准调用;

... CLIENT_SetSnapRevCallBack(@callbackSnapshot,FSDKUSer); ...

现在回调触发,变量的顺序是正确的,之后没有访问冲突,但是,我需要从我的 TDispositivo 实例或 TDispositivo 实例的所有者调用一些函数(事件等),在外部我做不到。

我怎样才能在我的 class 中执行此操作?

我曾尝试声明一个变量 FSDKSnap : TRevSap(当 TRevSap 是一种对象时)但得到了相同的错误或错位的变量和访问冲突

**

ORIGINAL

**

继续将我的大华 dll 转换为 Delphi。现在我陷入了回调,实际上是在所用类型的定义中。

header中有cpp代码

    #define BYTE        unsigned char
    #define UINT        unsigned int

    // Snapshot parameter structure 
    typedef struct _snap_param
    {
        unsigned int        Channel;                // Snapshot channel
        unsigned int        Quality;                // Image quality:level 1 to level 6
        unsigned int        ImageSize;              // Video size;0:QCIF,1:CIF,2:D1
        unsigned int        mode;                   // Snapshot mode;0:request one frame,1:send out requestion regularly,2: Request consecutively
        unsigned int        InterSnap;              // Time unit is second.If mode=1, it means send out requestion regularly. The time is valid.
        unsigned int        CmdSerial;              // Request serial number
        unsigned int        Reserved[4];
    } SNAP_PARAMS, *LPSNAP_PARAMS;

    // Snapshot callback function original shape 
    // Encode Type 10: jpeg 0: number i frame of mpeg4 
    typedef void (CALLBACK *fSnapRev)(LLONG lLoginID, BYTE *pBuf, UINT RevLen, UINT EncodeType, DWORD CmdSerial, LDWORD dwUser);

    // Set snapshot callback function 
    CLIENT_NET_API void CALL_METHOD CLIENT_SetSnapRevCallBack(fSnapRev OnSnapRevMessage, LDWORD dwUser);    

    // Snapshot request
    CLIENT_NET_API BOOL CALL_METHOD CLIENT_SnapPicture(LLONG lLoginID, SNAP_PARAMS par);

查看cpp代码,它将BYTE定义为unsigned char,所以映射到Delphi(字节),UINT映射到Cardinal。

结构也映射到 Cardinal。

---> 第一个问题在这里

回调 fSnapRev 有 (BYTE *pBuf),所以我想是一个指向字节 (Delphi PByte) 的指针,我怀疑这就是问题所在。内存这么小的缓冲区是不对的,可能是字节数组或 pansichar 数组。我怎么知道?喜欢尝试和错过?我接受建议。

RevLen 和编码类型已映射到 Cardinal。

有来自演示应用程序的 cpp 代码。

  //First part of the method to initialize the dll, 

    BOOL ret = CLIENT_Init(DisConnectFunc, (LDWORD)this);
    if (ret)
    {
        CLIENT_SetSnapRevCallBack(SnapPicRet,(LDWORD)this);
        //here defining the callback
        CLIENT_SetAutoReconnect(ReConnectFunc, (LDWORD)this);
    }
    else
    {
        MessageBox(ConvertString("initialize SDK failed!"), ConvertString("prompt"));
    }

    //the callback
    void CALLBACK SnapPicRet(LLONG ILoginID, BYTE *pBuf, UINT RevLen, UINT EncodeType, DWORD CmdSerial, 
    LDWORD dwUser)
    {
        CCapturePictureDlg *pThis = (CCapturePictureDlg*)dwUser;
        pThis->OnOnePicture(ILoginID,pBuf,RevLen,EncodeType,CmdSerial);
    }

    
    void CCapturePictureDlg::OnOnePicture(LLONG ILoginID, BYTE *pBuf, UINT RevLen, UINT EncodeType, UINT 
CmdSerial)
    {
        //Get file path
        char path[1000];
        int filelen = GetModuleFileName(NULL,path,1000);
        int i = filelen;
        while(path[i]!='\')
        {
            i--;
        }
        path[i + 1] = '[=12=]';
    
        //Get file name
        CString filepath(path);
        CString filename = "mpeg4.JPG";
        CString strfile = filepath + filename;
        char *pFileName = strfile.GetBuffer(200);
  
        /* Save image original file */
        FILE *stream;        
        if( (stream = fopen((const char*) pFileName, "wb")) != NULL )
        {
            int numwritten = fwrite( pBuf, sizeof( char ), RevLen, stream );
            fclose( stream );
        }
        
        /*Veirfy image encode type. If it is an I frame of mpeg4,then call I frame to decode to BMP to display.*/
        if ( EncodeType == 0) 
        {
            //int iRet = IFrameToBmp("tmp.bmp",pFileName);
            //if (iRet == 1)
            //{
            //  ShowBitmap("tmp.bmp");
            //}
        }
        else if (EncodeType == 10)
        {
            //ShowBitmap(pFileName);
            ShowSnapImage(pFileName);
        }
    }

在OnOnePicture中,第一段代码是定义要存储的图像文件的路径,然后将缓冲区写入文件流。如果缓冲区和大小来自 pBuf 和 RevLen,那么我可以将其写入 TMemoryStream 并分配给 TJpegImage 但仍然不知道 pBuf 到底是什么。

另一个 ocuard 的东西是数据,revLen returns 值 10 并且太小而不能成为图像的一个字节长度。

我的Delphi代码

  TSnapRev = procedure(lLoginID: Integer; pBuf: PByte; RevLen: Cardinal; EncodeType: Cardinal; CmdSerial: DWORD; dwUser: DWORD) of object stdcall;

// Snapshot parameter structure
  PSnapParams = ^TSnapParams;
  TSnapParams = record
    Channel: Cardinal;               // Snapshot channel
    Quality: Cardinal;               // Image quality:level 1 to level 6
    ImageSize: Cardinal;             // Video size;0:QCIF,1:CIF,2:D1
    mode: Cardinal;                  // Snapshot mode;0:request one frame,1:send out requestion regularly,2: Request consecutively
    InterSnap: Cardinal;             // Time unit is second.If mode=1, it means send out requestion regularly. The time is valid.
    CmdSerial: Cardinal;             // Request serial number
    Reserved: array[0..3] of Cardinal;
  end;

// Snapshot request
  function CLIENT_SnapPicture(lLoginID: Integer; par: TSnapParams): Boolean;  stdcall; external 'dhnetsdk.dll';

  procedure callbackSnapshot(lLoginID: Integer; pBuf: PByte; RevLen: Cardinal; EncodeType: Cardinal; CmdSerial: DWORD; dwUser: DWORD); stdcall;

 //Part of my initDll function
   FInicializado := CLIENT_Init(callbackDis,FSDKUser);
  if FInicializado then
    begin
      CLIENT_SetSnapRevCallBack(callbackSnapshot,FSDKUSer);
    end;
   Result := FInicializado;

  //Snapshot wrapper procedure
  procedure TDispositivo.SDKSnapshot;
  var
    sIn: TSnapParams;
  begin
    ZeroMemory(@sIn, SizeOf(sIn));
    With sIn do
      begin
        Channel := 1;
        mode := 0;
        CmdSerial := 0;
        if not CLIENT_SnapPicture(FLoginHandler,sIn) then
          begin
            doErro(999,'Não foi possível tirar o snapshot');
          end;
      end;
  end; 

//the callback implementation
procedure TDispositivo.callbackSnapshot(lLoginID: Integer; pBuf: PByte; RevLen: Cardinal; EncodeType: Cardinal; CmdSerial: DWORD; dwUser: DWORD);
var
  F: TMemoryStream;
  jpg : TJpegImage;
begin
  Showmessage('Tamanho do buffer: ' + SizeOf(pBuf).ToString + #13 +
              'RevLen: ' + RevLen.ToString + #13 +
              'Tipo: ' + EncodeType.ToString + #13 +
              'CmdSerial: ' + CmdSerial.ToString
              );
  F := TMemoryStream.Create;
  jpg := TJPEGImage.Create;
  Try
    F.Write(pBuf,RevLen);
    //F.Write(pBuf^,RevLen);
    F.Position:= 0;
    jpg.LoadFromStream(F);
    fOwner.doSnapshot(self,jpg);
  Finally
    FreeAndNil(F);
    FreeAndNil(jpg);
  End;
end;  

当我调用 SDKSnapshot 时,我得到了带有值的回调函数中的“showmessage”,但是在调试模式下我遇到了无限访问冲突,在 Release 模式下应用程序在 showmessage 之后关闭。

我尝试在回调时不执行任何操作,但仍然遇到访问冲突和终止。

我想知道我的问题是否出在回调过程 pBuf 的声明上。

我怀疑您的 LLoginId 应该是 Int64 .. LLONG 将在您的源平台的编译器方言/系统包含中定义。 (参见:long long in C/C++

您的错误表明参数持有垃圾(见下文),如果它们顺序不正确就会发生这种情况 - 这可能意味着您的参数大小错误(因此 LLoginId 没有从堆栈中读取所有值, 它后面的所有变量都将被破坏)。

您可以尝试制作 LLogin Int64,或者如果您想进一步调查,可以尝试以下操作:

您似乎成功调用了回调例程,但是您在例程中收到的变量不正确。 (你说你的 revLen 只有 10,并且访问冲突错误表明 pBuf 可能指向垃圾)。

您已将例程声明为 stdcall,这应该是正确的,并且参数将按照正常的“C”约定在堆栈上传递。

如果您中断例程的入口并查看 CPU 视图,您应该会看到变量是从堆栈中读取的,并确定每个变量都已正确设置。您应该能够将 pBuf 的地址放入内存 window 并确定它是否指向来自 JPEG 签名的 JPEG 数据。

您还可以查看堆栈的内存转储以检查传递给您的内容,看看您是否可以确定您真正需要的变量在哪里。

我要post一个不同的答案,因为现在这是一个不同的问题。

你的回调是一个标准过程,不接受对象引用(并且不能作为对象方法调用,当我检查你之前的 post 时它不是,因为这将是其中之一变量不匹配的主要原因)。

您需要能够从您拥有的一些信息中查找对象,这些信息在回调中是唯一的。在不知道有关 API 的更多详细信息的情况下,在您的情况下,它看起来像是 LLoginId 或 dwUser。

我可能会实现一个带有查找的 TDictionary,以将唯一代码与您正在使用的对象相匹配。记得在不使用时从 TDictionary 中删除对象!

假设您可以使用 dwUser,您的代码可能类似于:

implementation

  uses Systm.Generics.Collections;

  var
    gClassDict:      TDictionary<DWORD, TDispositivo>;

  procedure RegisterInDictionary(dwUser: DWORD, class: TDispitivo);
  begin
    if(gClassDict=nil) then
      gClassDict:=TDictionary<DWORD, TDispositivo>.Create;
    gClassDict.AddOrSetValue(DWORD, class);
  end;

  function GetClassFromDictionary(dwUser: DWORD): TDispotivo;
  begin
    if( (gClassDict=nil) Or
        (not(gClassDict.TryGetValue(dwUser, Result))) ) then
      Result:=nil;
  end;

然后在你的回调中调用GetClassFromDictionary获取你的对象。