DOBON.NET DOBON.NETプログラミング掲示板過去ログ

エントリポイントから起動されたフォーム内関数からのjabascript関数実行

環境/言語:[OS : Windows 7 / 言語 : Visual Basic .NET / .NET Framework : 4.5]
分類:[.NET]

【解決したい問題】

いつもお世話になっております。

現在、VB.Net・javascriptともに初級者レベルにもかかわらず、VB.Netのウェブ
ブラウザ上で動作するjavascriptとVBとの間で制御をやり取りするプログラムを
開発中(試作中)です。『VBプログラマの為のAjax入門』(http://www.geocities.jp/i_love_balard/myhome/ajax/javascript_vb.html)
とのサイト等を参考にさせて頂き、試作プログラムではありますが、〔VB.Netフォームからのjavascript起動〕、
〔javascript側からのVB.Net関数実行〕、〔VB.Net関数内からのjavascript関数実行〕
ができるようになりました。

ただ、今回の仕様ではアプリケーションの起動はスタートアップフォームからで
はなく、別クラス内に作成したエントリポイントから起動する事が必要(理由に
ついては長くなりますので御容赦願います)です。そこで、現状ではメインフォー
ム(Form1.vb)をスタートアップフォームにしていたのですが、別クラス(Class1)
を作成し、プロジェクトのプロパティページにて[スタートアップオブジェクト]
ドロップダウンで「Sub Main」を選択しました。しかし、それにより今まで実行
できていた〔VB.Net関数内からのjavascript関数実行〕がエラー(オブジェクト
参照がオブジェクトインスタンスに設定されていません。)になってしまいます。

どなたか、理由・対策をご存知の方、アドバイス頂けましたら幸いです。

【解決するために何をしたか】

[アプリケーションフレームワークを有効にする]チェックボックスの値に関係す
るのかとも思いましたが、無関係なようです。

【追加事項】

以下にクラス及びフォームのソースを添付します。

≪クラス≫
Public Class Class1
    <STAThread()> _
    Shared Sub Main()
        Application.EnableVisualStyles()
        Application.SetCompatibleTextRenderingDefault(False)
        Application.Run(New Form1())
    End Sub
End Class

≪フォーム≫
Imports System.Security.Permissions
Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.WebBrowser1.ObjectForScripting = New Acces_From_Web
        Dim htmldoc As String
        htmldoc = "<!DOCTYPE html PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN"">"
        htmldoc = htmldoc & vbCrLf & "<html lang=""ja"">"
        htmldoc = htmldoc & vbCrLf & "<head>"
        htmldoc = htmldoc & vbCrLf & "    <meta http-equiv=""content-type"" content=""text/html; charset=Shift_JIS"">"
        htmldoc = htmldoc & vbCrLf & "    <script type='text/javascript'>"
        htmldoc = htmldoc & vbCrLf & "        function fromVB() {"
        htmldoc = htmldoc & vbCrLf & "            alert('VB.netから呼ばれました!');"
        htmldoc = htmldoc & vbCrLf & "        }"
        htmldoc = htmldoc & vbCrLf & "    </script>"
        htmldoc = htmldoc & vbCrLf & "</head>"
        htmldoc = htmldoc & vbCrLf & "<script language=""JavaScript"" type=""text/javascript"">"
        htmldoc = htmldoc & vbCrLf & "<!--"
        htmldoc = htmldoc & vbCrLf & "function call_vb_sub(){"
        htmldoc = htmldoc & vbCrLf & "    window.external.CallFromJavascript('called from script code');"
        htmldoc = htmldoc & vbCrLf & "}"
        htmldoc = htmldoc & vbCrLf & "// -->"
        htmldoc = htmldoc & vbCrLf & "</script>"
        htmldoc = htmldoc & vbCrLf & "<body>"
        htmldoc = htmldoc & vbCrLf & "<form action="" method=""post"" enctype=""multipart/form-data"" name=""vb1"">"
        htmldoc = htmldoc & vbCrLf & "<input type=""button"" name=""call_vb_sub_b"" value=""VBのサブルーチンをコールする"" onclick=""call_vb_sub()"">"
        htmldoc = htmldoc & vbCrLf & "</form>"
        htmldoc = htmldoc & vbCrLf & "</body>"
        htmldoc = htmldoc & vbCrLf & "</html>"
        WebBrowser1.DocumentText = htmldoc
    End Sub
End Class
<PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
<System.Runtime.InteropServices.ComVisibleAttribute(True)> _
Public Class Acces_From_Web
    Public Sub CallFromJavascript(ByVal value As String)
        MessageBox.Show("これはjavascriptから呼ばれたメソッド" & vbCrLf & value)
        Form1.WebBrowser1.Document.InvokeScript("fromVB", {})
    End Sub
End Class
添付ファイル: 1405475292.jpg (31 KB)
■No32457に返信(Iraquserさんの記事)
> エラー(オブジェクト参照がオブジェクトインスタンスに設定されていません。)になってしまいます。

その時点では、Form1.WebBrowser1.Document は Nothing だからです。


> どなたか、理由・対策をご存知の方、

Acces_From_Web.CallFromJavascript 内で呼ばれている Form1 は、
Sub Main 内で生成した New Form1 とは別物です。


たとえば、Form1_Load 内に
 MsgBox(Me Is DirectCast(CallByName(My.Forms, "Form1", CallType.Get), Form1))
を書いてみてください。
Form1 をスタートアップにした場合は True ですが、
Sub Main からはじめた場合は False になるはずです。


また、Form1_Load 内に
 DirectCast(CallByName(My.Forms, "Form1", CallType.Get), Form1).Show()
を書き、スタートアップに対する動作の違いを確認してみて下さい。



> アドバイス頂けましたら幸いです。
手っ取り早いのは、「New Form1()」をしないことです。

「暗黙の Form」と「New Form1()」を併用するのではなく、
 Application.Run(My.Forms.Form1)
あるいはその省略形である
 Application.Run(Form1)
の形で記述すれば、一応動作するようになるでしょう。


とはいえ、そもそもは Acces_From_Web 内から Form1 を
直接参照している事が問題です。
暗黙の Form インスタンスに頼るのではなく、

<PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
<System.Runtime.InteropServices.ComVisibleAttribute(True)> _
Public Class Acces_From_Web
 Private wb As WebBrowser
 Public Sub New(wb As WebBrowser)
  Me.wb = wb
 End Sub

 Public Sub CallFromJavascript(ByVal value As String)
  MessageBox.Show("これはjavascriptから呼ばれたメソッド" & vbCrLf & value)
 wb.Document.InvokeScript("fromVB", {})
 End Sub
End Class

のように、制御対象の WebBrowser を引数として受け取るようにし、
それを呼び出し側から
 Me.WebBrowser1.ObjectForScripting = New Acces_From_Web(Me.WebBrowser1)
などとして渡すようにしてみてください。

これならば、Application.Run(New Form1()) や Application.Run(Form1) の
いずれであっても動作するようになるはずです。
■No32459に返信(魔界の仮面弁士さんの記事)

> その時点では、Form1.WebBrowser1.Document は Nothing だからです。

そうでした。お恥かしい。
アドバイス頂いた方式で解決しました。
有難うございます。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板