VB6で作ったActiveXコントロールをWindowsのフォントサイズ変更に対応させる
こんにちは>自分(たぶんここの内容を忘れて検索してきたんでしょ?(^^;)
Windowsの画面設定でフォントを小とか中とか大とかにしたときに、アプリのフィールドのレイアウトが崩れないようにしたいというのが話の始まり。
だったらFormのAutoScaleMode=Fontにすれば勝手にレイアウトを調整してくれるはず、と思ってやってみたら、一部のコントロールだけずれて表示されることが判明。
どんなコントロールがずれているか調べると、VB6で作ったActiveXコントロールをインポートしたものであることが判明。
運よくソースコードが手に入ったので自動レイアウト調整対応しようと思ったけど、どのタイミング(イベント)で対応すればわからないので、とりあえずレイアウト調整用のメソッドを追加して、.Netアプリ側で呼び出して調整できるようにすることで対応。
.Net用にインポートするためAxImpを使ったら・・
> AxImp hoge.ocx
AxImp エラー: タイプ ライブラリ インポータで型の検証中にエラーが発生しました。
クラス メンバなしでインポートしてください。
というエラー発生。
Googleで調べたら以下を発見。
The type library importer encountered an error during type verification
ようするに、エラーの詳細を知りたければTLBファイルを作ってTlbImpやれってことらしいと勝手に理解した。
でも、VB6で普通にコンパイルしてもTLBファイルができてない。
さらに調べたら以下を発見。
タイプ ライブラリを取得する方法 (。Visual Basic の OLE サーバーの TLB) ファイル
ようするに、プロジェクトプロパティーでリモートサーバーファイルをチェックしとけばいいってことなのでそうしてみたらTLBファイルができた!
できたTBLファイルをインポートしようとしたら以下のエラー発生。
> TblImp hoge.tlb
TlbImp : error TI0000 : System.IO.IOException - アクセスが拒否されました。
(HRESULT からの例外: 0x80070005 (E_ACCESSDENIED))
またまた調べたら以下のツィートまとめ発見。
鬱々真っ盛り
どうやら /outオプションを指定して成功したらしいが、そこでふとTlbImpがProgramFilesの中で実行されてるから、そこにファイルを出力しようとしてエラーになったんじゃないかと気づいた。
出力ファイル名はどうすればいいのか調べたら以下を発見
.NETクライアントからCOMオブジェクト使う
> TlbImp hoge.tlb /out c:\temp\hoge.dll
Type library imported to c:\temp\hoge.dll
まだ続くけど今日はここまで。
Windowsの画面設定でフォントを小とか中とか大とかにしたときに、アプリのフィールドのレイアウトが崩れないようにしたいというのが話の始まり。
だったらFormのAutoScaleMode=Fontにすれば勝手にレイアウトを調整してくれるはず、と思ってやってみたら、一部のコントロールだけずれて表示されることが判明。
どんなコントロールがずれているか調べると、VB6で作ったActiveXコントロールをインポートしたものであることが判明。
運よくソースコードが手に入ったので自動レイアウト調整対応しようと思ったけど、どのタイミング(イベント)で対応すればわからないので、とりあえずレイアウト調整用のメソッドを追加して、.Netアプリ側で呼び出して調整できるようにすることで対応。
.Net用にインポートするためAxImpを使ったら・・
> AxImp hoge.ocx
AxImp エラー: タイプ ライブラリ インポータで型の検証中にエラーが発生しました。
クラス メンバなしでインポートしてください。
というエラー発生。
Googleで調べたら以下を発見。
The type library importer encountered an error during type verification
ようするに、エラーの詳細を知りたければTLBファイルを作ってTlbImpやれってことらしいと勝手に理解した。
でも、VB6で普通にコンパイルしてもTLBファイルができてない。
さらに調べたら以下を発見。
タイプ ライブラリを取得する方法 (。Visual Basic の OLE サーバーの TLB) ファイル
ようするに、プロジェクトプロパティーでリモートサーバーファイルをチェックしとけばいいってことなのでそうしてみたらTLBファイルができた!
できたTBLファイルをインポートしようとしたら以下のエラー発生。
> TblImp hoge.tlb
TlbImp : error TI0000 : System.IO.IOException - アクセスが拒否されました。
(HRESULT からの例外: 0x80070005 (E_ACCESSDENIED))
またまた調べたら以下のツィートまとめ発見。
鬱々真っ盛り
どうやら /outオプションを指定して成功したらしいが、そこでふとTlbImpがProgramFilesの中で実行されてるから、そこにファイルを出力しようとしてエラーになったんじゃないかと気づいた。
出力ファイル名はどうすればいいのか調べたら以下を発見
.NETクライアントからCOMオブジェクト使う
> TlbImp hoge.tlb /out c:\temp\hoge.dll
Type library imported to c:\temp\hoge.dll
まだ続くけど今日はここまで。
Windows Mobile C# GPSサンプルでNullReferenceException
WindowsMobileのSDKについているC#用のGPSのサンプルプログラムを試したら
GpsTest.Form1.UpdateData() at TASK.Invoke()でNullReferenceExceptionが発生した。
GPSが正しいかどうかもわからなかったので
デバッグ前にちょっとネットで検索したら以下のサイトが見つかった。
http://social.msdn.microsoft.com/Forums/en/windowsmobiledev/thread/c8dc277d-4696-4d43-b7c0-ab1b2f282d59
そこには
position = args.Position の行の前にsleep入れろとか、
argsがnullなら無視しろとか・・
いろいろ書いてある。
これは素直にデバッグしたほうがよさそう。
ってことで、Invoke(updateDataHandler)にブレイクポイントをしかけて
エラーの箇所がわかったら、またその中にブレイクポイントしかけて・・。
結局以下のように修正すればいいことがわかりました。
Form1.cs
void UpdateData(object sender, System.EventArgs args)
{
: (省略)
str += "Satellite Count:\n " + position.GetSatellitesInSolution().Length + "/" +
position.SatellitesInViewCount + " (" +
position.SatelliteCount + ")\n";
: (省略)
}
また、GPSの座標が取得できるようになるとそちらでもZeroDevide例外が発生するので
同様にデバッグして以下のように修正。
DegreesMinutesSeconds.cs
public double ToDecimalDegrees()
{
int absDegrees = Math.Abs(degrees);
double val = (double)absDegrees + ((double)minutes / 60.0) + ((double)seconds / 3600.0);
if (degrees == 0)
{
return val;
}
return val * (absDegrees / degrees);
}
ちなみに、似たような修正コードを載せてる人を発見!
Fixing the Windows Mobile 5.0 GPS Sample Code
http://www.peterfoot.net/FixingTheWindowsMobile50GPSSampleCode.aspx
あれれ、degreesが0なら0.0を返しちゃってる。
分、秒はいらないのか?
それに緯度、経度は度10進にせずに返しちゃってるし。
いまいちだと思うけど、必要に応じてってことにしとくか。
なんにしても、いまさらのWindows Mobileなので需要はないと思いますが(^^;
4~5年前なら少しは需要があったかもね。
GpsTest.Form1.UpdateData() at TASK.Invoke()でNullReferenceExceptionが発生した。
GPSが正しいかどうかもわからなかったので
デバッグ前にちょっとネットで検索したら以下のサイトが見つかった。
http://social.msdn.microsoft.com/Forums/en/windowsmobiledev/thread/c8dc277d-4696-4d43-b7c0-ab1b2f282d59
そこには
position = args.Position の行の前にsleep入れろとか、
argsがnullなら無視しろとか・・
いろいろ書いてある。
これは素直にデバッグしたほうがよさそう。
ってことで、Invoke(updateDataHandler)にブレイクポイントをしかけて
エラーの箇所がわかったら、またその中にブレイクポイントしかけて・・。
結局以下のように修正すればいいことがわかりました。
Form1.cs
void UpdateData(object sender, System.EventArgs args)
{
: (省略)
str += "Satellite Count:\n " + position.GetSatellitesInSolution().Length + "/" +
position.SatellitesInViewCount + " (" +
position.SatelliteCount + ")\n";
: (省略)
}
また、GPSの座標が取得できるようになるとそちらでもZeroDevide例外が発生するので
同様にデバッグして以下のように修正。
DegreesMinutesSeconds.cs
public double ToDecimalDegrees()
{
int absDegrees = Math.Abs(degrees);
double val = (double)absDegrees + ((double)minutes / 60.0) + ((double)seconds / 3600.0);
if (degrees == 0)
{
return val;
}
return val * (absDegrees / degrees);
}
ちなみに、似たような修正コードを載せてる人を発見!
Fixing the Windows Mobile 5.0 GPS Sample Code
http://www.peterfoot.net/FixingTheWindowsMobile50GPSSampleCode.aspx
あれれ、degreesが0なら0.0を返しちゃってる。
分、秒はいらないのか?
それに緯度、経度は度10進にせずに返しちゃってるし。
いまいちだと思うけど、必要に応じてってことにしとくか。
なんにしても、いまさらのWindows Mobileなので需要はないと思いますが(^^;
4~5年前なら少しは需要があったかもね。
Visual Studio 2008 C# でデザイナの読み込み時に 1 つ以上のエラーが発生
朝っぱらから心臓に悪いエラー。
チェックイン前のソースをいじったことをどれだけ後悔したことか。。。
エラーの内容はこんな感じ。
-----
デザイナの読み込み時に 1 つ以上のエラーが発生しました。エラーは以下に一覧表示されます。コードの変更が必要なエラーもありますが、プロジェクトを再度ビルドすると解決できるエラーもあります。
ファイル内にデザインできるクラスがないため、このファイルのデザイナを表示できませんでした。ファイルの以下のクラスがデザイナで見つかりました: childUserControl --- baseUserControl を読み込めませんでした。アセンブリが参照されているか、およびすべてのプロジェクトがビルドされているかを確認してください。
非表示
場所 System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.EnsureDocument(IDesignerSerializationManager manager)
場所 System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager manager)
場所 Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager serializationManager)
場所 Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.DeferredLoadHandler.Microsoft.VisualStudio.TextManager.Interop.IVsTextBufferDataEvents.OnLoadCompleted(Int32 fReload)
-----
エラー前にやったことは、画像ファイルの差し替え(^^;
リソースが見つからないとかいうエラーも出てたんでとりあえずソース上では
画像ファイルの参照をコメントにしてコンパイルを通るようにしたんだけど
相変わらず上記のエラーがでてユーザーコントロールが開けない。
Baseクラスに問題ありって言ってるので、ためしに新たなUserControlを作成し
それを継承元に指定してリビルド。
・・でもだめ orz
ネットで検索したら
VSUG フォーラム Visual Studio Visual Studio 2... フォームのデザイナでエラー
http://vsug.jp/tabid/63/forumid/42/postid/4340/view/topic/Default.aspx
がヒット。
なるほど、確かに昨日ファイル検索したから、そのせいでインデックスが作られたかなと思い
フォルダのプロパティを見ると、確かに
「このフォルダー内のファイルに対し、プロパティだけでなくコンテンツにもインデックスを付ける」にチェックがついてる。
というわけで、プロジェクトのフォルダでチェックをはずしOKを押して
「変更をこのフォルダー、サブフォルダーおよびファイルに適用する」
にチェックをつけてOKを押して、インデックスを消してやった。
これで大丈夫かと思いきや、やっぱりだめ。
上記サイトに「参考にしたHP」として載っていた
VS2005 Another Desinger Issue - Winforms not opening
http://geekswithblogs.net/rupreet/archive/2005/12/21/63740.aspx
を開いてみると、
1. すべてのフォームを閉じる
2. VisualStudioを閉じる(この時すべてのフォームを閉じておくこと)
3. "bin" および "obj" フォルダを削除
4. VisualStudioを開く
5. リビルドする
6. エラーになってたフォームを開いてごらん。もう大丈夫!
みたいなこと(適当)が書かれてたので
フォームじゃなくてユーザーコントロールでも同じだよね?と思い、
さっそく実行。
めでたくユーザーコントロールを開くことができましたとさ。
いや、めでたい。
チェックイン前のソースをいじったことをどれだけ後悔したことか。。。
エラーの内容はこんな感じ。
-----
デザイナの読み込み時に 1 つ以上のエラーが発生しました。エラーは以下に一覧表示されます。コードの変更が必要なエラーもありますが、プロジェクトを再度ビルドすると解決できるエラーもあります。
ファイル内にデザインできるクラスがないため、このファイルのデザイナを表示できませんでした。ファイルの以下のクラスがデザイナで見つかりました: childUserControl --- baseUserControl を読み込めませんでした。アセンブリが参照されているか、およびすべてのプロジェクトがビルドされているかを確認してください。
非表示
場所 System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.EnsureDocument(IDesignerSerializationManager manager)
場所 System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager manager)
場所 Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager serializationManager)
場所 Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.DeferredLoadHandler.Microsoft.VisualStudio.TextManager.Interop.IVsTextBufferDataEvents.OnLoadCompleted(Int32 fReload)
-----
エラー前にやったことは、画像ファイルの差し替え(^^;
リソースが見つからないとかいうエラーも出てたんでとりあえずソース上では
画像ファイルの参照をコメントにしてコンパイルを通るようにしたんだけど
相変わらず上記のエラーがでてユーザーコントロールが開けない。
Baseクラスに問題ありって言ってるので、ためしに新たなUserControlを作成し
それを継承元に指定してリビルド。
・・でもだめ orz
ネットで検索したら
VSUG フォーラム Visual Studio Visual Studio 2... フォームのデザイナでエラー
http://vsug.jp/tabid/63/forumid/42/postid/4340/view/topic/Default.aspx
がヒット。
なるほど、確かに昨日ファイル検索したから、そのせいでインデックスが作られたかなと思い
フォルダのプロパティを見ると、確かに
「このフォルダー内のファイルに対し、プロパティだけでなくコンテンツにもインデックスを付ける」にチェックがついてる。
というわけで、プロジェクトのフォルダでチェックをはずしOKを押して
「変更をこのフォルダー、サブフォルダーおよびファイルに適用する」
にチェックをつけてOKを押して、インデックスを消してやった。
これで大丈夫かと思いきや、やっぱりだめ。
上記サイトに「参考にしたHP」として載っていた
VS2005 Another Desinger Issue - Winforms not opening
http://geekswithblogs.net/rupreet/archive/2005/12/21/63740.aspx
を開いてみると、
1. すべてのフォームを閉じる
2. VisualStudioを閉じる(この時すべてのフォームを閉じておくこと)
3. "bin" および "obj" フォルダを削除
4. VisualStudioを開く
5. リビルドする
6. エラーになってたフォームを開いてごらん。もう大丈夫!
みたいなこと(適当)が書かれてたので
フォームじゃなくてユーザーコントロールでも同じだよね?と思い、
さっそく実行。
めでたくユーザーコントロールを開くことができましたとさ。
いや、めでたい。
Windows7マシンへCtrl2Capをインストールするときに知っておくべき1つのこと
今まで黙ってたけど、ほんとはCapsLockよりCtrlのほうが好きだったんだ。
というわけで、Ctrl2capというソフトをインストールしました。
(Emacsユーザー御用達・・今は使ってませんが)
http://technet.microsoft.com/ja-jp/sysinternals/bb897578.aspx
コマンドプロンプトで実行すると
「Ctrl2cap must be run with administrative rights」
って怒られる。
管理者権限つければいいんでしょ~、と思って cmd /a ってやってみたら管理者権限にならず。
cmd /? でオプションを調べたら /a という管理者権限にするオプションが無くなってる。
実は、Windows7の管理者権限のあるコマンドプロンプトは
メニューで「コマンドプロンプト」を右クリックして
「管理者として実行...」としないといけないのでした。
これでめでたくインストール完了。
後は再起動するだけ。
これで小指が楽になるなぁ
というわけで、Ctrl2capというソフトをインストールしました。
(Emacsユーザー御用達・・今は使ってませんが)
http://technet.microsoft.com/ja-jp/sysinternals/bb897578.aspx
コマンドプロンプトで実行すると
「Ctrl2cap must be run with administrative rights」
って怒られる。
管理者権限つければいいんでしょ~、と思って cmd /a ってやってみたら管理者権限にならず。
cmd /? でオプションを調べたら /a という管理者権限にするオプションが無くなってる。
実は、Windows7の管理者権限のあるコマンドプロンプトは
メニューで「コマンドプロンプト」を右クリックして
「管理者として実行...」としないといけないのでした。
これでめでたくインストール完了。
後は再起動するだけ。
これで小指が楽になるなぁ
VB.NetやC#.Netから、Excelのセルに文字列や式を高速に設定する方法
業務アプリを作っていると、Excelで帳票作成とかよくあります。
そんなとき、MSDNの以下の記事のように1セルずつまじめに値をセットしたりしてませんか?
コード : ワークシートのセルに値を送る (C#)
http://msdn.microsoft.com/ja-jp/library/aa288907(v=vs.71).aspx
1、2セルの更新ならまだいいですが、それ以上だと・・お・そ・・い・・ですし、
ちょっと大きな表になるともう待ちきれません。
そんなときは、オブジェクト型の2次元配列を用意して値をセットしておき
同じ大きさのRangeのValue2にまとめてセットします。
だいたい、こんな感じです。
object[,] rng = new object[1,3];
rng[0,0] = "test"; //文字列
rng[0,1] = "123"; //数字
rng[0,2] = "=R1C1"; //式
Excel.Range xrange = get_Range("R1C1:R10C10", Type.Missing);
xrange.Value2 = rng;
(ポイントだけです。実際は変数を使うとかReleaseComObjectとかちゃんとやってください)
この方法はExcelマクロ(VBA)のときも使えますよ。