/*
 * Copyright 2008 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

// oophm.idl : IDL source for oophm
//

// This file will be processed by the MIDL tool to
// produce the type library (oophm.tlb) and marshalling code.

#include "olectl.h"
import "oaidl.idl";
import "ocidl.idl";
import "dispex.idl";

// This interface is something of a hack to work around the lack
// of ICanHandleException being defined by default in the dispex headers
[
	object,
	uuid(c5598e60-b307-11d1-b27d-006008c3fbfb),
	pointer_default(unique)
]
interface ICanHandleException : IUnknown
{
	HRESULT CanHandleException([in] EXCEPINFO *pExcepInfo, [in] VARIANT *pvar);
};

[
	object,
	uuid(73607C2E-369B-4055-8020-D7643A59F521),
	dual,
	nonextensible,
	helpstring("Iplugin Interface"),
	pointer_default(unique)
]
interface Iplugin : IDispatch{
	[id(1), helpstring("OOPHM connect")] HRESULT connect([in] BSTR url, [in] BSTR sessionKey, [in] BSTR hostedServer, [in] BSTR moduleName, [in] BSTR hostedHtmlVersion, [out,retval] VARIANT_BOOL* ret);
	[id(2), helpstring("method testObject")] HRESULT testObject([out,retval] IDispatch** ret);
	[id(3), helpstring("OOPHM init")] HRESULT init([in] IDispatch* jsniContext, [out,retval] VARIANT_BOOL* ret);
};

[
	object, 
	dual,
	nonextensible,
	uuid(AB9B16A0-03E9-481E-ADF5-B00B860A8C3A),
	helpstring("IpluginUI Interface"),
	pointer_default(unique)
]
interface IpluginUI : IDispatch
{
	// Example method that will be called by the HTML
	HRESULT OnClick([in]IDispatch* pdispBody, [in]VARIANT varColor);
};
[
	object,
	uuid(58276E45-1F24-4B71-88AC-2A7D0C26CDFF),
	dual,
	nonextensible,
	helpstring("IJavaObject Interface"),
	pointer_default(unique)
]
interface IJavaObject : IDispatchEx{
};
[
	object,
	uuid(1C3FBB2D-58C2-426C-A461-E6002F9EE294),
	dual,
	nonextensible,
	helpstring("IExceptionCatcher Interface"),
	pointer_default(unique)
]
interface IExceptionCatcher : IDispatch{
  [id(1), helpstring("method getException")] HRESULT getException([out,retval] VARIANT* retVal);
  [id(2), helpstring("method hasSeenException")] HRESULT hasSeenException([out,retval] BOOL* retVal);
};
[
	uuid(9259F105-BE55-4BF6-B7CE-D0AA878C1BA6),
	version(1.0),
	helpstring("oophm 1.0 Type Library")
]
library oophmLib
{
	importlib("stdole2.tlb");
	[
		uuid(1D6156B6-002B-49E7-B5CA-C138FB843B4E),
		control,
		helpstring("plugin Class")
	]
	coclass plugin
	{
		[default] interface Iplugin;
		interface IpluginUI;
	};
	[
		uuid(644FD769-8B9D-4AC4-A79E-AAAF5CD751C1),
		helpstring("JavaObject Class")
	]
	coclass JavaObject
	{
		[default] interface IJavaObject;
	};
	[
		uuid(1A2A78F4-B5A4-4208-B520-BDDA0A7EC5CB),
		helpstring("ExceptionCatcher Class")
	]
	coclass ExceptionCatcher
	{
		[default] interface IExceptionCatcher;
    interface ICanHandleException;
	};
};
