//////////////////////////////////////////////////////////////////////
			// Code Example: Attribute callbacks 
			//
			//////////////////////////////////////////////////////////////////////

			// This function is passed the step number. This allows for an application to
			// produce code with several steps as demonstrated.
			// Return 1 if you have finished, 0 if otherwise and -1 to exit.

			int CMyCode::RunMyCode(int step)
			{

			//The code below is sample code. On exiting the function the bodies that
			//exist will be drawn

				
				static PK_BODY_t block;
				static PK_BODY_t sheet;
				PK_FACE_t *faces = NULL;
				PK_PART_t *parts = NULL;
				int n_faces = 0;
				int n_parts = 0;
				CString text;
				int finished = 0;
				double cols[] = {1., 0., 0.};
				static PK_ATTDEF_t attdef;
				PK_AXIS2_sf_t basis_set;
				PK_BODY_section_o_t options;
				PK_TOPOL_track_r_t tracking;
				PK_section_2_r_t results;
				PK_ATTDEF_callback_flags_t flags;

				switch( step )
				{
				case 1:
			  
					CExampleAppDoc::ExAppSetStatusBarString("Registered merge and split callback functions for the colour attribute in CSession::RegisterCallbacks. Created a solid block");
					PK_BODY_create_solid_block( 10.0, 10.0, 10.0, NULL, &block );
					break;

				case 2:
				
					CExampleAppDoc::ExAppSetStatusBarString("Coloured all faces of the solid block red");
					PK_BODY_ask_faces(block, &n_faces, &faces);
					PK_ATTRIB_t attrib;
					int i;

					PK_ATTDEF_find("SDL/TYSA_COLOUR", &attdef);
					for(i=0; i< n_faces; i++)
					{
						PK_ATTRIB_create_empty(faces[i], attdef, &attrib);
						PK_ATTRIB_set_doubles(attrib, 0, 3, cols);
					}
					if(n_faces)
						PK_MEMORY_free(faces);
					break;

				case 3:
			 
					CExampleAppDoc::ExAppSetStatusBarString("Created sheet rectangle");
					basis_set.location.coord[0] = 0;
					basis_set.location.coord[1] = 0;
					basis_set.location.coord[2] = 5;
					basis_set.axis.coord[0] = 0;
					basis_set.axis.coord[1] = 0;
					basis_set.axis.coord[2] = 1;
					basis_set.ref_direction.coord[0] = 1;
					basis_set.ref_direction.coord[1] = 0;
					basis_set.ref_direction.coord[2] = 0;
					PK_BODY_create_sheet_rectangle( 20.0, 20.0, &basis_set, &sheet );
					break;

				case 4: 
					CExampleAppDoc::ExAppSetStatusBarString("Performed section retaining the front body. One new face created in the default grey colour, split faces retain the red colour");

					PK_BODY_section_o_m( options );
					options.fence = PK_section_fence_front_c;
					PK_BODY_section_with_sheet_2(block, sheet, &options, &tracking, &results);
					PK_TOPOL_track_r_f( &tracking );
					PK_section_2_r_f( &results );
					break;
				case 5:
					CExampleAppDoc::ExAppSetStatusBarString("Deleted all bodies and switched on the merge and split attribute callbacks");

					flags.split_callback_on = PK_LOGICAL_true;
					flags.merge_callback_on = PK_LOGICAL_true;
					flags.copy_callback_on = PK_LOGICAL_false;
					flags.delete_callback_on = PK_LOGICAL_false;
					flags.receive_callback_on =  PK_LOGICAL_false;
					flags.transmit_callback_on =  PK_LOGICAL_false;

					PK_ATTDEF_set_callback_flags(attdef, &flags);

					PK_SESSION_ask_parts(&n_parts, &parts);
					if(n_parts)
					{
						PK_ENTITY_delete(n_parts, parts);
						PK_MEMORY_free(parts);
					}
					break;

				case 6:
					CExampleAppDoc::ExAppSetStatusBarString("Created the red block and sheet again");
					PK_BODY_create_solid_block( 10.0, 10.0, 10.0, NULL, &block );
					PK_BODY_ask_faces(block, &n_faces, &faces);
					for(i=0; i< n_faces; i++)
					{
						PK_ATTRIB_create_empty(faces[i], attdef, &attrib);
						PK_ATTRIB_set_doubles(attrib, 0, 3, cols);
					}
					if(n_faces)
						PK_MEMORY_free(faces);

					basis_set.location.coord[0] = 0;
					basis_set.location.coord[1] = 0;
					basis_set.location.coord[2] = 5;
					basis_set.axis.coord[0] = 0;
					basis_set.axis.coord[1] = 0;
					basis_set.axis.coord[2] = 1;
					basis_set.ref_direction.coord[0] = 1;
					basis_set.ref_direction.coord[1] = 0;
					basis_set.ref_direction.coord[2] = 0;
					PK_BODY_create_sheet_rectangle( 20.0, 20.0, &basis_set, &sheet );
					break;
				case 7: 
					CExampleAppDoc::ExAppSetStatusBarString("Performed section retaining both bodies. Split faces are now blue with a new green face (CSession::ColourSplitCallback)");
					PK_BODY_section_o_m( options );

					PK_BODY_section_with_sheet_2(block, sheet, &options, &tracking, &results);
					PK_TOPOL_track_r_f( &tracking );
					PK_section_2_r_f( &results );
					break;

				case 8:
					CExampleAppDoc::ExAppSetStatusBarString("Performed boolean unite between the two bodies. Merged faces combined to form one black face (CSession::ColourMergeCallback)");
					PK_BODY_boolean_o_t bool_opts;
					PK_BODY_boolean_o_m( bool_opts );
					PK_boolean_r_t bool_res;

					bool_opts.merge_imprinted = PK_LOGICAL_true;
					PK_SESSION_ask_parts(&n_parts, &parts);
					PK_BODY_boolean_2(parts[0], 1, &parts[1], &bool_opts, &tracking, &bool_res);
					PK_TOPOL_track_r_f( &tracking );
					PK_boolean_r_f( &bool_res );
					break;
				
				default:
					flags.split_callback_on = PK_LOGICAL_false;
					flags.merge_callback_on = PK_LOGICAL_false;
					flags.copy_callback_on = PK_LOGICAL_false;
					flags.delete_callback_on = PK_LOGICAL_false;
					flags.receive_callback_on =  PK_LOGICAL_false;
					flags.transmit_callback_on =  PK_LOGICAL_false;

					PK_ATTDEF_set_callback_flags(attdef, &flags);
					finished = 1;
				}

				return finished;
			}

			//////////////////////////////////////////////////////////////////////
			Session.h
			
			#include "parasolid_kernel.h"

			class CSession  
			{
			public:

				BOOL Start();
				BOOL Stop();

				static void ReturnMemory(int * nBytes, char * * memory, int * ifail);
				static void GetMemory(int * nBytes, char * * memory, int * ifail);
				static void StopFrustrum( int * ifail );
				static void StartFrustrum( int * ifail );
				static PK_ERROR_code_t PKerrorHandler( PK_ERROR_sf_t* error );
				
				CSession();
				~CSession();
			private:
				static void ColourSplitCallback(PK_ENTITY_t old_entity,
				  int n_attribs, const PK_ATTRIB_t attribs[],
				  PK_ENTITY_t new_entity );
				static void ColourMergeCallback(PK_ENTITY_t live_entity,
				  int n_live_attribs, const PK_ATTRIB_t live_attribs[],
				  PK_ENTITY_t doomed_entity,
				  int n_doomed_attribs, const PK_ATTRIB_t doomed_attribs[]);
				void RegisterCallbacks();
			};
			
			//////////////////////////////////////////////////////////////////////
			Session.cpp
			
			#include "Session.h"
			#include "parasolid_kernel.h"
			#include "frustrum_ifails.h"

			// The following are frustrum function declarations

			extern void StartFileFrustrum( int *);
			extern void AbortFrustrum( int *);
			extern void StopFileFrustrum( int *);
			extern void OpenReadFrustrumFile( const int *, const int *, const char *, const int *,
						const int *, int *, int *);
			extern void OpenWriteFrustrumFile( const int *, const int *, const char *, const int *,
						const char *, const int *, int *, int *);
			extern void CloseFrustrumFile( const int *, const int *, const int *, int *);
			extern void ReadFromFrustrumFile( const int *, const int *, const int *, char *, int *,
						int *);
			extern void WriteToFrustrumFile( const int *, const int *, const int *, const char *,
						int *);
			extern int SeekXT(const int, const int, unsigned int, unsigned int);

			// The following are for the delta frustrum

			extern "C" {
				PK_ERROR_code_t FRU_delta_open_for_write(PK_PMARK_t, PK_DELTA_t *);
				PK_ERROR_code_t FRU_delta_open_for_read(PK_DELTA_t);
				PK_ERROR_code_t FRU_delta_write(PK_DELTA_t, unsigned, const char *);
				PK_ERROR_code_t FRU_delta_read(PK_DELTA_t, unsigned, char *);
				PK_ERROR_code_t FRU_delta_delete(PK_DELTA_t);
				PK_ERROR_code_t FRU_delta_close(PK_DELTA_t);
				int FRU__delta_init( int action );
			}


			//////////////////////////////////////////////////////////////////////
			// Construction/Destruction
			//////////////////////////////////////////////////////////////////////

			CSession::CSession()
			{
				// Start up Parasolid
				if ( !Start() )
					exit(0);
			}

			CSession::~CSession()
			{
				// Close down Parasolid
				Stop();
			}

			// Starts up Parasolid Session, returns true is successful, false otherwise.

			BOOL CSession::Start()
			{
				BOOL ok = TRUE;

				// Register frustrum functions
				// Note: the GO functions are registered in CExampleAppDoc
				
				PK_FSTART_f_t sf = StartFrustrum;
				PK_FABORT_f_t af = AbortFrustrum;
				PK_FSTOP_f_t stf = StopFrustrum;
				PK_FMALLO_f_t gm = GetMemory;
				PK_FMFREE_f_t rm = ReturnMemory;
				PK_FFOPRD_f_t orf = OpenReadFrustrumFile;
				PK_FFOPWR_f_t ow = OpenWriteFrustrumFile;
				PK_FFCLOS_f_t cf = CloseFrustrumFile;
				PK_FFREAD_f_t rf = ReadFromFrustrumFile;
				PK_FFWRIT_f_t wf = WriteToFrustrumFile;
				PK_FFSKXT_f_t sk = SeekXT;

				PK_SESSION_register_fru_o_t fru_opts;
				PK_SESSION_register_fru_o_m(fru_opts);

				fru_opts.fstart = &sf;
				fru_opts.fabort = ⁡
				fru_opts.fstop = &stf;
				fru_opts.fmallo = &gm;
				fru_opts.fmfree = &rm;
				fru_opts.ffoprd = &orf;
				fru_opts.ffopwr = &ow;
				fru_opts.ffclos = &cf;
				fru_opts.ffread = &rf;
				fru_opts.ffwrit = &wf;
				fru_opts.ffskxt = &sk;

				VERIFY(PK_SESSION_register_fru_2(&fru_opts) == PK_ERROR_no_errors);
				// Register Delta Frustrum

				PK_DELTA_frustrum_t delta_fru;

				delta_fru.open_for_write_fn = FRU_delta_open_for_write;
				delta_fru.open_for_read_fn = FRU_delta_open_for_read;
				delta_fru.close_fn = FRU_delta_close; 
				delta_fru.write_fn = FRU_delta_write;
				delta_fru.read_fn = FRU_delta_read;
				delta_fru.delete_fn = FRU_delta_delete;
			  
				VERIFY(PK_DELTA_register_callbacks(delta_fru) == PK_ERROR_no_errors);

				// Register Error Handler
				PK_ERROR_frustrum_t errorFru;
				errorFru.handler_fn = PKerrorHandler;
				VERIFY( PK_ERROR_register_callbacks( errorFru ) == PK_ERROR_no_errors );


				// Starts the modeller

				PK_SESSION_start_o_t options;
				PK_SESSION_start_o_m( options );

				// By default session journalling is turned off, to enable set options.journal_file 
				// to where you want this data to be written to.
				// eg. 
				// options.journal_file = "c:\\temp\\test";
				
				PK_SESSION_start( &options );
				RegisterCallbacks();
				// Check to see if it all started up OK
				PK_LOGICAL_t was_error = PK_LOGICAL_true;
				PK_ERROR_sf_t error_sf;
				PK_ERROR_ask_last( &was_error, &error_sf );
				if ( was_error )
					return false;

				// Enable latest behaviour
				PK_SESSION_behaviour_t behaviour_requested;
				behaviour_requested.behaviour_type = PK_SESSION_behave_as_latest_c;
				behaviour_requested.behaviour_value = 0;
				PK_SESSION_set_behaviour_o_t behaviour_opts;
				PK_SESSION_set_behaviour_o_m(behaviour_opts);
				PK_SESSION_behaviour_t behaviour_set;
				PK_SESSION_behaviour_t behaviour_previous;
				PK_behaviour_status_t behaviour_status;
				PK_SESSION_set_behaviour(behaviour_requested, &behaviour_opts, &behaviour_set, &behaviour_previous, &behaviour_status);
				// A production application would check for errors and inspect the fields of behaviour_set,
				// behaviour_previous and behaviour_status to confirm the requested behaviour was recognised
				
				return ok;
			}

			BOOL CSession::Stop()
			{
				PK_SESSION_stop();
				return TRUE;
			}

			void CSession::StartFrustrum(int * ifail)
			{
				*ifail = FR_no_errors;	
				FRU__delta_init( 1 );
				StartFileFrustrum( ifail );
			}

			void CSession::StopFrustrum(int * ifail)
			{

				*ifail = FR_no_errors;
				FRU__delta_init( 2 );
				StopFileFrustrum( ifail );
			}

			void CSession::GetMemory(int * nBytes, char * * memory, int * ifail)
			{

				*memory = new char[ *nBytes ];
				*ifail = (*memory) ? FR_no_errors : FR_memory_full;
			}

			void CSession::ReturnMemory(int * nBytes, char * * memory, int * ifail)
			{
				delete[] *memory;
				*ifail = FR_no_errors;
			}

			PK_ERROR_code_t CSession::PKerrorHandler( PK_ERROR_sf_t* error )
			{
				char text[500];
				sprintf_s(text, 500, "PK error: %s returned %s.", error->function,
					error->code_token);
				AfxMessageBox(CString(text));
				return error->code;
			}

			void CSession::RegisterCallbacks()
			{
				PK_ATTDEF_t attdef;
				PK_ATTDEF_callback_fns_s callbacks;
				PK_ATTDEF_find("SDL/TYSA_COLOUR", &attdef);
				callbacks.split_fn = ColourSplitCallback;
				callbacks.merge_fn = ColourMergeCallback;
				PK_ATTDEF_register_cb_o_t callback_opts;
				PK_ATTDEF_register_cb_o_m (callback_opts);
				PK_ATTDEF_register_cb(attdef, &callbacks, &callback_opts);

			}

			void CSession::ColourMergeCallback(PK_ENTITY_t live_entity,
				  int n_live_attribs, const PK_ATTRIB_t live_attribs[],
				  PK_ENTITY_t doomed_entity,
				  int n_doomed_attribs, const PK_ATTRIB_t doomed_attribs[] )
			{
			//live entity will be coloured black
				double cols[] = {0., 0., 0.};
				PK_ATTDEF_t attdef;
				PK_ATTRIB_t attrib;

				PK_ENTITY_delete(1, &live_attribs[0]);
				PK_ATTDEF_find("SDL/TYSA_COLOUR", &attdef);
				PK_ATTRIB_create_empty(live_entity, attdef, &attrib);
				PK_ATTRIB_set_doubles(attrib, 0, 3, cols);

			}

			void CSession::ColourSplitCallback(PK_ENTITY_t old_entity,
				  int n_attribs, const PK_ATTRIB_t attribs[],
				  PK_ENTITY_t new_entity )
			{
			//new entity will be coloured green
				double cols[] = {0., 1., 0.};
				PK_ATTDEF_t attdef;
				PK_ATTRIB_t attrib;

				PK_ATTDEF_find("SDL/TYSA_COLOUR", &attdef);
				PK_ATTRIB_create_empty(new_entity, attdef, &attrib);
				PK_ATTRIB_set_doubles(attrib, 0, 3, cols);

			//old entity will be coloured blue
				double cols1[] = {0., 0., 1.};

				PK_ENTITY_delete(1, &attribs[0]);
				PK_ATTRIB_create_empty(old_entity, attdef, &attrib);
				PK_ATTRIB_set_doubles(attrib, 0, 3, cols1);

			}