Import Filters (How to Create a Plug-In)

www.CAD6.com

The implementation of an import filter for the CAD6interface is a bit more complex than creating export filters. Basically, the import file format determines the complexity of the import filter. The first duty of an import filter developer is to take some time to understand the import file format and to think about how to translate it to MKD entities.

 

Simple Import Filter

For example, lets start with a very simple import filter that is capable of reading a list of coordinate pairs and converts them to markings. The import file for this filter shall be based on the data produced by the simple export filter build in the Export Filters chapter. Each line starts with an identifier indicating whether this is the last line of the file or not. If not, a pair of coordinates follows, separated by commas and terminated by a semicolon. Referring to the standard point types in MKD files, the identifier is MKI_DB_POINT_ANY if another coordinate follows and DB_END if the file ends. A possible file to be imported by this import filter could be:

 

0,10.0,20.0;

0,20.0,20.0;

0,20.0,10.0;

0,10.0,10.0;

999;

 

This file describes four points at the coordinates (10.0,20.0), (20.0,20.0), (20.0,10.0) and (10.0,10.0).

 

First, let's have a look at the basic command procedure of that import filter plug-in. The command procedure is responsible for retrieving the name of the file to be imported. It then opens this file, processes it and subsequently creates some entities using interface procedures. Finally, it handles possible errors. This procedure is basically the same for all import filters.

 

C++ Source Code

// Static variable is used to report errors.

// This is more effective than returning an

// error code from every procedure.

static __int32 gError;

 

//----------------------------------------------------------------------

// Import Filter entry point.

MKI_INTERFACE_EXPORT __int32

MKI_PlugInCommand(

 __int32 f_nCommandID,

 __int32 f_nExecMode,

 void* f_pData )

{

  bool fResult = false;

 

  switch( f_nExecMode )

  {

    case MKI_EXECMODE_HELP:

      // Display associated help file.

      MKI_DialogHelpTopic( g_hGlobalWnd, L"IMPORT", 1 );

      break;

 

    case MKI_EXECMODE_USER:

      // If the plug-in has options to be edited by the user,

      // they should be displayed here! Please use GetActiveWindow()

      // as parent window for any dialog displayed.

      break;

 

    case MKI_EXECMODE_SYSTEM:

      // Nothing to do here...

      break;

 

    case MKI_EXECMODE_GET_PROFILE:

      // Nothing to do here...

      break;

 

    case MKI_EXECMODE_SET_PROFILE:

      // Nothing to do here...

      break;

 

    case MKI_EXECMODE_MENU_INIT:

      // Nothing to do here...

      break;

 

    case MKI_EXECMODE_READY:

      // Nothing to do here...

      break;

  }

  return( fResult );

}

 

Second, let's implement the import callback procedure required in every import filter.

 

C++ Source Code

MKI_INTERFACE_EXPORT __int32

MKI_PlugInImport(

 const LPCWSTR f_pszFileName,

 __int32 f_nMode )

{

  MKI_DUMMYSTRW szDummyStr;

  HANDLE        hFileHandle;

 

  // First, check whether the given file is of a known

  // file format. If not, return immediately.

  // This procedure will not be explained further since

  // is will be unique for each file format.

  if( !PlugInCheckIfFileIsKnown( f_pszFileName ) )

    return( MKI_IMPORT_UNKNOWN );

 

  // Prepare the interface for object creation.

  // Open import file.

  if( MKI_FileOpen( &hFileHandle, f_pszFileName ) )

  {

    if( f_nMode & MKI_IMPORT_MODE_MERGE )

      MKI_UndoInitProcess();

    else

      MKI_DrawingNewFile( false );

 

    // Import data (implementation see below).

    PlugInImport( hFileHandle, f_pszFileName );

 

    // Close import file.

    MKI_FileClose( hFileHandle );

 

    // Error handling.

    switch( g_nError )

    {

      case 999:

        // Terminate the current undo level without

        // maintaining the objects created since the

        // previous call to MKI_UndoInitProcess.

        MessageBox( hGlobalWnd,

                    L"Import canceled.", L"Import Filter", MB_OK );

        goto _error;

 

      case 998:

        // Terminate the current undo level without

        // maintaining the objects created since the

        // previous call to MKI_UndoInitProcess.

        MessageBox( hGlobalWnd,

                    L"Out of Memory.", L"Import Filter", MB_OK );

        goto _error;

 

      case 0:

        // No error occurred, end this switch and continue.

        break;

 

      default:

        // Terminate the current undo level without

        // maintaining the objects created since the

        // previous call to MKI_UndoInitProcess.

        MKI_PrintW( szDummyStr,

                    L"Error %d in line %ld (offset %ld bytes)",
                    gError,
                    (int) MKI_FileReadCurrentLine(),
                    (int) MKI_FileReadCurrentSize() );

        MessageBox( hGlobalWnd, szDummyStr, "Import Filter", MB_OK );

        goto _error;

    }

 

    // Terminate the current undo level while

    // maintaining all objects created since the

    // previous call to MKI_UndoInitProcess.

    if( f_nMode & MKI_IMPORT_MODE_MERGE )

      MKI_UndoFinishProcess();

 

    // If blocks or instances had been modified, a call

    // of the MKI_UndoUpdateLinks() procedure would

    // be necessary here!

    // Redraw all windows to show the newly created objects.

    MKI_DrawWindowAll();

 

    // Terminate the object creation process.

    return( MKI_IMPORT_OK );

  }

  return( MKI_IMPORT_ERROR );

 

_error:

  // Terminate the current undo level without

  // maintaining the objects created since the

  // previous call to MKI_UndoInitProcess.

  if( Merge )

    MKI_UndoCancelProcess();

  else

    MKI_DrawingNewFile( false );

 

  // Terminate the object creation process.

  return( MKI_IMPORT_ERROR );

}

 

Now, let's have a look at the import procedure that is called from within the command procedure. This import procedure reads the data from the import file and translates it into MKD entities.

 

C++ Source Code

void

PlugInImport(

 HANDLE f_hFileHandle,

 const LPCWSTR f_pszFileName )

{

  MKI_FILENAMEW szFileName;

  MKI_DUMMYSTRW szDummyStr;

  __int32       nCount;

  double        dX, dY;

 

  // Until now, no error occurred, so reset gError.

  g_nError = 0;

 

  // Prepare reading from the file, i.e.

  // initialize the file buffer.

  if( !MKI_FileReadInitDisk( f_hFileHandle, false ) )

    return;

 

  // Display a progress indication window. For this

  // reason, assemble a string containing the file's

  // name and a description of the task performed.

  MKI_FileSplitName( f_pszFileName, nullptr, szFileName );

  MKI_CopyW( szDummyStr, L"Importing from file\n" szFileName );

  MKI_DialogShowProgress( "Import Filter", szDummyStr, true );

 

  // Try to read a coordinate pair from the file.

  if( PlugInReadCoordinate( &dX, &dY ) )

  {

    nCount = 0;

 

    do

    {

      // Create an object of type MKI_OBJ_MARK (marking).

      if( nCount == 0 )

        MKI_ObjectOpen( MKI_OBJ_MARK );

 

      // Add one marking to the previously opened object.

      MKI_ObjectAddPoint( MKI_DB_POINT_MARK, dX, dY );

      nCount++;

 

      // Check whether the maximum number of points per object

      // is reached. If so, insert the current object and

      // reset the counter.

      if( nCount >= POINTS_PER_OBJECT )

      {

        if( !MKI_ObjectFastInsert() ) {

          g_nError = 998;

          goto _stop;

        }

        nCount = 0;

      }

    }

    // Try to read further coordinate pairs.

    while( PlugInReadCoordinate( &dX, &dY ) );

 

    // If an object is still open, insert it.

    if( nCount > 0 )

    {

      if( !MKI_ObjectFastInsert() )

        g_nError = 998;

    }

 

    // Read the final semicolon.

    MKI_FileReadSemi();

  }

 

_stop:

  // Finish reading from the file.

  MKI_FileReadExit();

  // Hide the progress indication window.

  MKI_DialogHideProgress();

}

 

Finally, let's implement the basic reading procedure. It first reads the identification at the beginning of each line and, if applicable, the following coordinate pair:

 

C++ Source Code

bool

PlugInReadCoordinate( double* f_pdX, double* f_pdY )

{

  MKI_DUMMYSTRW szText1, 

                szText2;

  __int16       nDummy;

 

  // If any error occurred, stop here.

  if( g_nError )

    return( false );

 

  // Update the progress indication window.

  MKI_PrintW( szText1, L"Line %ld",

              MKI_FileReadCurrentLine() );

  MKI_PrintW( szText2, L"%ld KBytes",

              ( MKI_FileReadCurrentSize() + 1023 ) / 1024 );

  MKI_DialogUpdateProgress( szText1, szText2,
                            MKI_FileReadCurrentSize(),
                            MKI_FileReadTotalSize() );

 

  // Check whether the user pressed the CANCEL

  // button in the progress indication window.

  if( MKI_DialogIsCancelled() )

  {

    g_nError = 999;

    return( false );

  }

 

  // Read the first short value from the file. If its

  // value is DB_END, the file ends here.

  MKI_FileReadInt16( &nDummy );

  if( nDummy == DB_END )

    return( false );

 

  // Read a pair of coordinates separated by commas

  // and terminated by a semicolon.

  MKI_FileReadComma();

  MKI_FileReadDouble( f_pdX );

  MKI_FileReadComma();

  MKI_FileReadDouble( f_pdY );

  MKI_FileReadSemi();

 

  // Check whether a read error occurred.

  if( MKI_FileReadError() )

  {

    g_nError = 2;

    return( false );

  }

  return( true );

}

 

Import filters that want to allow silent running, i.e. that will hook onto the standard File > Open command as well as offering a menu command, must export a MKI_PlugInImport callback procedure that serves this task.

 

For further experience, you can find a more sophisticated version of this import filter in the sources of IMPORT_.DLL. This implementation includes additional code for language-dependent data libraries and the implementation of a customized common dialog window for file name retrievement.

 

CAD6interface 2024.2 - Copyright 2024 Malz++Kassner® GmbH