2011-07-28
バックテストでがっかり
2、3日かけてプログラムを作成して行ったバックテストの結果が(想定していたけど)あんまり良くなかったがっかり感。ひょっとしたら、結構良い成績になるんじゃないか、と思ったけど、やはり駄目だった。
まあ、これで一つ調べるべき事をつぶせたので、前進したと考えよう。
2011-07-19
IE9をType.InvokeMemberで操作
IE9では、Type.InvokeMemberを利用して、IEを操作することになるのだけど、情報が少ない。
従って、実験を繰り返して調べることになる。
ここでは、その研究結果のコードを掲載しておきます。もっと洗練された方法があるはずだけれど、とりあえず動くものを作るのが必要なので、野暮ったいのは勘弁して下さい。
IE8までは、もっと簡単なコードで充分だったのに、IE9では厳密に指定しないと駄目。
Visual Studio 2010 / VB.net用
http://www.moderns.co.jp/files/UsingIE9Object.zip
Imports System.Reflection Public Class Form1 Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click 'BindingFlags.GetProperty などを短く置き変えることが出来る。 'Dim getPr As BindingFlags = BindingFlags.GetProperty 'Dim setPr As BindingFlags = BindingFlags.SetProperty 'Dim invMe As BindingFlags = BindingFlags.InvokeMethod Dim ieObj As Object ieObj = CreateObject("InternetExplorer.application") 'IEのオブジェクトを作る If ieObj Is Nothing Then MsgBox("IE Nothing") End If ieObj.Visible = True '見えるようにする Dim uri As String = My.Computer.FileSystem.CombinePath(My.Application.Info.DirectoryPath, "IE9.html") 'uri = "http://www.moderns.co.jp/" Try ieObj.Navigate2(uri) Catch MsgBox("file not found:" & vbCrLf & uri) Exit Sub End Try Call ieWait(ieObj) Dim ieDoc As Object Dim typ As Type typ = Type.GetTypeFromProgID("mhtmlfile") 'あるいは、こちらでもOK。 'typ = Type.GetTypeFromCLSID(New System.Guid("{3050F4E7-98B5-11CF-BB82-00AA00BDCE0B}")) 'ieDoc = ieObj.Document 'IE8までは、こうした文法で良かった。IE9では、以下のようにするのが良い。 ieDoc = typ.InvokeMember("document", BindingFlags.GetProperty, Nothing, ieObj, Nothing) 'Title TextBox1.Text &= "title: " & typ.InvokeMember("title", BindingFlags.GetProperty, Nothing, ieDoc, Nothing) & vbCrLf 'URLは大文字 TextBox1.Text &= "URL: " & typ.InvokeMember("URL", BindingFlags.GetProperty, Nothing, ieDoc, Nothing) & vbCrLf 'Linkの数 TextBox1.Text &= "Link count : " & typ.InvokeMember("links", BindingFlags.GetProperty, Nothing, ieDoc, Nothing).length & vbCrLf 'TextBox1.Text &= "URL: " & GetP("URL", ieDoc) & vbCrLf 'TextBox1.Text &= "Link count : " & GetP("links", ieDoc).length & vbCrLf 'Typeを表示 mshtml.HTMLAnchorElementClass となる。 TextBox1.Text &= typ.InvokeMember("links", BindingFlags.GetProperty, Nothing, ieDoc, Nothing)(1).ToString & vbCrLf '2番目のリンクのInnerText TextBox1.Text &= "Second Link InnterText : " & typ.InvokeMember("innerText", BindingFlags.GetProperty, Nothing, typ.InvokeMember("links", BindingFlags.GetProperty, Nothing, ieDoc, Nothing)(1), Nothing) & vbCrLf '2番目のリンクをクリックする。 'Dim links As Object = typ.InvokeMember("links", BindingFlags.GetProperty, Nothing, ieDoc, Nothing) 'link 全部のObject 'typ.InvokeMember("click", BindingFlags.InvokeMethod, Nothing, links(1), Nothing) 'links(1)は、2番目のlinkを意味する。 'あるいは、こちらでも同じ。 'Dim link2 As Object = typ.InvokeMember("links", BindingFlags.GetProperty, Nothing, ieDoc, Nothing)(1) '2番目のlinkのObject (0)1番目 (1)2番目 (2)3番目 ・・・ 'typ.InvokeMember("click", BindingFlags.InvokeMethod, Nothing, link2, Nothing) 'Call ieWait(ieObj) TextBox1.Text &= vbCrLf 'Body Elementを確定する2種類の方法 '1 how to get the body object Dim htmlBody As Object htmlBody = typ.InvokeMember("body", BindingFlags.GetProperty, Nothing, ieDoc, Nothing) 'htmlBody = GetP("body", ieDoc) TextBox1.Text &= "body innerHTML : " & typ.InvokeMember("innerHTML", BindingFlags.GetProperty, Nothing, htmlBody, Nothing) & vbCrLf & vbCrLf '2 how to get the body object Dim htmlBody2 As Object htmlBody2 = typ.InvokeMember("getElementsByTagName", BindingFlags.InvokeMethod, Nothing, ieDoc, {"body"})(0) 'htmlBody2 = InvokeM("getElementsByTagName", ieDoc, {"body"})(0) TextBox1.Text &= "body innerHTML : " & typ.InvokeMember("innerHTML", BindingFlags.GetProperty, Nothing, htmlBody2, Nothing) & vbCrLf & vbCrLf 'Form Element Dim formElm As Object = typ.InvokeMember("getElementsByName", BindingFlags.InvokeMethod, Nothing, ieDoc, {"formName1"}) Dim inputElm As Object = typ.InvokeMember("getElementsByTagName", BindingFlags.InvokeMethod, Nothing, formElm(0), {"input"}) 'InputBox inputElmを利用 For i As Integer = 0 To inputElm.length - 1 TextBox1.Text &= typ.InvokeMember("name", BindingFlags.GetProperty, Nothing, inputElm(i), Nothing) & vbCrLf If typ.InvokeMember("name", BindingFlags.GetProperty, Nothing, inputElm(i), Nothing) = "siteurl" Then typ.InvokeMember("value", BindingFlags.SetProperty, Nothing, inputElm(i), {"input value"}) End If Next 'CheckBox inputElmを利用 For i As Integer = 0 To inputElm.length - 1 TextBox1.Text &= typ.InvokeMember("name", BindingFlags.GetProperty, Nothing, inputElm(i), Nothing) & vbCrLf If typ.InvokeMember("name", BindingFlags.GetProperty, Nothing, inputElm(i), Nothing) = "c1" Then typ.InvokeMember("checked", BindingFlags.SetProperty, Nothing, inputElm(i), {"True"}) End If Next 'RadioButton inputElmを利用 For i As Integer = 0 To inputElm.length - 1 TextBox1.Text &= typ.InvokeMember("name", BindingFlags.GetProperty, Nothing, inputElm(i), Nothing) & vbCrLf If typ.InvokeMember("name", BindingFlags.GetProperty, Nothing, inputElm(i), Nothing) = "r1" Then typ.InvokeMember("checked", BindingFlags.SetProperty, Nothing, inputElm(i), {"True"}) End If Next 'Select and Option Dim selectElm As Object = typ.InvokeMember("getElementsByName", BindingFlags.InvokeMethod, Nothing, ieDoc, {"sele1"})(0) Dim optionsElm As Object = typ.InvokeMember("getElementsByTagName", BindingFlags.InvokeMethod, Nothing, selectElm, {"option"}) For i As Integer = 0 To optionsElm.length - 1 TextBox1.Text &= typ.InvokeMember("innerText", BindingFlags.GetProperty, Nothing, optionsElm(i), Nothing) & vbCrLf If typ.InvokeMember("innerText", BindingFlags.GetProperty, Nothing, optionsElm(i), Nothing) = "def" Then typ.InvokeMember("selected", BindingFlags.SetProperty, Nothing, optionsElm(i), {"True"}) End If Next 'TextArea Dim textAElem As Object textAElem = typ.InvokeMember("getElementsByName", BindingFlags.InvokeMethod, Nothing, ieDoc, {"te1"}) 'textAElem = InvokeM("getElementsByName", ieDoc, {"te1"}) typ.InvokeMember("value", BindingFlags.SetProperty, Nothing, textAElem(0), {"textarea value"}) 'Call SetP("value", textAElem(0), {"textarea value"}) 'Form InnerHTML TextBox1.Text &= vbCrLf & "Form innerHTML : " & GetP("innerHTML", InvokeM("getElementsByName", ieDoc, {"formName1"})(0)) & vbCrLf End Sub ''' <summary> ''' IEの表示が完了するまで待つ ''' </summary> ''' <param name="ieObj"></param> ''' <remarks></remarks> Sub ieWait(ByRef ieObj As Object) Try Dim sw As New Stopwatch sw.Start() Do While (ieObj.Busy OrElse ieObj.ReadyState <> SHDocVw.tagREADYSTATE.READYSTATE_COMPLETE) _ AndAlso sw.Elapsed <= New TimeSpan(0, 0, 0, 20) '読み込み中でも、CheckWatingSecond(20秒)を超えたら抜ける Application.DoEvents() '読み込み中なら待つ Loop sw = Stopwatch.StartNew() Do While sw.Elapsed <= New TimeSpan(0, 0, 0, 0, 1000) '念のため読み込みが終わってもさらに1秒待つ Application.DoEvents() Loop sw.Reset() Catch ex As Exception 'IEが閉じられていた場合などエラーになるので、それをキャッチする。 MsgBox("Error") End Try End Sub ''' <summary> ''' InvokeMemberの、GetPropertyを実行 ''' </summary> ''' <param name="name1"></param> ''' <param name="target1"></param> ''' <param name="args1"></param> ''' <returns></returns> ''' <remarks></remarks> Function GetP(ByVal name1 As String, ByVal target1 As Object, Optional ByVal args1 As Object = Nothing) Dim typ As Type = Type.GetTypeFromProgID("mhtmlfile") Return typ.InvokeMember(name1, BindingFlags.GetProperty, Nothing, target1, args1) End Function ''' <summary> ''' InvokeMemberの、SetPropertyを実行 ''' </summary> ''' <param name="name1"></param> ''' <param name="target1"></param> ''' <param name="args1"></param> ''' <returns></returns> ''' <remarks></remarks> Function SetP(ByVal name1 As String, ByVal target1 As Object, Optional ByVal args1 As Object = Nothing) Dim typ As Type = Type.GetTypeFromProgID("mhtmlfile") Return typ.InvokeMember(name1, BindingFlags.SetProperty, Nothing, target1, args1) End Function ''' <summary> ''' InvokeMemberの、InvokeMethodを実行 ''' </summary> ''' <param name="name1"></param> ''' <param name="target1"></param> ''' <param name="args1"></param> ''' <returns></returns> ''' <remarks></remarks> Function InvokeM(ByVal name1 As String, ByVal target1 As Object, Optional ByVal args1 As Object = Nothing) Dim typ As Type = Type.GetTypeFromProgID("mhtmlfile") Return typ.InvokeMember(name1, BindingFlags.InvokeMethod, Nothing, target1, args1) End Function End Class
対象のHTML IE9.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>IE9 Object</title> </head> <body> <p><a href="http://www.moderns.co.jp/">modern design laboratory</a></p> <p><a href="http://www.msignal.info/">M.Signal</a></p> <p><a href="http://www.linkget.info/">LinkGet</a></p> <form action="form1.html" name ="formName1" method="get"> <input type="text" name="siteurl" size="20" /> <input type="checkbox" name="c1" value=""> <input type="checkbox" name="c2" value=""> <input type="radio" name="r1" value="b1"> <input type="radio" name="r1" value="b2"> <input type="radio" name="r1" value="b3"> <select name="sele1" size="1" tabindex="0"> <option value="">abc</option> <option value="">def</option> <option value="">ghi</option> </select> <textarea name="te1" rows="2" cols="20" tabindex="0"></textarea> </form> </body> </html>
2011-07-17
Internet Explorerを操作する為にMicrosoft.mshtml.dllを利用したプログラムを配布する際の問題。
開発環境か、Office用PIAをインストールしないと、Microsoft.mshtml.dllはインストールされない。従って、そのDLLを利用したプログラムを配布しても、利用したいPCにはインストールされていない可能性がある。
インストールされていないPCにMicrosoft.mshtml.dllをインストールするには、次のいずれかをインストールする必要がある。(上記3つは確認はとれていないが、おそらくOK)
- 2010:PIA Office 2010が必要
- 2007:PIA Office 2007が必要
- 2003:PIA Office 2003が必要
- .NET Framework 2.0 SDK(動作確認済)
ただし、上記3つはインストールするのに、対応するMicrosoft Officeがインストールされている必要があり、条件が厳しい。.NET Framework 2.0 SDKならOfficeは不要だが、482.6MB。ひどい。
その為、公開するアプリと一緒にMicrosoft.mshtml.dllを配布することを考えて調べてみた。けれども、配布できるファイルがredist.txtに書いてあり、Microsoft.mshtml.dllは配布できるファイルでは無いようだ。更に言えば、Microsoft.mshtml.dll単体をインストールするには、グローバル・アセンブリ・キャッシュ(GAC)に登録する必要があるが、難易度が高い(私はそこまで研究していないが)。
参考情報として、
- Microsoft.mshtml.dllをアプリのフォルダに置くだけでは無理。
- DLLをリソースとしてEXEファイルに埋め込んで、Microsoft.mshtml.dllがインストールされていない時に、埋めこんだDLLを利用する方法も出来なかった。
- C#の場合、Jeffrey Richter: Excerpt #2 from CLR via C#, Third Edition embed the DLL file(s) into your EXE file
- VBの場合、Embedding DLL resources into Executable (No more ILmerge)
結論として、私は、Microsoft.mshtml.dllの利用をあきらめた。代わりに、Type.InvokeMemberメソッドを利用して操作する方法に変更した。参照IE9をType.InvokeMemberで操作
このDLLを利用する必要に迫られたのは、IE8からIE9になり、IE9を操作するのに今までのコードでは操作できなくなったからだ。そのため、こうして相当な労力を費やして調査と実験とを繰り返しているのだ。なんで、HTMLを簡単に利用できるようになっていないのだろう。とは言っても仕方がないので、対応せざるを得ないんですけどね。
2011-07-15
Visual Studio 2010がクラッシュするようになったので、その原因追及。
拡張機能の、VS10x Code Map v2が、原因のようだとまず判明。この拡張機能を有効にしている場合で、IntelliSense(インテリセンス)が実行される時に、クラッシュするようだ。
次に、何の設定が問題になっているのか、原因の切り分けに多大な時間を費やした。
コードの量を減らしたり、参照を減らしたりしたり、****.vbproj.vs10xを削除したりしたが、クラッシュするのは変わらず。
最終的に、ClickOnceセキュリティ設定を有効にするのチェックを外して、あれこれ作業している内に、この現象が再現しなくなった。再現しないので原因ははっきりしないのだが、今まで大変に不便だったので直って良かった。
2011-03-21
寄り引け5銘柄
シグナル配信に、http://www.msignal.info/signal2を掲載しました。
2011-01-25
PHP内でTokenを使う
<?php $original= "[current-page-url]"; $original= token_replace($original, $type = 'global', $object = NULL, $leading = '[', $trailing = ']'); if ($original == "http://www.msignal.info/home") { ・・・処理・・・ } ?>
DrupalのPHP内でTokenを利用する方法がよく判らず難儀した。結局、上記のようにしたが、もっと上手な方法があるはず。
current-page-urlが、http://www.msignal.info/home の時に、処理をするスクリプト。
はっちゅう君+ アドイン開発
クリック証券のはっちゅう君+で、アドイン開発が出来るというので、簡単に株の売買が出来るようにならないか一日試行錯誤した。
結論から言うと、株の売買はもちろん、株のデータを受信してそれを表示することも、アドインとして作成することは出来ないことが判った。株のデータ受信はなんとかしてしまうことも出来るようだが、ヘルプにはそうした機能の記載は無い。最初、当然出来るだろうと思って、探しまくったけれど見つからず、どこか見落としているんだろうと思っていた。
ヘルプの説明とサンプルはC#なので、VB.netにするのに結構つまづいた。その点を書いておく。
例えば、サンプルでは、こうなっている。
namespace HelloWorld { public partial class Form1 : AddInForm { public Form1() { InitializeComponent(); } } }
これを、http://www.developerfusion.com/tools/convert/csharp-to-vb/ を利用してVB.netに変換すると、
Namespace HelloWorld Public Partial Class Form1 Inherits AddInForm Public Sub New() InitializeComponent() End Sub End Class End Namespace
になる。
けれど、
Namespace HelloWorld
End Namespace
はいらないので、消すこと。
