TweetFollow Us on Twitter

REALbasic Plug-in Development

Volume Number: 18 (2002)
Issue Number: 07
Column Tag: Getting Started

by Erick J. Tejkowski

REALbasic Plug-in Development

Plugging Made Easy

Introduction

Back in late 1999, we first discussed REALbasic plug-ins in MacTech. Since then, much has changed. REAL Software has released several improvements to the REALbasic plug-in SDK, countless developers have created plug-ins, and lots more plug-in code is out there for you to explore. Because so much has changed, we revisit the topic of REALbasic plug-in development this month. As we did nearly three years ago, we will examine the process of creating plug-ins for REALbasic. We will start with a brief description of the plug-in SDK features. Then, we will prepare the compiler for REALbasic plug-ins. Finally, we will code some plug-in examples so you can see how it all works. In the process, we will discuss what has changed in the SDK during the past three years. If you are completely new to REALbasic plug-in programming, this article should give you a good start on learning the skill.

Plug-in Fundamentals

When we last looked at the REALbasic plug-in SDK in 1999, plug-ins could be compatible either 68K or PPC Macintosh applications. Since then, REAL Software added Microsoft Windows and Macintosh Carbon targets to the list of REALbasic’s abilities. Starting with REALbasic 4, they also removed support for the 68K target. This means that the current REALbasic plug-in SDK supports the creation of PPC, Carbon, and Win32 plug-ins. Each plug-in can contain any combination of these targets, but it must always be compatible with the platform where you are using REALbasic. For example, if you plan to use the plug-in with a Classic version of REALbasic, your plug-in must have a PPC-compatible version for it to work. Likewise, the Carbon version of REALbasic requires a Carbon-compatible version of the plug-in.

A REALbasic plug-in consists of one or more code resources. The following list shows each possible target platform and its corresponding resource name:

  • Carbon – ‘PLCN’
  • PowerPC (PPC) – ‘PLPC’
  • Win32 – ‘PL86’

Plug-in resources start at resource ID #128 and increment from there on. However, you will seldom or never have more than one resource for each target. Thus, most plug-ins that you build will have one resource (#128) for each target (i.e. ‘PLPC’, ‘PLCN’, and ‘PL86’).

The current REALbasic plug-in SDK gives you the ability to create the following items:

  • Classes
  • Class Extensions
  • Controls
  • Functions
  • Database Engines

In this article, we will look at how to implement each of these, except database engines.

Before you embark upon any REALbasic plug-in development, you should first visit REAL Software’s web site and pick up a copy of the latest plug-in SDK. The SDK URL appears at the end of this article in the Bibliography section.

Prepare the Compiler

To begin creating REALbasic plug-ins, you will need a compiler. The tool of choice here is Metrowerk’s CodeWarrior. Since REALbasic plug-ins must contain PEF code resources, Apple’s Project Builder is not suitable for the task. Project Builder can only create Mach-O code.

The easiest way to build a plug-in is to use one of the example projects included with the REALbasic plug-in SDK as a base. If you prefer to start from scratch instead, create a folder in the Finder named “MacTech Plug-in”. Next, open your copy of the REALbasic plug-in SDK and copy the folders named “Glue Code” and “Includes” into the “MacTech Plug-in” folder. Then, launch CodeWarrior.

Create a new project in CodeWarrior using the Mac OS C Stationery. In the resulting New Project dialog that appears, select the Mac OS Toolbox: MacOS Toolbox PPC project stationery as shown in Figure 1.


Figure 1. Choose Mac OS Toolbox PPC Project Stationery to begin building a plug-in

Since a REALbasic plug-in is a code resource, you need to make some changes to the settings of your CodeWarrior project. From the Targets tab, control-click the target named “Classic Toolbox Debug” and select clear from the resulting popup menu. If you based your project on the Classic Toolbox stationery, the remaining target will be named “Classic Toolbox Final”.

Select Classic Toolbox Final Settings from the Edit menu. This displays the settings panels for the current target. In the Target Settings Panel, change the Target Name to “PPC Plug-in”. Next, choose the Access Paths Panel and add a path to the “Includes” folder you copied earlier. Then, select the PPC Target Panel and adjust it to look like Figure 2. Note that the Creator field has changed since we last examined plug-ins in 1999. It is now ‘RBv2’.


Figure 2. PPC Target Settings Panel

Finally, select the PPC Linker Panel and change it to match Figure 3. When you are finished, close the Settings window to return to the Project window.


Figure 3. PPC Linker Panel Settings

If you would like to create targets for Carbon or Win32, consult the REALbasic Plug-in SDK in the “Targeting New Platforms” section. The process works much the same way, but you will need to make a few tweaks specific to each platform.

Again, your best bet for starting out is to use one of the plug-in examples available in the SDK. Those examples have already made the necessary project settings for each platform. Simply copy the folder that contains one of these projects, and rename it to your liking. Once opened, you may want to alter the “Filename” setting in the PPC or X86 Target Panels for each target. You may also need to change the Access Paths Panel to match your directory structure. Other than that, a pre-made plug-in is ready to go and can greatly simplify your life. Use them whenever possible!

Global Methods

By this point, you should have a plug-in project shell that needs some code. As mentioned earlier, we will look at implementing global functions, classes, class extensions, and controls. The plug-in will focus on QuickTime. QuickTime has a large set of functions that are compatible for PPC, Carbon, and Win32. This simplifies matters, because you can often use the same code for multiple targets; even decidedly “Mac-looking” code works with Win32. It is also handy for REALbasic users, because REALbasic does not have some of these QuickTime features.

The simplest construct you can create in a REALbasic plug-in is a global method. Simply create a function as you normally would. For example, Listing 1 shows how to toggle the HighQuality setting of a REALmovie.

Listing 1: Toggle the HighQuality Setting of a REALmovie

SetMoviePlayHintsFunc

static void SetMoviePlayHintsFunc( REALmovie theMovie, Boolean theState)
{
	QT::Movie aMovie;
	
	//get the QT movie from the REALmovie struct
	aMovie = REALgetMovieMovie( theMovie );
	
	//if we have a movie, set it's highQuality on/off
	if (aMovie)
	{
		if (theState)
			SetMoviePlayHints
				(aMovie, hintsHighQuality, hintsHighQuality);
		else
			SetMoviePlayHints(aMovie, 0, hintsHighQuality);
	}

}

Note the REALmovie parameter in the SetMoviePlayHintsFunc function. A REALbasic user will want to pass a REALbasic movie to this function. We must then convert it to a QuickTime movie for use with standard QuickTime API calls. REALgetMovieMovie does this job for us. REALgetMovieMovie is a function provided by the REALbasic Plug-in SDK. The documentation for the Plug-in SDK lists all of the functions that are available to plug-in developers. The bulk of the SDK functions help you to convert back and forth between REALbasic and C/C++ data types and structures.

To let your plug-in know about this function, you must define it using code like that shown in Listing 2.

Listing 2: Define a Global Function

SetMoviePlayHintsMethod 
REALmethodDefinition SetMoviePlayHintsMethod = 
	{ (REALproc) SetMoviePlayHintsFunc, REALnoImplementation, "SetMoviePlayHints(theMovie as Movie, state as Boolean)" };

SetMoviePlayHintsMethod is the name of the REALmethod within the plug-in code. When you call from REALbasic, the SetMoviePlayHintsFunc function in turn is called. The last part of the REALmethodDefinition shows how the call appears to REALbasic users. Choose your phony parameter names carefully here, because they are what appear in the Tips window of REALbasic. Figure 4 shows what the Tips Window looks like when invoked for the SetMoviePlayHints method.


Figure 4. The Tips Window displays a function’s parameter names, but no data types.

The final step in adding a global function to a REALbasic plug-in is to register it. Every REALbasic plug-in has a PluginEntry function. It is here that you register the plug-in’s methods, classes, extensions, and controls. Listing 3 shows how to register the SetMoviePlayHintsMethod via a PluginEntry function.

Listing 3: The PluginEntry Function

The PluginEntry function is the entry point of a plug-in. Here you register the various items (classes, controls, methods, etc..) that you want included in the plug-in. 

void PluginEntry(void)
{
	REALRegisterMethod(&SetMoviePlayHintsMethod);
}

Class Extensions

Global methods are useful and easy to implement, but soon you will discover that they do not fill all of your REALbasic plug-in needs. Suppose, for example, that you wished to add some properties or methods to an existing REALbasic class. The REALbasic Plug-in SDK gives you the means to accomplish a task like this via a Class Extension.

To illustrate Class Extensions, we will add a new property to the MoviePlayer control to permit users to play every frame of a QuickTime movie. The properties are defined in Listing 4.

Listing 4: Define a Class Extension Property

MoviePlayerProperties
REALproperty MoviePlayerProperties[] = {
{ nil, "PlayEveryFrame", "Boolean", 0, (REALproc) GetPlayEveryFrame, (REALproc) SetPlayEveryFrame },
};

This defines a new Boolean property of the MoviePlayer called PlayEveryFrame. The “getter” function for the property is GetPlayEveryFrame, while its “setter” is SetPlayEveryFrame. Listing 5 shows the definition of the setter and getter functions for this new property.

Listing 5: MoviePlayer Class Extension Properties

GetPlayEveryFrame and SetPlayEveryFrame

Set and get the value of Class Extension’s Property with these two functions. 

static Boolean GetPlayEveryFrame(REALmoviePlayer instance, long param)
{
	Boolean everyFrame = false;
	MovieController thePlayer;
	
	thePlayer = REALgetMoviePlayerController(instance);
	MCDoAction
		(thePlayer, mcActionGetPlayEveryFrame, &everyFrame);
	
	return (everyFrame);
		
}

static void SetPlayEveryFrame(REALmoviePlayer instance, long param, Boolean state)
{
	
	MovieController thePlayer;
	
	thePlayer = REALgetMoviePlayerController(instance);
	if (state)
		MCDoAction
			(thePlayer, mcActionSetPlayEveryFrame, (QT::Ptr)true);
	else
		MCDoAction
			(thePlayer, mcActionSetPlayEveryFrame, (QT::Ptr)false);
	
}

Setter and getter functions for properties look like most C functions, but they have a few unique aspects that distinguish them from, say, a global method. First off, getter and setter functions for properties have two requisite parameters. In this example, they are:

REALmoviePlayer instance, long param

The first parameter is the class to which the control belongs. The second parameter (a long) is an extra variable for passing information around the plug-in. We do not use it in this example, but it is required in the function’s definition and prototype. The setter function has an additional parameter, which corresponds to the data type of the REALbasic property being added via the Class Extension.

With the properties declared and the setter/getter functions in place, the next step is to place them into a Class Extension Definition. Listing 6 illustrates the MoviePlayer Class Extension definition.

Listing 6: Defining a Class Extension

MoviePlayerExtension 
REALclassDefinition MoviePlayerExtension = {
	kCurrentREALControlVersion,
	"MoviePlayer",
	nil,
	0,
	0,
	nil,
	nil,
	MoviePlayerProperties,
	sizeof(MoviePlayerProperties) / sizeof(REALproperty),
};
 

A Class Extension uses a reference to a REALclassDefinition structure. The fields of this structure are shown in Listing 7. Each field is optional, but you need to include all fields up to and including the last one you want to use. In our Class Extension, we chose to stop after defining the MoviePlayerProperties, since we do not need any field beyond that.

Listing 7: REALclassDefinition Fields

	1. version the version of the plug-in architecture that the control was built under; 
		just pass the constant kCurrentREALControlVersion
	2. name: the name of the class as used in REALbasic 
	3. superName: the name of the class's superclass; 
		must be a built-in class or a plug-in class registered prior to this one 
    4. dataSize: the size of the custom data structure allocated for each object. 
		NOTE: this data structure must be the same size on all platforms 
		(use padding if necessary)! 
    5. forSystemUse: reserved (set to zero) 
    6. constructor: function to call to initialize your custom data 
    7. destructor: function to call to destroy your custom data 
    8. properties: a reference to the array of property declarations for the class 
    9. propertyCount: the number of properties for the class 
   10. methods: a reference to the array of method declarations for the class 
   11. methodCount: the number of method declarations for the class 
   12. events: a reference to the array of event declarations for the class 
   13. eventCount: the number of event declarations for the class 
   14. eventInstances: a reference to an array of event handlers for the class 
   15. eventInstanceCount: the number of event handlers there are 
   16. interfaces: a comma-delimited string of names of the interfaces 
		supported by this control 
   17. bindDescriptions: a reference to an array of binding descriptions for this control 
   18. bindDescriptionCount: the number of binding descriptions there are

Finally, register the Class Extension as you did with the global method earlier.

PluginEntry v2 
void PluginEntry(void)
{
	REALRegisterMethod(&SetMoviePlayHintsMethod);
	REALRegisterClassExtension(&MoviePlayerExtension);
}

Controls

Class Extensions are limited creatures. Since Class Extensions extend existing structures, you are not permitted to add custom data to them . Classes and Controls, on the other hand, are defined by you, so you can add as much custom data to them as desired. Since Classes and Controls are so closely related, we will limit our discussion to Controls. Any pointers you pick up about Controls will usually carry over to Classes.

To demonstrate how to create a REALbasic Control, we will build a simple viewer for displaying the various images one might fine in a multiple image file. QuickTime supports a few image file formats that allow multiple images in one file. Some of the more popular ones include Photoshop (.psd) and multi-page TIFF (.tif).

The first step is to create a data structure that will store the image being displayed by the control.

MultiImageData 
struct MultiImageData
{
	REALpicture 	theImage;
};

To make sure that the Control redraws correctly, we need to define a Behavior for the Control. The REALbasic Plug-in SDK lists all of the possible behaviors you might include, but we will only concern ourselves with one: redrawFunction, the third field in a Behavior structure. Simply name the function you will use to redraw the Control in the third field when defining the Control’s Behaviors.

MultiImageBehaviour
REALcontrolBehaviour MultiImageBehaviour = {
	nil,			 					// init the control
	nil,								// dispose
	MultiImageDraw	 		// redraw the control
};

Keep in mind that the MultiImageDraw function is responsible for drawing the Control while the REALbasic application runs as well as when it is displayed in a window in the IDE. In the IDE, we will fill in the Control with a blue color. During runtime, we will draw an image (if we have one loaded).

MultiImageDraw
static void MultiImageDraw(REALcontrolInstance instance)
{
	
	QT::Rect myRect;
	short myWidth,myHeight;
	RGBColor fillCol = {0,0,0};
		
	// get a reference to the control's data structure
	ControlData
		(MultiImageControl, instance, MultiImageData, data);
	
	// how big is the control?
	REALGetControlBounds(instance, &myRect);
	 		
	// if we are in the IDE, simply draw 
	// a blue box
	if (!REALinRuntime())
	{
		//fill in the control with blue 
		fillCol.red = 0;
		fillCol.green = 0;
		fillCol.blue = 65535;
		RGBForeColor(&fillCol);
		PaintRect(&myRect);
	}		
	else
	{
		//draw an image, if we are in the Runtime
		myWidth = myRect.right - myRect.left;
		myHeight = myRect.bottom - myRect.top;
		 		
		if (data->theImage)
		{
			REALDrawPicturePrimitive(data->theImage, &myRect, 0);
		}
	}
}

The Control will have two methods to tell us how many images are in a file and to draw a specific image in the Control. Define them as shown in Listing 8:

Listing 8: MultiImageControl Methods

MultiImageMethods, LoadImage, and ImageCountfunc
REALmethodDefinition MultiImageMethods[] = {
	{ (REALproc) LoadImage, REALnoImplementation, "LoadImageFile(FolderItem as FolderItem, pgNum as integer)"},
	{ (REALproc) ImageCountfunc, REALnoImplementation, "ImageCount(FolderItem as FolderItem) as integer" },
};

static void LoadImage
	(REALcontrolInstance instance, 
	REALfolderItem myRF, long pgNum)
{
	//get a reference to the control's data structure
	ControlData
		(MultiImageControl, instance, MultiImageData, data);
	
	int imgCount;
	imgCount = ImageCountfunc(instance, myRF);
	if ( imgCount > 0)
	{
		//get an image based on 1-based index 
		data->theImage = GetImageByIndexfunc(myRF, pgNum);

		//refresh the control's iamge
		MultiImageDraw(instance);

	}
	else
	{
		data->theImage = nil;
	}	
}


static int ImageCountfunc(REALcontrolInstance instance, REALfolderItem myRF)
	{
	//returns image count of a file 
		
		ComponentInstance 	gImporter;
		unsigned long			myCount;
		OSErr							myErr = QT::noErr;
		FSSpec							myFSpec;
	
		myCount = 0;
		ControlData
			(MultiImageControl, instance, MultiImageData, data);
		
		if (!REALFSSpecFromFolderItem(&myFSpec, myRF))
			return;

		myErr = GetGraphicsImporterForFile(&myFSpec, &gImporter);
		if (myErr != QT::noErr) return (myErr);
		myErr = GraphicsImportGetImageCount 
										(gImporter, &myCount);
		if (myErr != QT::noErr) return (32);
		
		if (gImporter != NULL)
			CloseComponent(gImporter);
		return myCount;
		
	}

You might have noticed that these Control functions have a parameter much like the Properties of the Class Extension presented earlier. This is required and gives you access to the instance of the control. This in turn permits you to access the Control’s data structure.

Next, define the control. Again, consult the SDK to see all the possible fields in the REALcontrol structure.

MultiImageControl
REALcontrol MultiImageControl = {
	kCurrentREALControlVersion,
	"MultiImageViewer",              // name of control
	sizeof(MultiImageData),
	0,	// for invisible controls, use: REALinvisibleControl
	128,				// PICT resource for toolbar 
	129,				// PICT resource for toolbar (depressed)
	320, 240,	// the default size of the control 
	nil,				// no properties this time...
	0,					// sizeof(properties)
	MultiImageMethods,	// the methods
	sizeof(MultiImageMethods) / sizeof(REALmethodDefinition),
	nil,				// the events
	0,					// sizeof(events)
	&MultiImageBehaviour
};

Finally, register the Control in the PluginEntry.

REALRegisterControl(&MultiImageControl);

The complete plug-in code is shown in Listing 9.

Listing 9: MacTechPlugin.cpp

// MacTechPlugin.cpp
// Demonstrates a simple REALbasic plug-in 
//
// Targets: Classic, Carbon
//
// REALbasic version used in demo: 4.0.2 
//
// CodeWarrior version used in demo: 6 - 
// Version 7 should also work without any project changes


#include "MacTechPlugin.h"


//**********************
//      GLOBAL METHOD
//**********************

static void SetMoviePlayHintsFunc
			( REALmovie theMovie, Boolean theState )
{
	QT::Movie aMovie;
	
	//get the QT movie from the REALmovie struct
	aMovie = REALgetMovieMovie( theMovie );
	
	//if we have a movie, set it's highQuality on/off
	if (aMovie)
	{
		if (theState)
			SetMoviePlayHints
				(aMovie, hintsHighQuality, hintsHighQuality);
		else
			SetMoviePlayHints(aMovie, 0, hintsHighQuality);
	}

}

//********************************************
//      CLASS EXTENSION - MoviePlayer
//********************************************

REALproperty MoviePlayerProperties[] = {
	{ nil, "PlayEveryFrame", "Boolean", 0, (REALproc) GetPlayEveryFrame, (REALproc) SetPlayEveryFrame },
};

static Boolean GetPlayEveryFrame(REALmoviePlayer instance, long param)
{
	Boolean everyFrame = false;
	MovieController thePlayer;
	
	thePlayer = REALgetMoviePlayerController(instance);
	MCDoAction
		(thePlayer, mcActionGetPlayEveryFrame, &everyFrame);
	
	return (everyFrame);
		
}

static void SetPlayEveryFrame(REALmoviePlayer instance, long param, Boolean state)
{
	
	MovieController thePlayer;
	
	thePlayer = REALgetMoviePlayerController(instance);
	if (state)
		MCDoAction
			(thePlayer, mcActionSetPlayEveryFrame, (QT::Ptr)true);
	else
		MCDoAction
			(thePlayer, mcActionSetPlayEveryFrame, (QT::Ptr)false);
	
}



//********************************************
//		CONTROL  - 	MultiImage viewer 
//		- for image files that might 
//		hold more than one image 
//		(.psd, .tif, etc...)
//********************************************

extern struct REALcontrol MultiImageControl;


struct MultiImageData
{
	REALpicture 	theImage;
};


static void MultiImageDraw(REALcontrolInstance instance)
{
	
	QT::Rect myRect;
	
	short myWidth,myHeight;
	RGBColor fillCol = {0,0,0};
		
	// get a reference to the control's data structure
	ControlData
		(MultiImageControl, instance, MultiImageData, data);
	
	// how big is the control?
	REALGetControlBounds(instance, &myRect);
	 		
	// if we are in the IDE, simply draw 
	// a blue box
	if (!REALinRuntime())
	{

		//fill in the control with blue 
		fillCol.red = 0;
		fillCol.green = 0;
		fillCol.blue = 65535;
		RGBForeColor(&fillCol);
		PaintRect(&myRect);

	}		
	else
	{
		//draw an image, if we are in the Runtime
		myWidth = myRect.right - myRect.left;
		myHeight = myRect.bottom - myRect.top;
		 		
		if (data->theImage)
		{
			REALDrawPicturePrimitive(data->theImage, &myRect, 0);
		}
	}
}

static void LoadImage(REALcontrolInstance instance, REALfolderItem myRF, long pgNum)
{
	//get a reference to the control's data structure
	ControlData
			(MultiImageControl, instance, MultiImageData, data);
	
	int imgCount;
	imgCount = ImageCountfunc(instance, myRF);
	if ( imgCount > 0)
	{
		//get an image based on 1-based index 
		data->theImage = GetImageByIndexfunc(myRF, pgNum);

		//refresh the control's iamge
		MultiImageDraw(instance);

	}
	else
	{
		data->theImage = nil;
	}	
}


//returns image count of a file 
static int ImageCountfunc(REALcontrolInstance instance, REALfolderItem myRF)
	{
		
		ComponentInstance 	gImporter;
		unsigned long				myCount;
		OSErr							myErr = QT::noErr;
		FSSpec							myFSpec;
	
		myCount = 0;

		ControlData
			(MultiImageControl, instance, MultiImageData, data);
		
		if (!REALFSSpecFromFolderItem(&myFSpec, myRF))
			return;

		myErr = GetGraphicsImporterForFile(&myFSpec, &gImporter);
		if (myErr != QT::noErr) return (myErr);
		myErr = GraphicsImportGetImageCount 
										(gImporter, &myCount);
		if (myErr != QT::noErr) return (32);
		
		if (gImporter != NULL)
			CloseComponent(gImporter);
		return myCount;
		
	}


//load an image into the control using 1-based index
static REALpicture GetImageByIndexfunc(REALfolderItem myRF, int indx)
	{
		
		ComponentInstance 	gImporter;
		QT::Rect						myRect;
		unsigned long				myCount, myIndex;
		OSErr							myErr = QT::noErr;
		OSErr							err = QT::noErr;
		FSSpec							myFSpec;
	
	if (!REALFSSpecFromFolderItem(&myFSpec, myRF))
		return;

		myErr = GetGraphicsImporterForFile(&myFSpec, &gImporter);
		if (myErr != QT::noErr) return (REALpicture)NULL;
		myErr = GraphicsImportGetImageCount 
												(gImporter, &myCount);
		if (myErr != QT::noErr) return (REALpicture)NULL;
		
		//loop through all of the layers
		//and look for the one we want
		//(i.e. indx)
		for (myIndex = 1; myIndex <= myCount; myIndex++) 
		{
			if (myIndex == indx)
			{
				myErr = GraphicsImportSetImageIndex
												(gImporter, myIndex);
				if (myErr!=QT::noErr) goto bail;
				GraphicsImportGetNaturalBounds(gImporter, &myRect);
				
				//Do the GWorld stuff
				GWorldPtr world;
				myErr = NewGWorld
									( &world, 8, &myRect, NULL, NULL, 0);
				if (err != QT::noErr) return (REALpicture)NULL;
				
				//set port and draw
				GraphicsImportSetGWorld 
									(gImporter, (CGrafPtr)world, NULL);
				GraphicsImportDraw(gImporter);
				
				if (gImporter != NULL)
					CloseComponent(gImporter);

				return (REALBuildPictureFromGWorld(world, true));
				
			}
			
		}
		
		bail:
		if (gImporter != NULL)
			CloseComponent(gImporter);
		return (REALpicture)NULL;
	}
	

REALclassDefinition MoviePlayerExtension = {
	kCurrentREALControlVersion,
	"MoviePlayer",
	nil,
	0,
	0,
	nil,
	nil,
	MoviePlayerProperties,
	sizeof(MoviePlayerProperties) / sizeof(REALproperty),
	nil,
	0,
	nil,
	0,
};

REALmethodDefinition MultiImageMethods[] = {
	{ (REALproc) LoadImage, REALnoImplementation, "LoadImageFile(FolderItem as FolderItem, pgNum as integer)" },
	{ (REALproc) ImageCountfunc, REALnoImplementation, "ImageCount(FolderItem as FolderItem) as integer" },
};


REALcontrolBehaviour MultiImageBehaviour = {
	nil,			 				// init the control
	nil,							// dispose
	MultiImageDraw	 	// redraw the control
};


REALcontrol MultiImageControl = {
	kCurrentREALControlVersion,
	"MultiImageViewer",        // name of control
	sizeof(MultiImageData),
	0,						
	128,				// PICT resource for toolbar 
	129,				// PICT resource for toolbar (depressed)
	320, 240,			// the default size of the control	nil,		
						// no properties this time...
	0,					// sizeof(properties)
	MultiImageMethods,	// the methods
	sizeof(MultiImageMethods) / sizeof(REALmethodDefinition),
	nil,				// the events
	0,					// sizeof(events)
	&MultiImageBehaviour
};


REALmethodDefinition SetMoviePlayHintsMethod = 
	{ (REALproc) SetMoviePlayHintsFunc, REALnoImplementation, "SetMoviePlayHints(theMovie as Movie, state as Boolean)" };


#pragma mark -
void PluginEntry(void)
{
	
	REALRegisterMethod(&SetMoviePlayHintsMethod);
	REALRegisterClassExtension(&MoviePlayerExtension);
	REALRegisterControl(&MultiImageControl);
	
}

Conclusion

This time we looked at how to build a REALbasic plug-in consisting of a global method, a Class Extension, and a Control. Although we only scratched the surface of plug-in possibilities, this at least gives you a good start for beginning plug-in development. Check the various resources listed in the bibliography if you need more help and above all, happy plugging!

Bibliography

The Internet provides the bulk of information about REALbasic plug-in development. Start at REAL Software’s site and download the latest SDK. Then, sign up for the REALbasic plug-in list. Many talented plug-in programmers frequent the lists and often provide valuable assistance.

REALsoftware
http://www.realsoftware.com
The mother ship... visit here often.

REALbasic Plug-in SDK
http://webster.realsoftware.com/download/release.html
Required visiting! The SDK provides all the files you need to get started programming REALbasic plug-ins.

REALbasic Plug-ins List
http://webster.realsoftware.com/support/internet.html
Need help? Join the REALbasic Plug-ins list and ask away!

Thomas Tempelmann
http://www.tempel.org/rb/index.html
Here you’ll find many great REALbasic plug-in code examples.

REALbasic Plugin Programming
Erick Tejkowski
http://www.mactech.com/articles/mactech/Vol.15/15.10/REALbasicPlugin/index.html
The original MacTech REALbasic plug-in article from 1999.

Erick Tejkowski is the author of REALbasic for Dummies. You can reach him at etejkowski@mac.com.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Adobe Creative Cloud 2.2.0.129 - Access...
Adobe Creative Cloud costs $49.99/month (or less if you're a previous Creative Suite customer). Creative Suite 6 is still available for purchase (without a monthly plan) if you prefer. Introducing... Read more
Tower 2.2.3 - Version control with Git m...
Tower is a powerful Git client for OS X that makes using Git easy and more efficient. Users benefit from its elegant and comprehensive interface and a feature set that lets them enjoy the full power... Read more
Apple Java 2015-001 - For OS X 10.7, 10....
Apple Java for OS X 2015-001 installs the legacy Java 6 runtime for OS X 10.11 El Capitan, OS X 10.10 Yosemite, OS X 10.9 Mavericks, OS X 10.8 Mountain Lion, and OS X 10.7 Lion. This package is... Read more
Adobe Muse CC 2015 2015.0.1 - Design and...
Muse CC 2015 is available as part of Adobe Creative Cloud for as little as $14.99/month (or $9.99/month if you're a previous Muse customer). Muse CS6 is still available for purchase (without a... Read more
Adobe Illustrator CC 2015 19.1.0 - Profe...
Illustrator CC 2015 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Illustrator customer). Illustrator CS6 is still available for... Read more
Corel Painter 14.1.0.1105 - Digital art...
Corel Painter helps you create astonishing art in a variety of media. Paint with vivid oil paints, fluid water colors, and earthy charcoals. Corel Painter flawlessly recreates the tones and textures... Read more
Pacifist 3.5.4 - Install individual file...
Pacifist opens up .pkg installer packages, .dmg disk images, .zip, .tar. tar.gz, .tar.bz2, .pax, and .xar archives and more, and lets you extract or install individual files out of them. This is... Read more
Merlin Project 3.1.0.40305 - Project man...
Merlin Project is for those of you who are responsible for complex projects. Simple lists of tasks won't suffice. Good planning raises questions about the dependencies of activities on each other,... Read more
DM1 2.0 - Advanced drum machine. (Commer...
DM1 is an advanced Drum Machine. It turns your computer into a fun and creative beat making machine. Easy and fast to use, loaded with 86 superb electronic drum kits and beautiful hyper-realistic... Read more
Posterino 3.2.1 - Create posters, collag...
Posterino offers enhanced customization and flexibility including a variety of new, stylish templates featuring grids of identical or odd-sized image boxes. You can customize the size and shape of... Read more

Mazes of Karradash (Games)
Mazes of Karradash 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: The city of Karradash is under attack: the monsters of the Shadow Realms are emerging from the depths.No adventurer is... | Read more »
Battle Golf is the Newest Game from the...
Wrassling was a pretty weird - and equally great - little wressling game. Now the developers, Folmer Kelly and Colin Lane, have turned their attention to a different sport: golfing. This is gonna be weird. [Read more] | Read more »
Qbert Rebooted has the App Store Going...
The weird little orange... whatever... is back, mostly thanks to that movie which shall remain nameless (you know the one). But anyway it's been "rebooted" and now you can play the fancy-looking Qbert Rebooted on iOS devices. [Read more] | Read more »
Giant Monsters Run Amok in The Sandbox...
So The Sandbox has just hit version number 1.99987 (seriously), and it's added a lot more stuff. Just like every other update, really. [Read more] | Read more »
Fish Pond Park (Games)
Fish Pond Park 1.0.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.0 (iTunes) Description: Nurture an idyllic slice of tourist's heaven into the top nature spot of the nation, furnishing it with a variety of... | Read more »
Look after Baby Buddy on your Apple Watc...
Parigami Gold is the new premium version of the match three puzzler that includes Apple Watch support and all new content. You won't simply be sliding tiles around on your wrist, the Apple Watch companion app is an all new mini-game in itself. You'... | Read more »
Swallow all of your opponents as the big...
Eat all of the opposition and become the largest ball in Battle of Balls now available in the App Store and Google Play. Battle of Balls pits you against other opponents in real time and challenges you to eat more balls and grow larger than all of... | Read more »
PAC-MAN Championship Edition DX (Games)
PAC-MAN Championship Edition DX 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: It’s Your World. EAT IT! Get ready for more ghost chain gobbling and frantic action in PAC-MAN® CE-DX! The... | Read more »
incurve (Games)
incurve 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: Get ready for 2 different gravities Goal is to hit as many white dots on your way up.When you're touching the screen, the dots have a... | Read more »
Crossy Road has its Own Merch Store Now....
Do you like Crossy Road? I mean do you really like Crossy Road? Well then you're in luck! Hipster Whale has opened up a Crossy Road store, so you can show off your fandom via official T-shirts. [Read more] | Read more »

Price Scanner via MacPrices.net

Apple restocks refurbished Mac minis for up t...
The Apple Store has restocked Apple Certified Refurbished 2014 Mac minis, with models available starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: - 1.4GHz... Read more
13-inch 2.5GHz MacBook Pro on sale for $899,...
Best Buy has the 13″ 2.5GHz MacBook Pro available for $899.99 on their online store. Choose free shipping or free instant local store pickup (if available). Their price is $200 off MSRP. Price is... Read more
21-inch 2.9GHz iMac on sale for $1299, save $...
Best Buy has the 21″ 2.9GHz iMac on sale today for $1299.99 on their online store. Choose free shipping or free local store pickup (if available). Their price is $200 off MSRP, and it’s the lowest... Read more
Free Image Sizer 1.3 for iOS Offers Photo Edi...
Xi’An, China based G-Power has announced the release of Image Sizer 1.3 for the iPhone, iPad, and iPod touch, an important update to their free photo editing app. Image Sizer’s collection of easy to... Read more
Sale! 13″ 1.6GHz/128GB MacBook Air for $899,...
B&H Photo has the 13″ 1.6GHz/128GB MacBook Air on sale for $899 including free shipping plus NY tax only. Their price is $100 off MSRP, and it’s the lowest price available for this model. Read more
13-inch Retina MacBook Pros on sale for $100...
Best Buy has 13-inch Retina MacBook Pros on sale for $100 off MSRP on their online store. Choose free shipping or free local store pickup (if available). Prices are for online orders only, in-store... Read more
Will BMW’s i3 Electric Vehicle Be The Automo...
The German-language business journal Manager Magazin’s Michael Freitag reports that Apple and the German performance/luxury automaker Bayerishe Motoren Werke (BMW) are back at far-reaching... Read more
Sale! $250 off 15-inch Retina MacBook Pro, $2...
B&H Photo has lowered their price for the 15″ 2.2GHz Retina MacBook Pro to $1749, or $250 off MSRP. Shipping is free, and B&H charges NY sales tax only. They have the 27″ 3.3GHz 5K iMac on... Read more
Global Smartphone Market Posts 11.6% Year-Ove...
According to the latest preliminary data released from the International Data Corporation (IDC) Worldwide Quarterly Mobile Phone Tracker, smartphone vendors shipped a total of 337.2 million units... Read more
15-inch and 13-inch Retina MacBook Pros on sa...
B&H Photo has 15″ & 13″ Retina MacBook Pros on sale for up to $180 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.2GHz Retina MacBook Pro: $1819 save $180 - 15″ 2.... Read more

Jobs Board

*Apple* Customer Experience (ACE) Leader - A...
…management to deliver on business objectives Training partner store staff on Apple products, services, and merchandising guidelines Coaching partner store staff on Read more
Project Manager - *Apple* Pay Security - Ap...
**Job Summary** The Apple Pay Security team is seeking a highly organized, results-driven Project Manager to drive the development of Apple Pay Security. If you are Read more
*Apple* TV Product Design Internship (Spring...
…the mechanical design effort associated with creating world-class products with the Apple TV PD Group. Responsibilities will include working closely with manufacturing, Read more
*Apple* Watch SW Application Project Manager...
**Job Summary** The Apple Watch software team is looking for an Application Engineering Project Manager to work on new projects for Apple . The successful candidate Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.