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
&currentRec)
{
  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/

Reply via email to