In ExportToFileCallback I want to use the file I assigned in SaveMsg but I don't seem to be able to get it from the pointer back to 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;
This DLL is provided by a third party and it has callbacks to do things. Here I am trying to query a camera for its configuration and the call back is called three times. I think it is passing back to me the data it wants me to append to the file I have assigned.
Here is the C code I am trying to replicate in Delphi.
#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;
}
I was overthinking it. The answer is in fact quite simple
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;
Many thanks for helping me out
in procedure TfrmMain.SaveMsg:
the myFile: FilePCDMsg; is a LOCAL variable (saved on stack).
Therefore, when execution of TfrmMain.SaveMsg finishes, the file reference myFile will no longer be valid, and therefore the pointer pFile you passed to CDKMsgExport() will become stale !
This is the biggest problem !
A much smaller problem is the syntax:
myFile:= FilePCDMsg( pFile ); // will not compile
myFile:= pFile^; // should compile
If you need the file reference AFTER execution of TfrmMain.SaveMsg has finished, DO NOT use a local variable.
A global variable will work, but you must be careful that you do not overwrite it while it still has a previous and needed value.
Other (and possibly better) idea is to allocate the file variable on heap: use New() and then pass a pointer to it.
However, if you do this, then the ExportToFileCallBack() should also Dispose() the allocated pointer.
the call back is called three times.
If you mean that the ExportToFileCallBack() will be called 3 times after you call TfrmMain.SaveMsg only one time,
This means more trouble !
IF you Dispose() the allocated pointer in the first time, then of course the pointer will no longer be valid in the 2nd and 3rd time !
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.