Difference between revisions of "Function Definition"

From FM Plugin Wikipedia
Jump to: navigation, search
(New page: By default, the FM 7 API requires you to define each Function Definition in multiple files. This means duplication on Mac & Windows. It is possible to modify the main FMExample_Plugin.cpp ...)
 
Line 24: Line 24:
 
Define each of our plugins details.
 
Define each of our plugins details.
  
For each Function Definition, I have created a set of definitions as below.  The 'ID' as far as I can tell can be any number, but once you have set it for a function, you cannot change or else it will no longer link for any FileMaker database which calls that function.  I have used increments of 10 so that I can insert a function at a later date if wanted.
+
For each Function Definition, I have created a set of definitions as below.  The 'ID' as far as I can tell can be any number, but once you have set it for a function, you cannot change it or else it will no longer link for any FileMaker database which calls that function.  I have used increments of 10 so that I can insert a function at a later date if wanted.
  
  
Line 107: Line 107:
  
 
Notice that our actual Function Definition is now a single line per definition.
 
Notice that our actual Function Definition is now a single line per definition.
 +
 +
 +
 +
===Step Five===
 +
Update our Plugin Shutdown routine.  Check that we are using the same ID's
 +
 +
/* ::=- Do_PluginShutdown =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=:: */
 +
static void Do_PluginShutdown(void)
 +
{
 +
// Unregister plug-in functions
 +
fmx::QuadCharAutoPtr pluginID('I', 'D', 'M', 'A');
 +
fmx::errcode err;
 +
 +
err = fmx::ExprEnv::UnRegisterExternalFunction(*pluginID, IDMA_Version_ID );
 +
err = fmx::ExprEnv::UnRegisterExternalFunction(*pluginID, IDMA_DoScript_ID );
 +
 +
// DeInitialise any variables as necessary
 +
 +
} // Do_PluginShutdown
 +
 +
 +
 +
===Step Six===
 +
I also wanted to move my Plugin Option String,  Name and Description out of the  .string or  .rc  files.  I added their  #define's earlier in step one.  Now, I need to get the plugin to use these instead.
 +
 +
 +
*1st - Add the following two new functions
 +
 +
void copyCharToUnichar(char * S, FMX_Long maxLength, FMX_Unichar * R)
 +
{  // convert the 'char' string into a 'FMX_Unichar' string.  Assumes NULL byte terminated string passed.
 +
long i = 0;
 +
 +
while ( (i < (maxLength-2)) && (S[i] != 0) )
 +
{
 +
R[i] = (FMX_Unichar)S[i];
 +
i++;
 +
}
 +
R[i] = 0x0000; // terminate with a NULL
 +
 +
}
 +
 +
 +
void IDMA_GetString(unsigned long whichString, FMX_ULong /* winLangID */, FMX_Long resultsize, FMX_Unichar* string)
 +
{  // takes the requested 'whichString' and returns the appropriate response, converted to a UniChar with a NULL termination.
 +
switch (whichString)
 +
{
 +
case kFMXT_OptionsStr: copyCharToUnichar(IDMA_Plugin_OptionString, resultsize, string);    break;    // the "IDMA1nnYYnn";  string
 +
case kFMXT_NameStr: copyCharToUnichar(IDMA_Plugin_Name, resultsize, string);    break;    // the plugin name.  eg.  IDMA Plugin
 +
case kFMXT_AppConfigStr: copyCharToUnichar(IDMA_Plugin_Description, resultsize, string);    break;    // the plugin description.  eg.  This plugin...
 +
 +
default: copyCharToUnichar("Error : Unknown Request" , resultsize, string);
 +
}// switch (whichString)
 +
 +
} // IDMA_GetString (FMX_Unichar* version)
 +
 +
 +
*2nd - Modify the  FMExternCallProc(FMX_ExternCallPtr pb)  function.
 +
 +
case kFMXT_GetString:
 +
{
 +
IDMA_GetString(gFMX_ExternCallPtr->parm1, gFMX_ExternCallPtr->parm2, gFMX_ExternCallPtr->parm3, reinterpret_cast<FMX_Unichar*>(gFMX_ExternCallPtr->result));
 +
}
 +
break;

Revision as of 22:18, 11 July 2007

By default, the FM 7 API requires you to define each Function Definition in multiple files. This means duplication on Mac & Windows. It is possible to modify the main FMExample_Plugin.cpp file to include the definitions all in the one file, removing the duplication.


In this example, I have replaced the use of the 'FMExample.strings' file (Mac) and 'FMExamplePlugin.rc' file (Windows) to define each Function.

Step One

Define the Plugin Option String, Name and Description fields.

#define IDMA_Plugin_Name			"IDMA Plugin"
#define IDMA_Plugin_Description			"This plug-in provides additional functionality to FileMaker."

#define IDMA_Plugin_OptionString		"IDMA1nnYYnn"
//						 ^--^ || | |---- // No Win32s support
//						 |    || |------ // Want idle time 
//						 |    ||-------- // No old external functions
//						 |    |--------- // Has preferences dialog
//						 |-------------- // 'IDMA' plug-in ID

Note : I just copied these from the .strings or .rc file, then appended the #define name to the start instead.


Step Two

Define each of our plugins details.

For each Function Definition, I have created a set of definitions as below. The 'ID' as far as I can tell can be any number, but once you have set it for a function, you cannot change it or else it will no longer link for any FileMaker database which calls that function. I have used increments of 10 so that I can insert a function at a later date if wanted.


// Function IDs				====WARNING :  ID Values are important.  Do not change once used, or will affect FileMaker linkage !!! ===
#define IDMA_Version_Name		"Version( \"Version\" )"
#define IDMA_Version_ID			201
#define IDMA_Version_Min		0
#define IDMA_Version_Max		1
#define IDMA_Version_Flags		fmx::ExprEnv::kMayEvaluateOnServer | fmx::ExprEnv::kDisplayInAllDialogs

#define IDMA_DoScript_Name		"idma_DoScript( Get(FileName) ; scriptname ; paramater )"
#define IDMA_DoScript_ID		211
#define IDMA_DoScript_Min		2
#define IDMA_DoScript_Max		3
#define IDMA_DoScript_Flags		fmx::ExprEnv::kMayEvaluateOnServer | fmx::ExprEnv::kDisplayInAllDialogs


Repeat the above for each additional Function Definition.


Step Three

We need to create a couple of new functions to replicate the 'Do_GetString' function that comes with the API to read our define's instead.

static fmx::TextAutoPtr _n(char * S)
{ // return the function name only as a FMX::TextAutoPtr.  eg. returns  'Version' from  'Version( \"Version\" )'

	fmx::TextAutoPtr	R;
	R->Assign(S);

	// The string for this whichStringID is a Function Prototype, but all the plug-in needs now is the Function Name by itself.
	fmx::TextAutoPtr		parenToken;		parenToken->Assign("(");

	unsigned long		originalSize = R->GetSize();
	unsigned long		firstParenLocation; 

	firstParenLocation = R->Find(*parenToken, 0);
	R->DeleteText(firstParenLocation, originalSize-firstParenLocation);

	return R;

} // Do_GetString (TextAutoPtr version)

static fmx::TextAutoPtr _p(char * S)
{ // return the function definition as a FMX::TextAutoPtr.  eg. returns  'Version( \"Version\" )'

	fmx::TextAutoPtr	R;
	R->Assign(S);

	return R;

} // Do_GetString (TextAutoPtr version)


Step Four

Modify the Do_Plugin_Inti() function as below

/* ::=- Do_PluginInit =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=:: */
static FMX_Long Do_PluginInit(FMX_Short version) 
{
	// Check the app API version
	if ((version < k70ExtnVersion) || (version > kMaxExtnVersion)) 
	{
		// This version of FileMaker is not supported; let FileMaker disable this 
		// plug-in and report the problem to the user.
		return (kBadExtnVersion);
	}

	// Initialise any variables as necessary.
	
	// Register plug-in functions
	fmx::QuadCharAutoPtr	pluginID('I', 'D', 'M', 'A');
	fmx::errcode			err;

	err = fmx::ExprEnv::RegisterExternalFunction(*pluginID, IDMA_Version_ID, *_n(IDMA_Version_Name), *_p(IDMA_Version_Name), IDMA_Version_Min, IDMA_Version_Max, IDMA_Version_Flags, Do_Version );
	err = fmx::ExprEnv::RegisterExternalFunction(*pluginID, IDMA_DoScript_ID, *_n(IDMA_DoScript_Name), *_p(IDMA_DoScript_Name), IDMA_DoScript_Min, IDMA_DoScript_Max, IDMA_DoScript_Flags, Do_StartScript	 );	
	
	// Return kCurrentExtnVersion to enable the plug-in in FileMaker.
	return (kCurrentExtnVersion);

} // Do_PluginInit

Notice that our actual Function Definition is now a single line per definition.


Step Five

Update our Plugin Shutdown routine. Check that we are using the same ID's

/* ::=- Do_PluginShutdown =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=:: */
static void Do_PluginShutdown(void) 
{
	// Unregister plug-in functions
	fmx::QuadCharAutoPtr	pluginID('I', 'D', 'M', 'A');
	fmx::errcode			err;
	
	err = fmx::ExprEnv::UnRegisterExternalFunction(*pluginID, IDMA_Version_ID );
	err = fmx::ExprEnv::UnRegisterExternalFunction(*pluginID, IDMA_DoScript_ID );
	
	// DeInitialise any variables as necessary
		
} // Do_PluginShutdown


Step Six

I also wanted to move my Plugin Option String, Name and Description out of the .string or .rc files. I added their #define's earlier in step one. Now, I need to get the plugin to use these instead.


  • 1st - Add the following two new functions
void copyCharToUnichar(char * S, FMX_Long maxLength, FMX_Unichar * R)
{  // convert the 'char' string into a 'FMX_Unichar' string.  Assumes NULL byte terminated string passed.
	long i = 0;
	
	while ( (i < (maxLength-2)) && (S[i] != 0) )
	{
		R[i] = (FMX_Unichar)S[i];
		i++;
	}
	R[i] = 0x0000;	// terminate with a NULL
	
}


void IDMA_GetString(unsigned long whichString, FMX_ULong /* winLangID */, FMX_Long resultsize, FMX_Unichar* string)
{  // takes the requested 'whichString' and returns the appropriate response, converted to a UniChar with a NULL termination.
	switch (whichString)
	{
		case kFMXT_OptionsStr:			copyCharToUnichar(IDMA_Plugin_OptionString, resultsize, string);    break;    // the "IDMA1nnYYnn";  string
		case kFMXT_NameStr:			copyCharToUnichar(IDMA_Plugin_Name, resultsize, string);    break;    // the plugin name.  eg.  IDMA Plugin
		case kFMXT_AppConfigStr:		copyCharToUnichar(IDMA_Plugin_Description, resultsize, string);    break;    // the plugin description.  eg.  This plugin...

		default:						copyCharToUnichar("Error : Unknown Request" , resultsize, string);
	}// switch (whichString)

} // IDMA_GetString (FMX_Unichar* version)


  • 2nd - Modify the FMExternCallProc(FMX_ExternCallPtr pb) function.
		case kFMXT_GetString:
		{
			IDMA_GetString(gFMX_ExternCallPtr->parm1, gFMX_ExternCallPtr->parm2, gFMX_ExternCallPtr->parm3, reinterpret_cast<FMX_Unichar*>(gFMX_ExternCallPtr->result));
		}
		break;