C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

カーソルファイルを読み込むとプログラムが起動しない

[トピック内 7 記事 (1 - 7 表示)]  << 0 >>

■91669 / inTopicNo.1)  カーソルファイルを読み込むとプログラムが起動しない
  
□投稿者/ けるん (1回)-(2019/07/18(Thu) 19:52:22)

分類:[.NET 全般] 

VB2017で作成した自作プログラムがあり、

複数台の
Windows10と7で試していて、ほとんどPCで問題なく起動できるのですが、
なぜか1台だけ、起動できないWin7のPCがあります。


原因を探るために
コードを一つずつ削除してビルドして繰り返して調べたところ、どうも以下のコードに問題があることが分かりました。




Public Class Form1


Private CursorTest As New System.Windows.Forms.Cursor(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(
GetType(Form1).Namespace & ".Test.cur"))


End Class




このように、
EXEファイルに埋め込んだカーソルファイルを読み込みたいのですが、
なぜ、1台だけうまく起動できないPCがあるのでしょうか?

起動できないPCとできるPCの違いは何でしょうか?

そして、起動できないPCで上記のコードを使いたい場合
どのようにしたら良いですか?



引用返信 編集キー/
■91670 / inTopicNo.2)  Re[1]: カーソルファイルを読み込むとプログラムが起動しない
□投稿者/ 魔界の仮面弁士 (2247回)-(2019/07/18(Thu) 20:38:54)
No91669 (けるん さん) に返信
> コードを一つずつ削除してビルドして繰り返して調べたところ、どうも以下のコードに問題があることが分かりました。
> Private CursorTest As New System.Windows.Forms.Cursor(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(Form1).Namespace & ".Test.cur"))

上記の宣言を
 Private CursorTest As System.Windows.Forms.Cursor = Nothing
に変更し、Form1 の コンストラクタにて、
 Dim a = System.Reflection.Assembly.GetExecutingAssembly()
 Dim b = GetType(Form1).Namespace & ".Test.cur"
 Dim c = a.GetManifestResourceStream(b)
 Dim d As New System.Windows.Forms.Cursor(c)
 Me.CursorTest = d
のようにして、どの段階で問題が起きているのかを追跡してみてください。
引用返信 編集キー/
■91671 / inTopicNo.3)  Re[2]: カーソルファイルを読み込むとプログラムが起動しない
□投稿者/ けるん (2回)-(2019/07/18(Thu) 20:56:54)
ありがとうございます。

どうも
 Dim d As New System.Windows.Forms.Cursor(c)

型 'System.ArgumentException' の例外が System.Windows.Forms.dll で発生しましたが、ユーザー コード内ではハンドルされませんでした

追加情報:イメージの形式が有効ではありません。イメージ ファイルが壊れている可能性があります。



というエラーが発生しているようです。

PCによって実行できたりできなかったりするのはなぜなのでしょうか?
引用返信 編集キー/
■91672 / inTopicNo.4)  Re[3]: カーソルファイルを読み込むとプログラムが起動しない
□投稿者/ 魔界の仮面弁士 (2248回)-(2019/07/18(Thu) 21:12:10)
2019/07/18(Thu) 22:33:34 編集(投稿者)

No91671 (けるん さん) に返信
> PCによって実行できたりできなかったりするのはなぜなのでしょうか?

内部的には、OleCreateIPictureIndirect API への呼び出しになっていそうなので、
実行環境の .NET Framework バージョンもしくは OLEAUT32.DLL のバージョンが
異なっているなどの理由かもしれません。自信なし。
 
あとは「管理者として実行」「互換モード実行」「セキュリティソフト」で
違いがでるかどうか、という程度。
 

該当リソースをファイルとして保存して、それをバイナリエディタで開き、
正しいカーソル形式になっているかどうかも確認した方が良いかも。

.cur 形式なら、先頭 4 バイトは 00,00,02,00 のはずですし、
.ico 形式なら、先頭 4 バイトは 00,00,01,00 のはず。
.ani や .svg 形式はそもそも非対応。


Imports System.IO
Public Class Form1
 Private Declare Auto Function LoadCursorFromFile Lib "user32" (lpFileName As String) As IntPtr

 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  TextBox1.Text = "C:\windows\Cursors\aero_busy_xl.ani"
 End Sub

 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
  '☆ OK
  Button1.Cursor = New Cursor(LoadCursorFromFile(TextBox1.Text))
 End Sub

 Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
  '★ NG
  Button2.Cursor = New Cursor(TextBox1.Text)
 End Sub

 Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
  '★ NG
  Dim stm As New MemoryStream(File.ReadAllBytes(TextBox1.Text))
  Button3.Cursor = New Cursor(stm)
 End Sub
End Class
引用返信 編集キー/
■91673 / inTopicNo.5)  Re[4]: カーソルファイルを読み込むとプログラムが起動しない
□投稿者/ けるん (3回)-(2019/07/18(Thu) 22:28:42)
先頭 4 バイトは 00,00,02,00 になっていました。

うーん、.NET Framework バージョンなのかも知れませんね。
VisualStudioはなぜか.NET標準の方法だとうまくカーソルファイルを読み込めないのですね・・・

どうもありがとうございました。

解決済み
引用返信 編集キー/
■91688 / inTopicNo.6)  Re[5]: カーソルファイルを読み込むとプログラムが起動しない
□投稿者/ けるん (5回)-(2019/07/20(Sat) 15:22:04)
追加回答ありがとうございます。

LoadCursorFromFile
ならうまくいくので、こちらを使おうと思います

なぜ、.NET機能のカーソル機能は軟弱なのでしょうね
ホットポイントも読み込めませんし・・・

解決済み
引用返信 編集キー/
■91691 / inTopicNo.7)  Re[6]: カーソルファイルを読み込むとプログラムが起動しない
□投稿者/ 魔界の仮面弁士 (2251回)-(2019/07/20(Sat) 18:03:34)
No91688 (けるん さん) に返信
> なぜ、.NET機能のカーソル機能は軟弱なのでしょうね

カラーカーソルやアニメーションカーソルを使う場合、自分が知る限りでは
そもそも Win32 API 側が、LoadCursorFromFile で「ファイルから読み取る」か、
LoadImage または LoadCursor で「リソースから読み取る」という選択肢しか
用意されていなかったように思います。

メモリからの直接読み込みがサポートされていないので、
.NET Framework 側でもどうにもならなかったんだろうと想像。



> ホットポイントも読み込めませんし・・・
おまけにモノクロカーソルになりますしね…。
アニメーションカーソルも使えませんし。

本来のカーソルを exe 内のリソースに埋め込む場合は、
 Private Declare Auto Function LoadCursor Lib "user32" (hInstance As IntPtr, lpCursorName As String) As IntPtr
 Private Declare Auto Function LoadCursor Lib "user32" (hInstance As IntPtr, wdResourceId As IntPtr) As IntPtr
を使って
 Dim hInstance As IntPtr = System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetEntryAssembly().GetModules().First())
 Dim hImage As IntPtr = LoadCursor(hInstance, リソース内の対象のカーソルを示す識別子)
 Button1.Cursor = New Cursor(hImage)
という感じにすることで、一応可能だったりします。


厄介なのは、この場合に必要な「exe 内のリソース」というのが、
マネージリソース(*.resx)ではなく、Win32 リソース(*.res)であるという点。

マネージリソースが使えなくなるので、いろいろデメリットもありますが、
とりあえず手順だけ:


1) 下記にある Resource Editor をダウンロードして起動
 http://melander.dk/reseditor

2) [Resources]ペイン で [Add] ボタンを押して、
 [Cursor] または [Add from file...] でカーソル追加。
 カラーカーソルやアニメーションカーソルでも OK。

3) [File] メニューから、.res ファイルとして保存する。今回は example.res。


さらに VB 側で、マネージリソースの代わりに Win32 リソースが取り込まれるよう、
プロジェクト設定を変更。

1) VB の WinForm プロジェクトで、プロジェクトの プロパティの
 [アプリケーション]タブで[アイコン]を(既定のアイコン)にしておく。

 ※ここのアイコン設定は、*.res 指定とは共存できません。
  exe のアイコンを用意したいなら、それも *.res に含めておく必要があります。

2) 先ほど作っておいた example.res をプロジェクトフォルダーに配置。
 ※別のパスにすることもできますが、ここでは説明省略。


3) .vbproj をメモ帳または XML エディタで開き、
 https://dobon.net/vb/dotnet/programing/embedwin32resource.html#section6
 にしたがって、<ProjectGroup> タグの下に
 「<Win32Resource>example.res</Win32Resource>」を追加。

4) ビルドしてエラーが出なければ完了。


マネージリソースではないので、開発環境での WinForm デザイナに影響が出たりするので、
自分は <ProjectGroup> ではなく、<ProjectGroup Condition="ビルド条件"> タグの下においてます。



実際にはマネージリソースが使えないデメリットの方が大きいので、
カーソルをバイナリとしてマネージリソースの中に埋め込んでおき、
一時フォルダにでも展開して、LoadCursorFromFile した方が安全かも。
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ