In the system I'm working on, we have a page whose backing bean implements an API to fetch data from a database other than the system's main (user-related) one, and stores the data locally (in memory).
Part of the object that is stored is a link (and a Javascript function) that points to the secondary system's related page.
Here's my relevant code from the JSF page;
<p:dataTable id="dtDemonstrativoBoletos" value="#{bean.boletos}" rowKey="#{boleto.link}"
widgetVar="dtDemonstrativoBoletos" var="boleto"
selection="#{bean.boletoSelecionados}" rowIndexVar="#{boleto.link}">
<p:autoUpdate />
<p:column selectionMode="multiple" width="0" toggleable="false"/>
<!-- columns -->
<p:column width="24" style="padding-left:0;">
<p:link href="#{boleto.link}" target="_blank" >
<i class="fa fa-eye" style="color:darkslategrey;"/>
</p:link>
</p:column>
<p:ajax event="rowDblselect" listener="#{bean.redirecionarBoleto} update="dtDemonstrativoBoletos"/>
</p:dataTable>
Backing bean method;
public void redirecionarBoleto() throws IOException {
try {
if (!this.boletoSelecionados.isEmpty()) {
PrimeFaces.current().executeScript(this.boletoSelecionados.get(0).getLinkJs());
} else if (this.boletoSelecionado != null) {
PrimeFaces.current().executeScript(this.boletoSelecionado.getLinkJs());
}
this.getBoletoSelecionado().redirecionarJavascript();
/* the getBoletoSelecionado() method returns either the this.boletoSelecionado object
or attributes the first element in the this.boletoSelecionados list to it,
just to be clear */
this.boletoSelecionados = new ArrayList<Boleto>();
} catch (NullPointerException ex) {
} catch (Exception e) {
// TODO: handle exception
}
}
and object class.
public class Boleto {
private String situacao;
private String descricao;
private String codigoBoleto;
private String codigoEntidade;
private String link;
private String linkJs;
private Date dataVencimento;
/*getters and setters*/
public void redirecionarJavascript() {
PrimeFaces.current().executeScript(this.linkJs);
}
}
The API sets the link property as a parametrized .xhtml with the codigoBoleto and codigoEntidade values and the linkJs property with boleto.setLinkJs("window.open('" + boleto.getLink() + "')");.
Now into the issue: since the link is readily available on the DataTable, clicking on it redirects correctly to the page (as expected) within 1.12 and 1.48 seconds (going from localhost to production server), while the ajax event takes up to 50 seconds to reach the backing bean. I'm not even joking. Once it gets to the bean, it takes nil time to process the actual method (longest delay is between me seeing that it reached the breakpoint and pressing 'Skip') and the same amount of time - a second and a half - to reach the other page.
Any suggestions as to why my page straight up doesn't want to reach the code will be very warmly welcomed. Also, the linkJs property was implemented as a testing measure, to be immediately called, but the ajax can't see the boleto variable in the DataTable - I get a PropertyNotFoundException or some such. Also, I need it to work with rowDblselect due to system standardization.
Regarding the "PropertyNotFoundException" issue. It may be because the getter and setter methods are missing for that specific property or because you have not created the JSF 2.3 configuration class in the package where you have the backing bean.
import javax.enterprise.context.ApplicationScoped;
import javax.faces.annotation.FacesConfig;
import static javax.faces.annotation.FacesConfig.Version.JSF_2_3;
#FacesConfig(version=JSF_2_3)
#ApplicationScoped
public class ConfigurationJSF {
}
That is the configuration for JSF 2.3
Related
I have a problem. I have two classes in same javafx package. A single html file with javascript at the head section, a java class(extending Application). Now the problem is when i tried to click the button after the page is displayed in the javafx webview, nothing is updated in the webView. Below is the code for the two file. Please i need to know why it isn't working. i have been debugging this problem since 8hrs now, no success. thanks in advance.
java class
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class JavaFXApplication25 extends Application {
// inner class
public class Adder
{
public double add(double n, double m)
{
return n + m;
}
}
#Override
public void start(Stage primaryStage) throws URISyntaxException, MalformedURLException {
WebView w = new WebView();
WebEngine e = w.getEngine();
e.setJavaScriptEnabled(true);
e.load(this.getClass().getResource("tester.html").toURI().toURL().toExternalForm());
Scene scene = new Scene(new VBox(w));
primaryStage.setScene(scene);
primaryStage.show();
// make javascript aware of java object
e.getLoadWorker().stateProperty().addListener(
(p, o, n) ->{
if(n == Worker.State.SUCCEEDED){
JSObject b = (JSObject) e.executeScript("window");
b.setMember("adder", new Adder());
}
}
);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
The html file
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript">
function addNum(){
var n1 = Number(document.getElementById('num1').value);
var n2 = Number(document.getElementById('num2').value);
var n3 = adder.add(n1, n2);
document.getElementById('r').innerHTML = n3;
}
</script>
</head>
<body>
<input type="text" id="num1" />
<input type="text" id="num2" />
<p> <span id="r"> </span></p>
<button onclick="addNum()" >Add</button>
</body>
The point is that the programs runs and displays the page, but on pressing the button, nothing is updated on the page
I even tried to make the upcall before loading the html page, yet, no success. Please someone should help check the bug in the code. Thanks once again.
Now below is the output after been run. It shows nothing even after when the Add button is clicked several times! No error message on the standard console, nothing nothing!
output
if(n == Worker.State.SUCCEEDED){
JSObject b = (JSObject) e.executeScript("window");
b.setMember("adder", new Adder());
}
Welcome to the execrable pain in the ass that is DOM event sync between JavaFX and DOM stuff.
The worker state "SUCCEEDED" does not necessarily mean that the DOM is loaded in the page.
The DOM is loaded at document.onLoad() ... and even so it's kind of a can of worms since not all content is loaded by that time (images and stuff).
JQuery has a convenient JQuery(document).ready(function (e){ /*do whatever*/ }) routine you can use to trigger something that lets JavaFX know that it's ready to do stuff in the DOM (basically what you tried to accomplish with the code above [..]Worker.State.SUCCEEDED[..])
Essentially the sequence of events is something like:
1. JavaFX => Worker.state reaches SUCCEEDED STATE
2. DOM ====> Starts converting HTML into DOM components
3. ??? ====> This step is a complete mystery unbeknownst to even the savvy-est of skript kiddies. but i'm pretty sure this is where zuckerberg gets access to your webcam for a few frames. ... so beware!
4. DOM ====> Finishes doing its thing and fires off the onLoad() event which triggers the document.load() listener and associated function.
5. DOM ====> Officially inovkes the first JS function it comes across (not always the one you'd think it'd come across because JS is a magic programming language that doesn't give a shit about threads, or sequencing thereof, and anything goes when it comes JOs)
6. DOM+JS => Continues loading for some reason (i am not kidding)
7. DOM+JS => Some other weird flibbetlygibbletly bullshit done by the DOM and whatever javascript runs inside it ... if you're using timers... good luck.
8. DOM+JS => at this point, jQuery (if used) intercepts the .ready() event listener.
9. DOM+JS => believe me... stuff still isn't completely loaded. (because rampant JS scripts can add DOM components as they see fit and no .ready or .load event listener will ever be called.)
To add insult to injury, this sequence of events can take anywhere between 1ms and 1 minute to reach (8)... it's arbitrary as hell.
I wound up writing code which starts comparing node trees for changes in order to figure out when exactly to start messing with the DOM.... but i digress.
What you want is to make sure you initiate your JS-JavaFX communication protocol once the DOM is ready to run your custom javascript.
Put that shit in document.onLoad(), listen for it inside JavaFX, and then set the adder as you did so already... then hope for the best.
Thanks everyone...After a little research, i was able to come up with an extremely simple solution..Here it goes in steps:
declare a private field (which is an object of the class that contains the public methods to be called from javascript) in the main class.
instantiate the private field
add the member to the web engine after it loads
call the java method from the javascript.
so here goes the updated code
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class JavaFXApplication25 extends Application {
// inner class
public class Adder
{
public double add(double n, double m)
{
return n + m;
}
}
// STEP 1: Now declare the private field (COMPULSORY)
private Adder adder;
#Override
public void start(Stage primaryStage) throws URISyntaxException, MalformedURLException {
WebView w = new WebView();
WebEngine e = w.getEngine();
e.setJavaScriptEnabled(true);
e.load(this.getClass().getResource("tester.html").toURI().toURL().toExternalForm());
Scene scene = new Scene(new VBox(w));
primaryStage.setScene(scene);
primaryStage.show();
//STEP 2: instantiate the private js object from step1
adder = new Adder();
// make javascript aware of java object
e.getLoadWorker().stateProperty().addListener(
(p, o, n) ->{
if(n == Worker.State.SUCCEEDED){
JSObject b = (JSObject) e.executeScript("window");
b.setMember("adder", new Adder());
}
}
);
}
/**
#param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
The HTML code still remains the same as before.
//Now, i think there is a bug in this aspect of javafx with jdk 8 and above. I am specifically using jdk 8_126...version. It seems there is automatic destruction of the javascript handler class by the jvm. Fortunately, wrapping the js hanler as a private field in the main class seems to prevent this terrible occurrence.
I am currently working on a JavaFX based application, where users can interact with places that are marked on a world map. To do this, I am using an approach similiar to the one described in http://captaincasa.blogspot.de/2014/01/javafx-and-osm-openstreetmap.html ([1]).
However, I am facing a hard-to-debug problem related to the Javascript callback variable injected to the embedded HTML-page using the WebEngine's setMember() method (see also https://docs.oracle.com/javase/8/javafx/embedded-browser-tutorial/js-javafx.htm ([2]) for an official tutorial).
When running the program for a while, the callback variable is loosing its state unpredictably! To demonstrate this behaviour, I developed a minimal working/failing example. I am using jdk1.8.0_121 64-bit on a Windows 10 machine.
The JavaFx App looks as follows:
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javafx.application.Application;
import javafx.concurrent.Worker.State;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class WebViewJsCallbackTest extends Application {
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
public static void main(String[] args) {
launch(args);
}
public class JavaScriptBridge {
public void callback(String data) {
System.out.println("callback retrieved: " + data);
}
}
#Override
public void start(Stage primaryStage) throws Exception {
WebView webView = new WebView();
primaryStage.setScene(new Scene(new AnchorPane(webView)));
primaryStage.show();
final WebEngine webEngine = webView.getEngine();
webEngine.load(getClass().getClassLoader().getResource("page.html").toExternalForm());
webEngine.getLoadWorker().stateProperty().addListener((observableValue, oldValue, newValue) -> {
if (newValue == State.SUCCEEDED) {
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("javaApp", new JavaScriptBridge());
}
});
webEngine.setOnAlert(event -> {
System.out.println(DATE_FORMAT.format(new Date()) + " alerted: " + event.getData());
});
}
}
The HTML file "page.html" looks as follows:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<!-- use for in-browser debugging -->
<!-- <script type='text/javascript' src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script> -->
<script type="text/javascript">
var javaApp = null;
function javaCallback(data) {
try {
alert("javaApp=" + javaApp + "(type=" + typeof javaApp + "), data=" + data);
javaApp.callback(data);
} catch (e) {
alert("caugt exception: " + e);
}
}
</script>
</head>
<body>
<button onclick="javaCallback('Test')">Send data to Java</button>
<button onclick="setInterval(function(){ javaCallback('Test'); }, 1000)">Send data to Java in endless loop</button>
</body>
</html>
The state of the callback variable javaApp can be observed by clicking on the "Send data to Java in endless loop" button. It will continuously try to run the callback method via javaApp.callback, which produces some logging message in the Java app. Alerts are used as an additional communication channel to back things up (always seems to work and currently used as work-around, but that's not how things are ment to be...).
If everything is working as supposed, each time logging similiar to the following lines should be printed:
callback retrieved: Test
2017/01/27 21:26:11 alerted: javaApp=webviewtests.WebViewJsCallbackTest$JavaScriptBridge#51fac693(type=object), data=Test
However, after a while (anything from 2-7 minutes), no more callbacks are retrieved, but only loggings like the following line are printed:
2017/01/27 21:32:01 alerted: javaApp=undefined(type=object), data=Test
Printing the variable now gives 'undefined' instead of the Java instance path. A strange observation is that the state of javaApp is not truly "undefined". using typeof returnsobject, javaApp === undefined evaluates to false. This is in accordance with the fact that the callback-call does not throw an exception (otherwise, an alert starting with "caugt exception: " would be printed).
Using Java VisualVM showed that the time of failure happens to coincide with the time the Garbage Collector is activated. This can be seen by observing the Heap memory consumption, which drops from approx. 60MB to 16MB due to GC.
What's goining on there? Do you have any idea how I can further debug the issue? I could not find any related know bug...
Thanks a lot for your advice!
PS: the problem was reproduced much faster when including Javascript code to display a world map via Leaflet (cf [1]). Loading or shifting the map most of the time instantly caused the GC to do its job. While debugging this original issue, I traced the problem to the minimal example presented here.
I solved the problem by creating an instance variable bridge in Java that holds the JavaScriptBridge instance sent to Javascript via setMember(). This way, Gargbage Collection of the instance is prevented.
Relevant code snippet:
public class JavaScriptBridge {
public void callback(String data) {
System.out.println("callback retrieved: " + data);
}
}
private JavaScriptBridge bridge;
#Override
public void start(Stage primaryStage) throws Exception {
WebView webView = new WebView();
primaryStage.setScene(new Scene(new AnchorPane(webView)));
primaryStage.show();
final WebEngine webEngine = webView.getEngine();
webEngine.load(getClass().getClassLoader().getResource("page.html").toExternalForm());
bridge = new JavaScriptBridge();
webEngine.getLoadWorker().stateProperty().addListener((observableValue, oldValue, newValue) -> {
if (newValue == State.SUCCEEDED) {
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("javaApp", bridge);
}
});
webEngine.setOnAlert(event -> {
System.out.println(DATE_FORMAT.format(new Date()) + " alerted: " + event.getData());
});
}
Altough the code now works smoothly (also in conjunction with Leaflet), I am still irritated of this unexpected behaviour...
Edit: The explanation for this behaviour is documented since Java 9 (thanks #dsh for your clarifying comment! I was working with Java 8 at the time and unfortunately didn't have this information at hand...)
I am developing a WinRT application and was wondering if i could link a Hyperlink tag to a JavaScript function or be able to call the view page with NavigateUri? Or if it is possible to use interaction triggers that call the JS by a command.
==Update==
I have been testing different xaml tags from hyperlink to hyperlinkbutton. HyperlinkButton seems to appear and is clickable. it is just the on click function that doesn't seem to get called...
<HyperlinkButton Grid.Row="1" Click="__Title__.OnBuildingClick" Content="Buildingoo"/>
<HyperlinkButton Grid.Row="1" Click="__Title__.OnBuildingClick" Content="Buildingoo" ?
<i:EventTrigger EventName="ClickHyperlink">
<behaviors:EventToScriptBehavior Command="__Title__.OnBuildingClick" />
</i:EventTrigger>
</i:Interaction.Triggers>
</HyperlinkButton>
these are the 2 approaches i have taken. The functino onBuildingClick is only an alert msg but it doesnt get called..
Assuming the webView has a predefined name "currentWebView":
<WebView x:Name="currentWebView" ... />
You can access the control from the codebehind using its name, and then tell the web view to search the DOM for a javascript function by name, and invoke it if the function exists.
To invoke a method by name you will use the C# Method "InvokeScript" and pass 2 parameters:
Param 1: Name of Javascript function
Param 2: Comma Separated List of Arguments in order of Javascript Signature
currentWebView.InvokeScript("nameOfFunction", "myFirstparam, secondParam, thridParam");
Additionally, in order to allow the XAML UI to respond to the Javascript event your Javascript code must call
nameOfFunction(param1, param2, param3){
window.external.notify("This content will be accessible in the next steps NotifyEventArgs e.Value property.")
};
and in the last piece of wiring up the ability to respond to Javascript from C#, you must apply an event handler in the C# codebehind to allow the XAML to be notified what is going on inside the WebControl
// In the Constructor / OnLoaded/ OnNaviagtedTo Event of the code behind
currentWebView.ScriptNotify += new NotifyEventHandler(currentWebView_ScriptNotify);
... then later in the class
private void currentWebView_ScriptNotify(object sender, NotifyEventArgs e)
{
//can access the value included in the notification
var notification = e.Value;
someTextblock.Text = notification;
}
Putting It Together:
<HyperlinkButton x:Name="btnExecuteJavaScript" Grid.Row="1" Click="btnExecuteJavaScript_Click" Content="Buildingoo"/>
public void btnExecuteJavaScript_Click(object sender, RoutedEventArgs e)
{
currentWebView.InvokeScript("OnBuildingClick", "arbitraryParameter, mayNotBeNeeded");
}
How do I conditionally invoke JavaScript from a bean in JSF 2?
I have a class that uses PrimeFaces which uploads user files to a particular folder, but if the user attempts to upload a file with the same name as one that is already present, I want JavaScript in this case to open up a box on the screen asking the user if he wants to overwrite the old file, or cancel the operation. If no file with that name is present, then JavaScript is not called.
I know how to test that a folder has a particular file in it, it is just that I need to know how to invoke JavaScript conditionally.
I would most appreciate any advice on this.
I have looked at variopus resources online, but still cannot get the application to work correctly. basically, this is what I have done, in an included xhtml page I have the following code for the file upload:
<p:fileUpload id="fileUpload" fileUploadListener="#{filters.upload}"
allowTypes="#{filters.uploadTypes}" invalidFileMessage="#{filters.uploadBadType}"
sizeLimit="#{filters.uploadSize}" invalidSizeMessag="#{filters.uploadBadSize}"
update="fileUpload fileTable uploadMessage" description="Select Text File"
disabled="#{filters.disableFileUploadButton}"/>
<!--- Then further in the same file is this: -->
<p:remoteCommand name="remoteCommandOverwrite" actionListender="#{filters.execOverwrite}"/>
The parent xhtml page that includes the above I have the foolowing JavaScript:
<script type="text/javascript">
function popupConfirm() {
var overwrite = confirm('Warning: This will overwrite the existing file - Do you confirm this?');
if (overwrite) remoteCommandOverwrite([{name: overwrite, value: true}]);
}
</script>
In my bean I have the following code in three methods:
public void upload(FileUploadEvent event) {
FacesMessage msg = new FacesMessage("Success! ", event.getFile().getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
overwrite = false;
// Do what you want with the file
try {
copyFile(event.getFile().getFileName(), event.getFile().getInputstream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void copyFile(String fileName, InputStream in) {
// Initialization etc.
File file = new File(uploadFull + fileName);
if (file.exists()) {
RequestContext.getCurrentInstance().execute("popupConfirm()");
// Then test to see if overwrite is true or false, and act accordingly
}
// Then I am supposed to get the value of overwrite here:
public void execOverwrite() {
System.out.println("### execOverwrite() ###");
FacesContext context = FacesContext.getCurrentInstance();
Map<String, String> map = context.getExternalContext().getRequestParameterMap();
String soverwrite = (String) map.get("overwrite");
if (soverwrite.equals("true")) {
overwrite = true;
System.out.println("overwrite: true");
}
}
What I am trying to do is first to invoke conditionally the JavaScript function popupConfirm(). On clicking the "Upload" button that is invoked if the codition is true, which is what I want. This is then supposed to call
That works and brings up the confirm() box, but the is never called, so the method execOverwrite() in my bean is also never called, and I cannot pick up the return value and pass it to the code inside the method copyFile(). What is going wrong?
I put this problem on the back burner for about a week, and have just got back to it. I got it to work, and can pass a value back to the bean, but somehow I need to resume execution from the place where JavaScript is called.
To sumarize, my JavaScript contains the following code:
<script type="text/javascript">
function popupConfirm() {
var overwrite = confirm('Warning: This will overwrite the existing file - Do you confirm this?');
if (overwrite) remoteCommandOverwrite([{name: 'overwrite', value: 'true'}]);
}
</script>
And in the xhtml code I have:
<p:fileUpload id="fileUpload" fileUploadListener="#{filters.upload}" ...../>
<!-- Other code -->
<p:remoteCommand name="remoteCommandOverwrite" actionListener="#{filters.execOverwrite}"/>
Then on clicking the file upload button after clicking the choose file button, the code in the JavaScript, as listed above, is executed:
RequestContext.getCurrentInstance().execute("popupConfirm()");
Then on clicking "OK" in the dialog box, this method in the same bean is called:
public void execOverwrite() {
FacesContext context = FacesContext.getCurrentInstance();
Map<String, String> map = context.getExternalContext().getRequestParameterMap();
String soverwrite = map.get("overwrite");
if (soverwrite.equals("true")) {
overwrite = true; }
}
}
where the flag "overwrite" will eventually be tested to see if it is true.
Using various print statements I check that this works. However, the code does not resume executing after encountering the statement: RequestContext.getCurrentInstance().execute("popupConfirm()"); regardless of whether I enter "OK" or "Cancel" in the dialog, which is what i want it to do. It looks as if a callback of some type is required, and would most appreciate some ideas.
According to your tag, you are using PrimeFaces, so there is an easy way to invoke a javascript function from a server side event managed bean method when the browser has completed processing the server response. PrimeFaces gives you a utility class called RequestContext.
public void doActionListenerMethod() {
if (!isValid()) {
RequestContext.getCurrentInstance().execute("MyJSObject.doClientSideStuff()");
}
}
The following will execute the string argument as a Javascript when JSF has finished rendering on the client.
I have an MFC application that uses CHtmlView. It displays some text in html format from some temp html file. Is it possible to handle mouse click on a paragraph to send some data to the program? I understand that javascript can be used to handle click, but how to pass the data from javascript function to the application??
Thanks.
It is possible to cleanly call the containing application from within the Javascript of the HTML page. At the Javascript level the MSHTML interface that is doing the actual work of the CHtmlView provides an "external" object that acts as a way back to the calling application.
Suppose we want to add a method "someCall()" that can be called from Javascript, and that the method takes a string as an argument. In JavaScript we would call it with something like
external.someCall("An example string");
In the MFC application, we need to write a CCmdTarget derived object to act as the implementation of the "external" object as a dispatch-based COM object, something like:
class TestExternal : public CCmdTarget
{
public:
TestExternal()
{
EnableAutomation();
}
void SomeCall(LPCWSTR str)
{
// This is where we get called when the Javascript runs...
}
private:
DECLARE_DISPATCH_MAP()
};
BEGIN_DISPATCH_MAP(TestExternal,CCmdTarget)
DISP_FUNCTION(TestExternal,"someCall",SomeCall,VT_EMPTY,VTS_WBSTR)
END_DISPATCH_MAP()
To tie this implementation of "external" with the HTML view, in a class derived from CHtmlView you need to over-ride OnGetExternal() and to point it to an instance of TestExternal that lives at least as long as the CHtmlView:
class TestHtmlView : public CHtmlView
{
// Usual implementation stuff goes here...
public:
HRESULT OnGetExternal(LPDISPATCH *lppDispatch)
{
*lppDispatch = m_external.GetIDispatch(TRUE);
return S_OK;
}
private:
TestExternal m_external;
};
Note that I haven't actually tested this, but it seems about right from memory ...