Tab Julius

Subscribe to Tab Julius: eMailAlertsEmail Alerts
Get Tab Julius: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Article

MOA Tour

Macromedia Open Architecture quirks, clues, shortcuts, and hints

In this last article (for now) of a series of articles on Xtra development using Macromedia's Open Architecture, or MOA, I thought it'd be nice to take a quick tour through some of the little quirks, clues, shortcuts, and hints I've accumulated over the years. These are in no specific order other than that I've tried to keep related items together.

Director Isn't Loading My Xtra
First, make sure it really isn't loading. Unfortunately, in Director, there is no specific menu item that will show you all the Xtras. In later versions of Director you can type "put the xtralist" (without quotes) in the message window and it will list all Xtras loaded by Director. It's not formatted for easy reading, but it is comprehensive. Other than that, where your Xtra appears depends on what kind of Xtra it is. Scripting, or Lingo Xtras, show up when you type "showxlib" in the message window. In later versions of Director you can find them in the third-party Xtras button on the message window as well.

Sprite/Asset Xtras show up under the Insert menu. Tool Xtras show up on the Xtras menu, and Transition Xtras show up in the transition list.

If you've verified that it's really not there, there are a couple of reasons why it might not show up. First, it has to be in the Xtras folder with a .X32 extension for Windows, or the proper Type/Creator on Mac with the proper resources. It's okay if it's in a subfolder under the Xtras folder, as Director searches all subfolders.

On Windows, the most common reason is failure to include the .DEF file. If you delete all the original source file references from the skeleton template and add in yours instead, it's very easy to forget to add in the .DEF file from the WINPROJ folder. No .DEF file = no loading of Xtras.

If it's not loading and Director is complaining of a "Duplicate Xtra", then you're most likely using a GUID that is already used by another Xtra. Each Xtra must have unique GUIDs, as discussed in an earlier article.

Next, it's possible that something in your registration code is preventing it from registering. Is there a check for a particular resource or version of Director? You should walk through the code and see if there are any exits that might apply.

Finally, is it statically linked to a required external .DLL that it can't find? Because if so, it won't load. A good way to test this is to, on Windows, run Microsoft's DEPENDS.EXE on the file (DEPENDS.EXE comes with Visual Studio, and checks all file dependencies, except for those loaded dynamically at runtime). You might be able to run it on the Xtra in the Xtras folder, or you may have to put the Xtra in the Director folder itself for the test, depending on where you keep your required .DLL and how you have it structured. A similar problem can occur on the Mac with weakly linked libs, although I don't know of any tool, offhand, that is a Mac equivalent of DEPENDS.EXE.

If you fixed the "problem" but it still doesn't load, it's slightly possible that Director got out of sync with the Xtra. To improve startup time, Director queries each Xtra for its registration information and caches that information; if the cache gets out of sync, it may think your Xtra is unloadable even though it really is. In that case, just delete the cache. The cache file is DIRAPI.MCH and it's safe to delete (but if you're squeamish, just rename it). Director will rebuild the file if it's missing.

Director Crashes at the Splash Screen
Director loads Xtras while the Director splash screen is being displayed. As such, a crash during the splash screen usually is due to an errant Xtra. One obvious place to check is your registration code - use the debugger to walk through it. If it seems clean, and you've got a scripting Xtra, a little-known cause of crashes is an improper message table. At least in earlier versions of Director (have not tried this in MX+), a bad entry in the message table will bring Director to a screeching halt. As an example, I believe a line like the following would do it:

"myFunction *, object me, *"

or

"myFunction * object me, *"

I ran into this a number of years ago when I had an Xtra with global commands that I was converting to an object-based model. The original declaration was something like "* myFunction*", meaning that it was global (the first asterisk) and had no restrictions on the number of parameters (the second asterisk). I went through and added "object me" to all the commands but forgot to move the asterisk. Thus it was a wildcard asterisk followed by a specific variable declaration. I do not recall at this point if there was a comma between the asterisk and the "object" keyword. Nevertheless, the net result was that Director crashed big-time; it was not in my C code as far as I could tell, yet it was obviously a result of my Xtra.

It wasn't until after a lot of searching and trying to recall exactly what I had changed that I finally realized it was a change in the message table, and even then it took a while to track it down. I mention it here because it's easy to make a typo in the message table that results in a not-so-obvious bug that can take forever to find.

The Debugger Isn't Hitting My Breakpoints
Make sure that you're actually debugging your Xtra. I like to compile directly into the Xtras folder in order to minimize any mistakes that might be caused by moving files from the debug or release folder out to somewhere else. If you work on multiple versions of Director, or if your Xtra was originally built for an older version of Director, make sure your debug settings are compiling it into the proper folder (for your current version) and not the old one.

My Xtra Loads, Except in Shockwave
In order for an Xtra to load in Shockwave, there needs to be a flag set during registration that says the Xtra is "Safe for Shockwave". In other words, you have to explicitly say that the Xtra is safe for Shockwave by default an Xtra is considered not safe for Shockwave.

In Shockwave, you have access to nearly every MOA function that you do when running from a desktop. And you certainly have full access to all of the operating system functions that you normally would. Setting the flag doesn't, in and of itself, set any limitations; it just tells Director that you swear you've taken the necessary precautions to make it safe for Director to load. Such precautions include not retrieving information or files from the user's machine, or doing any tinkering with their system, at least not without providing clear warning to the user and giving him or her the opportunity to opt out.

And remember, to load in Shockwave, the Xtra has to be in the Shockwave Xtras folder, not just the Director folder. Shockwave has its own set of folders where the Shockwave plugin is. An easy way to find it is to simply search for the file "TextXtra.x32" on your system, which will pull up both your Director folder and your Shockwave folder. On Windows, officially there's a registry entry to tell you where it is, but usually you'll find it in \Windows\System\Macromed\Shock wave 8\Xtras" (note that it says MACROMED, not MACROMEDIA (8 char limitation). On the Mac, it will usually be "/System Folder/Extensions/Macromedia/Shockwave 8/Xtras". Also remember that any external .DLLs you need will need to be there too.

Okay, on to some specific programming topics...

Director Goes Through My Function Fine, but Crashes Upon Returning
Did you try to release one of the args from the callPtr? Because that's a no-no. Director owns those args and expects to release them later on. When you use AccessArgByIndex, you're not creating an arg, you're simply accessing an existing one. As such, it's not your responsibility to release it.

How Do I Get a Pointer to a Sprite or a Cast Member?
In MOA, to get something you want, you usually have to walk the chain of command, particularly when it comes to casts, scores, and sprites. You can't just instantiate a sprite variable, you have to work your way to it.

Start with IMoaDrPlayer, an interface that it's helpful to just acquire in the beginning and keep around. With IMoaDrPlayer you can then get a pointer to the active movie (or any of the movies - you can call GetMovieCount() and GetNthMovie() to walk through the movie list, or just call GetActiveMovie() to get the one playing at the time of the call).

Then, with the movie, for which you will have a pointer to as a IMoaDrMovie2 object, you can get at the casts and the score. GetScoreAccess() will get you a pointer to the score, and you can use that IMoaDrScoreAccess pointer to get your fingers on the sprites, frames, and whatnot. Or, if you want to wander through the casts of a movie, use IMoaDrMovie2 to GetCastCount(), get a cast by name or index, and then with the casts you can get at the cast members.

Ultimately you can traverse the whole tree and get at everything loaded in the movie. You just can't go directly to castmember x of cast y of movie z, although that might be a nice feature to have.

I'm Getting Crashing Calling My Xtra from Another Thread
Xtras, through MOA, have the ability to call back into Lingo, such as through IMoaDrPlayer's CallHandler() function, which will call a handler in the active movie. This works, because Director put everything on hold while it called your Xtra, and now you're calling back into Director, a condition Director allows via MOA. This is considered a synchronous call...Director called your Xtra; you're calling back into Director; it's a straight line (or loop?).

But if you've created a separate thread that needs to call Director, or if you have a window with a callback for an external operating system function that needs to notify Director when something happens, you may run into a crash. This is because Director doesn't have an inkling that you might call it, particularly under Internet Explorer, and your call is wholly unexpected - the equivalent of stopping at a random house at a random time and ringing the doorbell and just going in, rather than having an invitation. Director might be able to accommodate you, but it might not.

If it can't, then you're looking at a potential crash. How do you get around this? By using Director's Push/Pop Xtra context. Basically it works like this - at a "normal" time, when running, when you've been called from Director (perhaps when you're going to set up your thread or your window with a callback), you ask Director for a copy of the movie context via IMoaDrMovieContext. Then, later, at the time when you need to call asynchronously into Director, you will need to assert the context, thus making it safe for your call. You do this via PushXtraContext(), and when you're done, you would then call PopXtraContext(). Failure to do so, when using threads or your own windows (on Windows), is asking for a crash. It may not happen right away, but you will find that it may die arbitrarily while calling Director if you haven't asserted the context.

My Xtras Make Windows, but the Screen Doesn't Refresh When I Move Them
If your Xtra puts up a window, and if you drag the title bar to move the window and Director leaves a trail of windows behind, well, that's because Director doesn't know that you opened a window.

Yes, seriously, you have to tell Director that you've got a window open. This is because Director has optimized its stage refresh code on the assumption that it is the only window in its process that is open. If you're going to open a window, you need to tell Director about it. This is done by wrapping it before and after with calls to IMoaMmWndWin's WinPrepareDialogBox and WinUnprepareDialogBox().

On the Mac, there's a similar issue with dialog boxes, resolved in a similar manner via IMoaMmWndMac's MacPrepareModalDialog() and MacUnprepareModalDialog().

I Want to Sell My Xtra - How Can I Protect It?
This is a much more common question than one might think. For those writing Xtras, protecting your work is important, if that's how you make (or supplement) your living.

There are commercial tools out there for limiting code use, but typically they're more for major product manufacturers (like Macromedia) rather than Joe or Jane Developer. Most commonly it's some kind of a serial number system. The Xtra won't work (or will have limited functionality) without a serial number or similar registration code.

What restrictions you put on it depends on you and what your Xtra does. For instance, many developers like to make their Xtra functional in authoring mode, but to run in a projector or Shockwave requires a serial number. This scheme is good because it allows users to try the Xtra in Director's authoring mode and get used to it and make sure it meets their needs before purchasing it. Usually they don't buy unless they're ready and return rates are very low. The drawback is the inevitable last-minute-ohmygosh-I-need-it-now-we're-shipping-tomorrow emergency order. But it's a system that works quite well, usually. It won't work so well for tool-Xtras or authoring-only Xtras.

Another scheme, if appropriate, is to have an authoring version of the Xtra and a runtime version. The runtime one can be shipped and distributed, but it can't be reused for authoring by someone else. The authoring version has the purchaser's name in big lights and is not to be redistributed. This is nice because it keeps serial numbers from being distributed in .DIR files, but runs the risk of the authoring version being accidentally distributed and it doesn't address the issue of try-before-you-buy.

Regardless of which approach you take, you can address the protection by checking for authorization either in your registration code, in your individual functions, or in your handling of the ::Call function. It is there that you can decide to allow all, some, or no functionality based on whatever criteria you want to set. A call to IMoaAppInfo::GetInfo() will get you runtime information such as the runMode (whether you're in authoring or in a projector). Note that some of the info that GetInfo supplies, such as a serial number and even a user name and organization name, aren't available at runtime (in a projector), only at authoring time.

You will then need to come up with a serial number algorithm such that (1) no two serial numbers are alike; and (2) you can verify it's a valid serial number. You will then need to write a program to generate such numbers, and one to analyze a number and determine if it's valid.

There is no recommended way to write these. Everyone tries for a technique that builds in as much protection as possible. You could simply make a unique serial number (by building on date/time and other information), or you could tie it to the user's name or company by making them enter their name along with the number for verification.

To see if a submitted number, or number and name, is valid you would submit it to a series of tests. These would be the reverse of how you generated the number. Besides just coming up with unique information, you might then want to create a checksum for the number and put it in the number somewhere. Checksums are numbers calculated off of other numbers. Your credit card number has a checksum (usually just a single check digit) that acts as a quick test as to whether or not the rest of the number is correct. For instance, in MasterCard # 5431 2345 6789 0123, the last digit "3" might be calculated from the first 15. If the first 15 ought to come up with a 7, after running through whatever the MasterCard check formula is, but the submitted number is 3, then it's an immediate indication that the number is invalid for some reason.

You can use the same approach in your serial numbers - but they can be much more complex. Registration codes with letters in them, like "F2aBgADC-33qrUz", usually decode the letters into numbers, and go from there. Also, parts of the code can be shifted around, scrambled, so ultimately it would be very hard to make a "fake" serial number that would satisfy all the conditions of unscrambling, and check digits, letter conversions, and so on.

Your Xtra would not need to contain a list of all possible serial numbers, it would merely need to have the algorithm to test a provided serial number. If a provided serial number passes all your tests, then you can consider it valid!

Final Question
Will there be more articles on Xtras development?

Maybe, but not immediately. We're going to move into some advanced Director development for a while. Look forward to some interesting articles on internationalizing your product to run in multiple languages!

Until then, enjoy!

More Stories By Tab Julius

Tab Julius has been writing software since the mid-70s, and now works for a software firm developing medical imaging applications, although he still does limited consulting on the side.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.