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

マウスカーソルを変更後、SendMessageTimeoutの反映

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

【解決したい問題】

マウスカーソルを変更するプログラムを作成しているのですが、カーソルを規定のフォルダにコピーし、レジストリを変更する箇所まではできたのですが、その変更を即時反映させようと、SendMessageTimeout、またはSendMessageを呼び出して、反映させようとしたのですが、うまく反映されません。解決方法をご存知、またはわかる方がいらっしゃいましたら、ご教授下さい。
開発環境は、
Visual Studio 2010 Express + Win7 32bit
です。

以下、作成したプログラムです。

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

'マウスカーソルをコピー
System.IO.File.Copy("C:\test\a.ani", "C:\Windows\Cursors\a.ani", True)

'レジストリ書き込み
Dim editKey As String = String.Concat("%SystemRoot%\Cursors\", TextBox1.Text)
Dim KeyName As String = String.Concat(WindowsIdentity.GetCurrent().User.ToString(), "\Control Panel\Cursors")
Dim GetValueName As String = "Arrow"

Try
'キーを書き込みで開く
Dim Key As RegistryKey = Registry.Users.OpenSubKey(KeyName, True)

'値を設定
Key.SetValue(GetValueName, editKey, RegistryValueKind.ExpandString)

'キーを閉じる
Key.Close()
Catch ex As NullReferenceException
'エラー処理
End Try

'マウス情報取得
'SystemParametersInfo(SPI_GETMOUSE)で取得
Dim test1() As Integer = testGet()

'マウス情報設定
'SystemParametersInfo(SPI_SETMOUSE)で設定
testSet(test1)

'最初にやってみたもの
testRt = SendMessageTimeout(&HFFFF, &H1A, 0, "Environment", &H2, 5000, 0)

'SendMessageTimeoutでうまくいかなかったため、次にこちらでやってみました。
'testRt = SendMessage(&HFFFF&, &H1A&, 0, 0)

MsgBox("終わり")

End Sub


Declare Auto Function SendMessageTimeout Lib "User32" ( _
ByVal hWnd As Integer, _
ByVal Msg As UInt32, _
ByVal wParam As Integer, _
ByVal lParam As String, _
ByVal fuFlags As UInt32, _
ByVal uTimeout As UInt32, _
ByRef lpdwResult As IntPtr _
) As Long


Declare Function SendMessage Lib "User32.dll" Alias "SendMessageA" ( _
ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, _
ByVal lParam As Integer) As Integer

【追加事項】

取り合えずexeにしてみて、当方テーマが、クラシックテーマにしているので、7デフォルトのテーマに戻して、実行してみましたが、うまくいきませんでした。また、Vistaの環境がありますので、Vistaでやってみましたが、うまくいきませんでした。
Vistaの環境は、Home Premium 32bit
.netFramework 4.0です。
http://msdn.microsoft.com/ja-jp/library/cc429946.aspx
を読む限り、SPI_SETMOUSE/SPI_GETMOUSEはマウスカーソルの移動速度関係のパラメータであってカーソル形状には関係なさそうですが。
システムカーソルの再ロードはSPI_SETCURSORSでは。
あとWM_SETTINGCHANGEはSystemParametersInfoの第4引数に指定すればシステムが自動的に送信するのでは?
■No32149に返信(銀狐さんの記事)
> '最初にやってみたもの
> testRt = SendMessageTimeout(&HFFFF, &H1A, 0, "Environment", &H2, 5000, 0)
>
> 'SendMessageTimeoutでうまくいかなかったため、次にこちらでやってみました。
> 'testRt = SendMessage(&HFFFF&, &H1A&, 0, 0)

  うまくいかなかったとは?
  リターン値は吟味しましたか?
  リターン値がNGの場合、GetLastError()して、エラー内容取得した
  結果はどうなってましたか?

  あと、SendMessegaeTime API の、最後のパラメータですが、一応、
  『0』にはせず、値を取得するようにしてみて下さい。

● 本来、マウスポインターの変更は、PC再起動を必要とする機能の
  はずなので・・・

  最低でもログオフ=>ログオンさせないと、レジストリの再ロード
  が行わず、更新結果が反映されない。と言うことだと思います。

※ 要はシステムがレジストリの再ロードを行えば、反映された結果が
  得られるということ。

※ 以前にも似た話でカキコしたことがあったのですが・・・
  検索すれば、私の投稿記事がヒットするかも。
  方法としては2点
  どちらも、オススメしません・・・何かあっても自己責任で!
  1. 起動しているプロセスの『explorer.exe』をすべて強制停止
    させ、無くなったら、explorer.exe を1個起動させる。
    これでレジストリが再ロードされる。
    ただし、他に多大な影響を受けるソフトウェアがあるかもし
    れない。
  2. レジストリハイブのサイロードのAPIを呼んでみる。
    NT時代にこのAPIが追加されたはず。今も使えるかは未確認。
    ※ APIはご自身で調べてみて下さい。
  上記2点のうち、1.の方で『できた』と言う回答があった。

以上。参考まで
Hongliangさん・オショウさん
返信ありがとうございました。

結果的に、ご指摘頂いてうまくいきました。
最後にうまく動いたコードを記載致します。

まずはご指摘頂いた箇所から答えさせて頂きます。

Hongliangさんのご指摘
>SPI_SETMOUSE/SPI_GETMOUSEはマウスカーソルの移動速度関係のパラメータであってカーソル形状には関係なさそうですが
これについては、「SystemParametersInfo」を使用すること自体始めてで、調べて、どこかで見つけて、記載したものです。この辺は色々と自分が至らなかったということです。

>WM_SETTINGCHANGEはSystemParametersInfoの第4引数に指定すればシステムが自動的に送信するのでは?
これも上記と同じ理由です。

オショウさんのご指摘
>うまくいかなかったとは?
プログラムは正常終了し、マウスカーソルに変更がなかったということです。

>リターン値がNGの場合、GetLastError()して、エラー内容取得した結果はどうなってましたか?
この辺も至らなく、ご指摘頂いて、「GetLastError()」は初めて知りました。

>あと、SendMessegaeTime API の、最後のパラメータですが、一応、『0』にはせず、値を取得するようにしてみて下さい。
これは、一度intger型で取得するようにしたのですが、「0」のままでした。(リテラル値に、0を設定しています。)

>本来、マウスポインターの変更は、PC再起動を必要とする機能のはずなので・・・
これについては、Windowsそのものでマウスポインターを変更しても、PC再起動は不要で行っているので、できるかなと思い、ネットで調べたら、できるみたいな記載があったので、チャレンジしてみました。


以下、成功したコードです。(Importは、レジストリ関連で使用しています。)
Imports Microsoft.Win32
Imports System.Security.Principal

Public Class Form1

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

'カーソルを所定のフォルダにコピー
System.IO.File.Copy("C:\Windows\Cursors\a.ani", "C:\test\a.ani", True)

'レジストリに書き込む値を設定
Dim editKey As String = String.Concat("%SystemRoot%\Cursors\", TextBox1.Text)

' 操作するレジストリ・キーの名前
Dim KeyName As String = String.Concat(WindowsIdentity.GetCurrent().User.ToString(), "\Control Panel\Cursors")
'処理対象のレジストリの値の名前
Dim GetValueName As String = "Arrow"

Try
'レジストリ操作
Dim Key As RegistryKey = Registry.Users.OpenSubKey(KeyName, True)
Key.SetValue(GetValueName, editKey, RegistryValueKind.ExpandString)
Key.Close()
Catch ex As NullReferenceException
'エラー処理
End Try

'レジストリ反映
If (SetCursors() = False) Then
'失敗
End If

End Sub


'APIでマウスの情報を取得
Declare Function SystemParametersInfo Lib "User32" Alias "SystemParametersInfoA" (ByVal uAction As Integer, ByVal uparam As Integer, lpvParam As Integer, ByVal fuWinIni As Integer) As Integer
Function SetCursors()

'反映し、処理結果を返却(SPI_SETCURSORS)
Return SystemParametersInfo(87, 0, 0, &H2)
End Function
End Class


改めて、Hongliangさん・オショウさん
ありがとうございました。
解決済み!

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