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
获取你的对象。
**
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
获取你的对象。