COM Programming with Microsoft .NET

Lets look at a simple implementation example. Its possible to create controls that are completely safe for scripting using Microsoft Visual Studio .NET. The only problem is that the managed version lacks the IObjectSafety interface that marks it as safe to use. Figure 14-9 shows what the unmanaged form of this interface looks like.

Figure 14-9: Youll use the IObjectSafety interface to mark components and controls as safe for scripting.

Note 

You can find the code for this example in the Chapter14\ScriptableControl folder of the books companion content. You can download the sample content from the books Web page at the URL http:// www.microsoft.com/mspress/books/6426.asp .

For the purposes of this example, just the interface is important. The fact that this interface contains only two methods and most of the variables are relatively simple makes it an easy interface to begin with. Listing 14-3 shows the implementation of this interface in managed code.

Listing 14-3: The converted form of the IObjectSafety interface

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("CB5BDC81-93C1-11cf-8F20-00805F2CD064")] publicinterfaceIObjectSafety { [PreserveSig()] UInt32GetInterfaceSafetyOptions(refGuidriid, outInt32pdwSupportedOptions, outInt32pdwEnabledOptions); [PreserveSig()] UInt32SetInterfaceSafetyOptions(refGuidriid, Int32dwOptionSetMask, Int32dwEnabledOptions); }

 

The heading for this information is much the same as the IComponent interface we discussed earlier, so this example uses the same attributes as before. Notice that the [Guid] attribute contains the correct GUID for this interface, as shown in Figure 14-9.

Reading the documentation tells you that the methods in this interface both return values. Consequently, you must use [PreserveSig()] for both methods. The possible return values for this example include

publicconstUInt32S_OK=0x00000000; publicconstUInt32E_FAIL=0x00000001; publicconstUInt32E_NOINTERFACE=0x80004002;

The E_NOINTERFACE return value isnt a failure as you might suppose. It simply indicates to the caller that the component or control hasnt implemented this method. Many callers will interpret this value as a failure, but some will also perform a default action based on the lack of support provided by the component or control. Its important to use the correct return value. Use E_FAIL only if the call actually failed.

One tricky piece of information required by this example is the riid . You need to track this value back to its origins to find that its actually a pointer to an interface identifier (IID), which is nothing more than a GUID for the purposes of this example. The example could have used a number of other types for this input, including an IntPtr . The Guid type should work in most situations.

The final arguments are simply Int32 values. However, they have special meaning in this case because the caller interprets each bit position. You could create a flag enumeration for these two entries, but it isnt necessary. The bit positions needed to signify that the control is safe for scripting are contained in the two constants shown here:

publicconstInt32INTERFACESAFE_FOR_UNTRUSTED_CALLER=0x00000001; publicconstInt32INTERFACESAFE_FOR_UNTRUSTED_DATA=0x00000002;

Its time for the decisive momentdoes the interface work? The sample control, ScriptableControl.MyButton, is extremely simple. The only purpose it serves is to demonstrate the IObjectSafety interface. Viewing this control in the OLE/COM Object Viewer will show you that it does indeed possess the IObjectSafety interface, as shown in Figure 14-10.

Figure 14-10: The sample control implements and exposes the IObjectSafety interface, which makes it possible to use the control in a scripting scenario.

 

Категории