[英]How to use a function in C that takes a function callback as an argument from dll file in Python code?
[英]How to create a file in delphi pass it to a C DLL and use the file in a callback?
在 ExportToFileCallback 中,我想使用我在 SaveMsg 中分配的文件,但我似乎无法从指向 FilePCDMsg 的指针中获取它。
type
FilePCDMsg = File of PCDKMsg;
PFilePCDMsg = ^FilePCDMsg;
procedure TfrmMain.SaveMsg( pMsg: PCDKMsg; fn: String = '' );
var
myFile: FilePCDMsg;
pFile : PFilePCDMsg;
begin
if fn.IsEmpty then
fn := TPath.GetTempFileName;
CodeSite.Send( 'SaveMsg fn', fn );
AssignFile( myFile, fn );
Rewrite( myFile );
pFile := Addr( myFile );
CDKMsgExport( pMsg, ExportToFileCallBack, pFile );
end;
function ExportToFileCallBack( pData: PUInt8; len: UInt32; pUser: Pointer ): Integer; cdecl;
var
pFile : PFilePCDMsg;
myFile: FilePCDMsg;
begin
// this is the C code for what I want to do
// return fwrite(pData, 1, len, (FILE*)pUser) == len;
pFile := PFilePCDMsg( pUser );
myFile := FilePCDMsg( pFile ); // will not compile
end;
这个 DLL 是由第三方提供的,它有回调来做事。 在这里,我试图查询相机的配置,并且回调被调用了 3 次。 我认为它正在将它希望我到 append 的数据传回给我分配给我的文件。
这是我试图在 Delphi 中复制的 C 代码。
#ifdef WIN32
#include <windows.h>
#include "../../include/external/stdint.h"
#include "../../include/external/inttypes.h"
#endif
#ifdef LINUX
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <inttypes.h>
#endif
#include <stdio.h>
#include "../../include/CDK.h"
const char* strAddress = NULL;
uint16_t uPort = 10001;
const char* strOptions = NULL;
const char* strPathOut = ".";
void help()
{
printf("Command line:\n");
printf(" receive address [-port port] [-options options] [-output outputpath]\n");
printf(" Port default value : 10001\n");
printf(" Output path default value : .\n");
}
int parseCommandLine(int argc, char* argv[])
{
int i;
if (argc < 2)
{
return 0;
}
strAddress = argv[1];
for (i=2;i<argc;++i)
{
if (strcmp(argv[i], "-port") == 0)
{
++i;
if (i >= argc)
return 0;
uPort = atoi(argv[i]);
}
else if (strcmp(argv[i], "-options") == 0)
{
++i;
if (i >= argc)
return 0;
strOptions = argv[i];
}
else if (strcmp(argv[i], "-output") == 0)
{
++i;
if (i >= argc)
return 0;
strPathOut = argv[i];
}
}
return 1;
}
void traceCallback(CDK* pSrc, unsigned char level, const char* strTrace, void* pUser )
{
printf("[%u] %s\n", level, strTrace);
}
int32_t exportToFileCallback(const uint8_t* pData, uint32_t len, void* pUser)
{
return fwrite(pData, 1, len, (FILE*)pUser) == len;
}
void parseConfig(CDKMsg *pMsg)
{
CDKMsgElement* pEltConfig = NULL;
CDKMsgElement* pEltDevice = NULL;
CDKMsgElement* pEltCameras = NULL;
const char* str;
uint32_t i = 0;
uint32_t j = 0;
pEltConfig = CDKMsgChild(pMsg);
if(NULL == pEltConfig)
{
return;
}
pEltDevice = CDKMsgElementFirstChild(pEltConfig, "device");
if (NULL != pEltDevice )
{
str = CDKMsgElementAttributeValue(pEltDevice, "name");
if (str)
printf("Name : %s\n", str);
}
pEltCameras = CDKMsgElementFirstChild(pEltConfig, "cameras");
if (NULL != pEltCameras )
{
CDKMsgElement* pEltCamera = CDKMsgElementFirstChild(pEltCameras,NULL);
CDKMsgElement* pEltCameraParam = NULL;
while(pEltCamera)
{
/* camera attributes */
printf("%s : \n", CDKMsgElementName(pEltCamera));
for(i = 0; i < CDKMsgElementAttributeCount(pEltCamera); i++)
{
str = CDKMsgElementAttributeName(pEltCamera,i);
printf("* \t %s : %s\n", str,CDKMsgElementAttributeValue(pEltCamera,str));
}
/* camera parameters */
pEltCameraParam = CDKMsgElementFirstChild(pEltCamera,NULL);
while(pEltCameraParam)
{
printf("* \t %s : \n", CDKMsgElementName(pEltCameraParam));
for(j = 0; j < CDKMsgElementAttributeCount(pEltCameraParam); j++)
{
str = CDKMsgElementAttributeName(pEltCameraParam,j);
printf("** \t\t %s : %s\n", str,CDKMsgElementAttributeValue(pEltCameraParam,str));
}
pEltCameraParam = CDKMsgElementNextChild(pEltCamera,pEltCameraParam,NULL);
}
pEltCamera = CDKMsgElementNextChild(pEltCameras,pEltCamera,NULL);
}
}
}
int main(int argc, char* argv[])
{
CDK* pCDK = NULL;
FILE* pFile = NULL;
char strFileName[256];
CDKMsg * pMsgRequest = NULL;
CDKMsg * pMsgAnswer = NULL;
CDKSetTraceFunction(traceCallback, NULL);
printf("App launched\n");
printf("CDK version : %s\n", CDKGetVersion());
/* command line */
if (!parseCommandLine(argc, argv))
{
help();
return -1;
}
printf("Get config from %s:%u in %s\n", strAddress, uPort, strPathOut);
if (strOptions)
{
printf(" Options : %s\n", strOptions);
}
pCDK = CDKCreate();
if (!CDKBind(pCDK, strAddress, uPort, strOptions))
{
printf("CDKBind failed : %s\n", CDKGetLastError(pCDK));
goto labelEnd;
}
if(!CDKWaitForConnection(pCDK,30000))
{
printf("ERROR : %s\n", CDKGetLastError(pCDK));
goto labelEnd;
}
/* get config */
pMsgRequest = CDKMsgCreate();
CDKMsgSetChild(pMsgRequest, CDKMsgElementCreate("getConfig"));
pMsgAnswer = CDKSendRequest(pCDK, pMsgRequest, 30000);
CDKMsgDestroy(pMsgRequest);
if (NULL == pMsgAnswer )
{
printf("ERROR : %s\n", CDKGetLastError(pCDK));
goto labelEnd;
}
/* export config msg */
sprintf(strFileName, "%s/config.cdkmsg", strPathOut);
pFile = fopen(strFileName, "wb");
if (NULL == pFile)
{
printf("Unable to create output file, does the output path exist?");
goto labelEnd;
}
if (!CDKMsgExport(pMsgAnswer, &exportToFileCallback, pFile))
{
printf("Message export failed : %s", CDKGetLastError(pMsgAnswer));
goto labelEnd;
}
/* Parse config */
parseConfig(pMsgAnswer);
labelEnd:
if (pFile)
{
fclose(pFile);
}
if (pMsgAnswer)
{
CDKMsgDestroy(pMsgAnswer);
}
if (pCDK)
{
CDKDestroy(pCDK);
}
return 0;
}
我想多了。 答案其实很简单
procedure TfrmMain.SaveMsg(pMsg: PCDKMsg);
begin
CDKMsgExport( pMsg, ExportToFileCallBack, nil );
end;
function ExportToFileCallBack( pData: PUInt8; len: UInt32; pUser: Pointer ): Integer; cdecl;
var
FileName: string;
Stream : TStream;
begin
FileName := 'Config.xml';
if TFile.Exists( FileName ) then
Stream := TFileStream.Create( FileName, fmOpenReadWrite )
else
Stream := TFileStream.Create( FileName, fmCreate );
try
Stream.Seek( 0, soFromEnd );
Stream.WriteBuffer( Pointer( pData )^, len );
CodeSite.SendStreamAsText( 'ExportToFileCallBack', Stream );
finally
Stream.Free;
end;
end;
非常感谢你帮助我
在过程 TfrmMain.SaveMsg 中:
我的文件:FilePCDMsg; 是一个本地变量(保存在堆栈上)。
因此,当 TfrmMain.SaveMsg 执行完成时,文件引用 myFile 将不再有效,因此您传递给 CDKMsgExport() 的指针 pFile 将变得陈旧!
这是最大的问题!
一个小得多的问题是语法:
myFile:= FilePCDMsg(pFile); // 不会编译
我的文件:= pFile^; // 应该编译
如果在 TfrmMain.SaveMsg 执行完成后需要文件引用,请勿使用局部变量。
全局变量将起作用,但您必须小心不要在它仍然具有先前和需要的值时覆盖它。
其他(可能更好)的想法是在堆上分配文件变量:使用 New() 然后将指针传递给它。
但是,如果您这样做,则 ExportToFileCallBack() 还应该 Dispose() 分配的指针。
回调被调用了 3 次。
如果您的意思是只调用一次 TfrmMain.SaveMsg 后 ExportToFileCallBack() 将被调用 3 次,
这意味着更多的麻烦!
如果您在第一次 Dispose() 分配的指针,那么指针在第二次和第三次当然将不再有效!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.