Here're the functions to create a .PDB database on Palm handheld by
CodeWarrior:
Err OpenDatabase(UInt32 typeDB,UInt32 creatorID,const char*
nameP,DmOpenRef &pDB,LocalID &dbId)
{
Err err=0;
LocalID AppInfoID;
UInt *AppInforPtr=NULL;
UInt16 attributes;
pDB = DmOpenDatabaseByTypeCreator(typeDB,creatorID,dmModeReadWrite);
//if Fail
if (pDB==0)
{
//Create a record database
err = DmCreateDatabase(0,nameP,creatorID,typeDB,false);//Record database
if (err!=0)
{
err=DmGetLastErr();
ErrFatalDisplayIf(err,"Can't create database!Try again");
return err;
}
//Try again
pDB = DmOpenDatabaseByTypeCreator(typeDB,creatorID,dmModeReadWrite);
//Check again
if (pDB==0)
{
ErrFatalDisplayIf(true,"Can't open database");
return DmGetLastErr();
}
//Set for DatabaseInfo block
//Get Database ID to access AppInfo block by the func:DmDatabaseInfo()
if (DmOpenDatabaseInfo(pDB,&dbId,NULL,NULL,NULL,NULL))
return dmErrInvalidParam;
//Get AppInfoID from cardNo and DbID
DmDatabaseInfo(0,dbId,NULL,&attributes,NULL,NULL,NULL,NULL,NULL,&AppInfoID,N
ULL,NULL,NULL);
attributes |=dmHdrAttrBackup;//dmHdrAttrResDB,dmHdrAttrAppInfoDirty
DmSetDatabaseInfo(0,dbId,NULL,&attributes,NULL,NULL,NULL,NULL,NULL,NULL,NULL
,NULL,NULL);
//DmDatabaseInfo(0,dbId,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&AppInfoID,NULL,N
ULL,NULL);
//Initialize for AppInfo:sizeof(UInt) is size of AppInfo
if (AppInfoID == NULL)
{
VoidHand handle;
handle = DmNewHandle (pDB,sizeof(UInt));//sizeof(StructAppInfo)
if (!handle) return dmErrMemError;
AppInfoID = MemHandleToLocalID(handle);
DmSetDatabaseInfo(0,dbId,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&AppInfoID,NULL,
NULL,NULL);
}
AppInforPtr =(UInt*)MemLocalIDToLockedPtr(AppInfoID,0);
if (AppInforPtr!=NULL)
{
UInt BusID=1;
//Clear the app info block.
DmSet(AppInforPtr,0,sizeof(UInt),0);//sizeof(StructAppInfo)
DmWrite(AppInforPtr,0,&BusID,sizeof(BusID));
MemPtrUnlock(AppInforPtr);
}
//The conduit ignores dmHdrAttrAppInfoDirty
//CloseDatabase(pDB);
if (AppInforPtr==NULL)
DmDeleteDatabase(0,dbId);
}
return 0;
}
I use the function to create a database and it runs well with some
action on the database:add/update/delete... on palm handheld.
Then on PC Desktop ,I use CDK4.02,Windows 2000 and VC++6.0 to create a
Conduit(MFC Framework Conduit) and then I modify in "class App" of this
conuit the following:
My conduit use to read .PDB file on Palm handheld created by CodeWarrior
and write to text file on PC Desktop,value for each record on .PDB database
is a line in text file on PC Desktop
long OpenRemoteDatabase(byte& hRemoteDatabase, CSyncProperties& rProps)
{
// Open the remote database name passed in from the sync properties.
// This name is derived from the registry database.
return(SyncOpenDB(rProps.m_RemoteName[0], 0, hRemoteDatabase));
}
////////////////////////////////////////////////////////////////////////////
/
// CloseRemoteDatabase()
////////////////////////////////////////////////////////////////////////////
/
// Function: CloseRemoteDatabase()
//
// Description: Close the remote database
//
// Parameters: byte - hRemoteDatabase, handle to remote database
//
// Returns: !0 if error
////////////////////////////////////////////////////////////////////////////
/
long CloseRemoteDatabase(byte hRemoteDatabase)
{
return(SyncCloseDB(hRemoteDatabase));
}
///////////////////////////////////////////////
long AllocateRawRecordMemory(CRawRecordInfo& rawRecord, WORD size)
{
long retval = 0;
// Allocate memory for rawRecord data
rawRecord.m_TotalBytes = 0;
rawRecord.m_pBytes = (BYTE*) new char [size];
if (rawRecord.m_pBytes)
{
rawRecord.m_TotalBytes = size;
memset(rawRecord.m_pBytes, 0, size);
}
return(retval);
}
//////////////////////////////////////////////////
long FreeRawRecordMemory(CRawRecordInfo& rawRecord)
{
long retval = 0;
// Free memory for rawRecord data
if (rawRecord.m_TotalBytes > 0 && rawRecord.m_pBytes)
delete rawRecord.m_pBytes;
return(retval);
}
////////////////////////////////////////////////////
long ConvertHHtoPC(CRawRecordInfo& rawRecord, CString& text)
{
long retval = 0;
//copy the raw data into string
text = (char*)rawRecord.m_pBytes;
text = text + "\r\n";
return(retval);
}
////////////////////////////////////////////////////////////
long ConvertPCtoHH(CString& text, CRawRecordInfo& rawRecord)
{
long retval = 0;
int size;
//trim all the ending white spaces
text.TrimRight();
//copy string into raw data and set the size
size = text.GetLength()+1;
if ( size > TRAK_RAW_REC_MEM ) size = TRAK_RAW_REC_MEM;
memcpy(rawRecord.m_pBytes, text.GetBuffer(size), size);
rawRecord.m_RecSize = TRAK_RAW_REC_MEM;
return(retval);
}
////////////////////////////////////////////////////////////////////////////
////////
long CopyHHtoPC(CSyncProperties& rProps, CString strLocalFile, byte
hRemoteDatabase )
{
long retval = 0;
CRawRecordInfo rawRecord;
CString strRecord, strLocalFile2;
DWORD dwByteWritten;
HANDLE fp;
WORD NumRec;
SyncGetDBRecordCount( hRemoteDatabase, NumRec );
if ( NumRec == 0 )
{
AfxMessageBox( "There is no data to copy to PC");
LogAddFormattedEntry( slText, FALSE, "There is no data to copy to PC\n");
return -1;
}
memset(&rawRecord, 0, sizeof(CRawRecordInfo));
rawRecord.m_FileHandle = hRemoteDatabase;
//rawRecord.m_RecIndex = NumRec - 1;
// allocate memory for the raw record to max memopad record size
AllocateRawRecordMemory(rawRecord, TRAK_RAW_REC_MEM);
//LogAddFormattedEntry( slText, FALSE, "Begin of CopyHHtoPC");
//Create the new file to overwrite old file(memo.dat)
fp = CreateFile( (LPCSTR) strLocalFile, GENERIC_READ | GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if ( fp == INVALID_HANDLE_VALUE )
{
LogAddFormattedEntry( slText, FALSE, "Can not open local file" );
return -1;
}
// read the remote records from the beginning
rawRecord.m_RecIndex = 0;
// start transferring records from Palm to PC
while( (retval=SyncReadRecordByIndex( rawRecord)) == 0)
{
ConvertHHtoPC( rawRecord, strRecord );
LogAddFormattedEntry( slText, FALSE, (LPCSTR) strRecord );
//If not last record
if (WriteFile( fp, (LPCSTR) strRecord, strRecord.GetLength(),
&dwByteWritten, NULL ) == FALSE )
{
LogAddFormattedEntry(slText, FALSE, "Write local file error");
break;
}
// continue to next record
rawRecord.m_RecIndex++;
}
// close local file(s)
CloseHandle( fp );
FreeRawRecordMemory(rawRecord);
return(retval);
}
//Note : the function CopyPCtoHH always use the filename strLocalFile 'as
is'.
//It will not append extension, so any program that calls this function,
should
//prepare a complete strLocalFile
////////////////////////////////////////////////////////////////////////////
///////
long CopyPCtoHH(CSyncProperties& rProps, CString strLocalFile, byte
hRemoteDatabase)
{
long retval = 0;
CRawRecordInfo rawRecord;
LPTSTR lpStr = !NULL;
char arTrakBuffer[TRAK_FILE_SIZE], *pRec;
char Seperator[] = "\r\n";
CString strLine;
HANDLE fp;
DWORD dwByteRead;
// delete the the remote database
// Note that this implementation purges all handheld data based on
// our particular definition of copy pc to handheld.
//LogAddFormattedEntry( slText, FALSE, "Begin of CopytoHH");
retval = SyncPurgeAllRecs(hRemoteDatabase);
// log error
if (retval)
{
LogAddFormattedEntry( slText, FALSE, "Could not clear the database on
PP.");
goto abort;
}
//initialize the rawRecord
memset(&rawRecord, 0, sizeof(CRawRecordInfo));
rawRecord.m_FileHandle = hRemoteDatabase;
rawRecord.m_RecIndex = 0;
//Allocate the pointer to buffer to contain data of rawRecord
AllocateRawRecordMemory(rawRecord, TRAK_RAW_REC_MEM);
memset( arTrakBuffer, 0, TRAK_FILE_SIZE );
// open existing file
fp = CreateFile((LPCSTR) strLocalFile, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( fp == INVALID_HANDLE_VALUE )
{
LogAddFormattedEntry( slText, FALSE, "Can not open local file %s",
strLocalFile );
return -1;
}
if ( ReadFile( fp, arTrakBuffer, TRAK_FILE_SIZE, &dwByteRead, NULL ) ==
FALSE )
{
LogAddFormattedEntry( slText, FALSE, "Can not read local file" );
return -1;
}
//each line of file is one record on database of hand-held
pRec = strtok( arTrakBuffer, Seperator );
while( pRec != NULL )
{
// convert pc format to hh format
ConvertPCtoHH( CString(pRec), rawRecord);
LogAddFormattedEntry( slText, FALSE, pRec );
// set category id(unfiled category) or 1-15
rawRecord.m_CatId = 0;
//write to remote database
retval = SyncWriteRec(rawRecord);
if (retval)
{
LogAddFormattedEntry( slText, FALSE, "Error writing to HH DB");
goto abort;
}
// clear the record id for hh to assign
// it also avoids writing to the same record id on the hh.
//Add new record into unfiled category
rawRecord.m_RecId = 0;//Return new record index
rawRecord.m_CatId = 0;
//Find the next token
pRec = strtok( NULL, Seperator );
}
CloseHandle( fp);
abort:
// free allocated memory
FreeRawRecordMemory(rawRecord);
return(retval);
}
ExportFunc long OpenConduit(PROGRESSFN pFn, CSyncProperties& rProps)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
long retval = -1;
byte hRemoteDatabase=0;
CString localFileName;
CONDHANDLE conduitHandle =(CONDHANDLE)0;
if (pFn)
{
// If the conduit is set to do nothing, then make a note of it and return.
if (rProps.m_SyncType == eDoNothing)
{
LogAddEntry("SalesNexus - sync configured to Do Nothing",slText,false);
return 0;
}
LogAddFormattedEntry(slText,FALSE,"SalesNexus starts");
//Register this conduit with SyncMgrDLL for communication to HH
if (retval = SyncRegisterConduit(conduitHandle))
return(retval);
//Open the remote database
OpenRemoteDatabase(hRemoteDatabase,rProps);
//INFOFILE's similar to m_LocalName of CSyncProperties
//use fileName provided by CSyncProperties from the registry
//database if provided
if (strlen(rProps.m_LocalName) != 0)
{
//get the path and file name and concatnate them together
localFileName = rProps.m_PathName;
localFileName += rProps.m_LocalName;
}
else
{
//use the internally defined name
localFileName = rProps.m_PathName;
localFileName += INFOFILE;//SalesNexus.dat
}
LogAddFormattedEntry(slText,FALSE,"Local file on Desktop is
%s\n",localFileName);
switch (rProps.m_SyncType)
{
case eFast:
case eSlow:
{
LogAddFormattedEntry(slText,FALSE,"HH<----->PC");
}
break;
case ePCtoHH:
case eInstall:
case eProfileInstall:
{
//Copy from PC to handheld
TRACE0("Text Conduit: PC -> HH\n");
LogAddFormattedEntry( slText, FALSE, "PC------>HH");
//Take care: CopyPCtoHH needs the file w/ appropriate extension
//It will not add by default
retval = CopyPCtoHH(rProps,localFileName, hRemoteDatabase);
}
break;
case eHHtoPC:
case eBackup:
{
LogAddFormattedEntry(slText,FALSE,"HH------>PC");
retval = CopyHHtoPC(rProps,localFileName,hRemoteDatabase);
}
break;
case eDoNothing:
default:
break;
}
//Close the remote database
if (hRemoteDatabase)
CloseRemoteDatabase(hRemoteDatabase);
//Log finish
if (!retval)
LogAddEntry("SalesNexus Conduit", slSyncFinished, FALSE);
else
LogAddEntry("SalesNexus Conduit", slSyncAborted, FALSE);
SyncUnRegisterConduit(conduitHandle);
/*
CSalesNexusMonitor* pMonitor;
pMonitor = new CSalesNexusMonitor(pFn, rProps, myInst);
if (pMonitor)
{
pMonitor->SetFilelinkSupport(SubscriptionSupported());
retval = pMonitor->Engage();
delete pMonitor;
}
*/
}
return(retval);
}
I define some parameters for "template database" the following on
CodeWarrior:
#define TYPE_DB_ACT ('data')
#define NAME_DB_ACT ("acdb")
#define CREATOR_ID_ACT ('acdb')
#define ACT_NAME 50
#define ACT_DATE 50
#define ACT_TIME 5
#define ACT_YTDSALES 20
//Define data structure for database
typedef struct
{
int act_id;
int act_conFk;
int act_typeFk;
char act_name[ACT_NAME+1];
char acd_date[ACT_DATE+1];
char act_time[ACT_TIME+1];
char act_ytdS[ACT_YTDSALES+1];
}ActivityDB;
typedef ActivityDB* ActivityDBPtr;
Then I create a "template database" with the function:
Err CreateActivityDatabase(UInt32 typeDB,UInt32 creatorID,const Char
*nameP,DmOpenRef &pDB,LocalID &DbIDSource)
{
ActivityDBPtr rec;
int i=0;
Boolean b;
Err err=0;
Handle hRecord;
UInt16 currentRec;
err=OpenDatabase(typeDB,creatorID,nameP,pDB,DbIDSource);
if (err) goto end;
for(i=0;i<numActivities;i++)
{
rec = (ActivityDBPtr)MemPtrNew(sizeof(ActivityDB));
MemSet((void*)rec,(UInt32)sizeof(ActivityDB),0);
b=NewRecord(pDB,sizeof(ActivityDB),hRecord,currentRec);
if (b)
{
if (hRecord)
{
rec->act_id=i;
rec->act_conFk=i;
rec->act_typeFk=i;
if (StrLen(ActivityName[i]))
StrCopy(rec->act_name,ActivityName[i]);
if (StrLen(ActivityDate[i]))
StrCopy(rec->acd_date,ActivityDate[i]);
if (StrLen(ActivityTime[i]))
StrCopy(rec->act_time,ActivityTime[i]);
if (StrLen(ActivityYtdSales[i]))
StrCopy(rec->act_ytdS,ActivityYtdSales[i]);
err=SetValueRecordForDatabase(hRecord,rec);
}
}
else
{
//ErrFatalDisplayIf(b==false,"Can't create source database!Try
again");
return DmGetLastErr();
}
}
err=CloseDatabase(pDB);
FrmCustomAlert(CreateDatabaseAlert,"Create database successfully","","");
end:
//Don't use memory that allocate for rec,free it
if (rec) MemPtrFree(rec);
return err;
}
Boolean NewRecord(DmOpenRef pDB,UInt32 sizeDatabase,Handle &hRecord,UInt16
¤tRec)
{
Err err=0;
Char zero=0;
UInt16 uIndex;
//Calculate total records
uIndex=GetNumRecords(pDB);
//Create new record
if (pDB)
{
hRecord=(Handle)DmNewRecord(pDB,&uIndex,sizeDatabase);
//If successfully
if (hRecord)
{
VoidPtr p;
//Lock the record to write data
p = MemHandleLock(hRecord);
//Init the begin value for record
err = DmWrite(p,0,&zero,sizeDatabase);
//Unlock pointer
MemPtrUnlock(p);
//Release the record for the database manager
DmReleaseRecord(pDB,uIndex,true);
//Remember the index of current record
currentRec=uIndex;
return true;
}
else
{
ErrFatalDisplayIf(err,"Couldn't create a new record");
return false;
}
}
else
{
ErrFatalDisplayIf(err,"Couldn't create a new record");
return false;
}
}
Err SetValueRecordForDatabase(Handle hRecord,ActivityDBPtr rec)
{
Err err=0;
VoidPtr p =(VoidPtr)MemHandleLock(hRecord);
UInt32 offset=0;
UInt32 size;
size=sizeof(int);
DmWrite(p,offset,(void*)&(rec->act_id),size);
offset+=size;
DmWrite(p,offset,(void*)&(rec->act_conFk),size);
offset+=sizeof(int);
DmWrite(p,offset,(void*)&(rec->act_typeFk),size);
offset+=sizeof(int);
if (rec->act_name!=NULL)
{
size=ACT_NAME+1;
DmWrite(p,offset,rec->act_name, size);
offset+=size;
}
if (rec->acd_date!=NULL)
{
size=ACT_DATE+1;
DmWrite(p,offset,rec->acd_date,size);
offset+=size;
}
if (rec->act_time!=NULL)
{
size=ACT_TIME+1;
DmWrite(p,offset,rec->act_time,size);
offset+=size;
}
if (rec->act_ytdS!=NULL)
{
size=ACT_YTDSALES+1;
DmWrite(p,offset,rec->act_ytdS,size);
offset+=size;
}
MemPtrUnlock(p);
return err;
}
Then I build my conduit and then I register it with Hotsync Manager to
have in the list of conduits(Icon on TaskBar/Custom/list of conduits)
Some information about Register with Hotsync Manager
Conduit:SalesNexus.dll
Creator ID:acdb
Directory:product
File :product.dat
Remote Database:acdb
Name: SalesNexusConduit
User Name:POSE
Priority:2
My conduit doesn't recognize by Hotsync Manager(in log file progress)
but when I register my conduit with "Memo Pad" on Palm handheld,it runs
well(in log file progress,I see the some information that I write for this
conduit)
Conduit:SalesNexus.dll
Creator ID:memo
Directory:product
File :product.dat
Remote Database:MemoDB
Name: SalesNexusConduit
User Name:POSE
Priority:2
I also check some cases:
My conduit registered on the desktop with my Creator ID(my own
created record database)
Don't have any other application/database on Palm handheld has
CreatorID with my own created record database
Please help me about some questions:
I must create a record database with some attributes/functions to my
conduit "recognize" my own created record database on palm
handheld?(Ex:?????),Must I have other application infor? or my conduit have
any missing?
Thanks in advance,
Trinh.
--
For information on using the Palm Developer Forums, or to unsubscribe, please see
http://www.palmos.com/dev/support/forums/