为什么SendMessageTimeout不更新环境变量?

Ste*_*ger 4 .net vb.net pinvoke environment-variables

问题:我有一个安装程序,它会随程序安装一些本机dll.dll位于一个单独的文件夹中,我将其添加到路径环境变量中.

这已成功完成,如果我检查Windows系统设置,变量将显示在路径中.

但是,如果我启动命令行程序/服务,它说dll未找到...

我用set命令检查环境变量路径,我的文件夹不在那里.

如果我做

SET path = %path%;my/folder/here/
Run Code Online (Sandbox Code Playgroud)

然后启动我的程序,然后它的工作原理.

根据这篇MS KB文章,这是因为需要重新启动计算机.

除非我这样做

SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);            
Run Code Online (Sandbox Code Playgroud)

现在我只使用下面的代码,但错误消息仍然存在.%path%中的我的文件夹拼写正确,我检查了一下.

我究竟做错了什么 ?

' http://www.pinvoke.net/default.aspx/Enums/SendMessageTimeoutFlags.html '
<Flags()> _
Public Enum SendMessageTimeoutFlags
    SMTO_NORMAL = 0
    SMTO_BLOCK = 1
    SMTO_ABORTIFHUNG = 2
    SMTO_NOTIMEOUTIFNOTHUNG = 8
End Enum    

' http://ghouston.blogspot.com/2005/08/how-to-create-and-change-environment.html '
Public Const HWND_BROADCAST As Integer = &HFFFF
Public Const WM_SETTINGCHANGE As Integer = &H1A    

' http://pinvoke.net/default.aspx/user32.SendMessageTimeout '
<System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
Public Shared Function SendMessageTimeout(ByVal windowHandle As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByVal flags As SendMessageTimeoutFlags, ByVal timeout As Integer, ByRef result As IntPtr) As IntPtr
End Function    

' http://support.microsoft.com/?kbid=104011 '
' http://blog.jtbworld.com/2005/11/set-environment-variable-using-vbnet.html '
Sub UpdatePath()
    Dim result As Integer
    ' SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,(LPARAM) "Environment", SMTO_ABORTIFHUNG,5000, &dwReturnValue); '   

    ' CType("Environment", System.IntPtr) '
    Dim s As String = New String("Environment")
    Dim ptr As IntPtr = Runtime.InteropServices.Marshal.StringToHGlobalUni(s)

    'SendMessageTimeout(CType(HWND_BROADCAST, System.IntPtr), WM_SETTINGCHANGE, 0, ptr, SendMessageTimeoutFlags.SMTO_BLOCK Or SendMessageTimeoutFlags.SMTO_ABORTIFHUNG Or SendMessageTimeoutFlags.SMTO_NOTIMEOUTIFNOTHUNG, 5000, result) '
    SendMessageTimeout(CType(HWND_BROADCAST, System.IntPtr), WM_SETTINGCHANGE, 0, ptr, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 5000, result)
End Sub
Run Code Online (Sandbox Code Playgroud)

Sil*_*Net 11

我怀疑它与Unicode/ANSI处理有关; 基本系统似乎想要ANSI中的"环境",但是包括shell在内的大多数应用程序都需要Unicode,如果它们完全承认它的话.在CI中,只需将其发送为:

SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 1000, NULL );
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) L"Environment", SMTO_ABORTIFHUNG, 1000, NULL );
Run Code Online (Sandbox Code Playgroud)

这很好地完成了工作.

在VB.Net中,我认为你的等价物是:

Dim s As String = New String("Environment")
Dim ptrA As IntPtr = Runtime.InteropServices.Marshal.StringToHGlobalAnsi(s)
Dim ptrU As IntPtr = Runtime.InteropServices.Marshal.StringToHGlobalUni(s)
SendMessageTimeout(CType(HWND_BROADCAST, System.IntPtr), WM_SETTINGCHANGE, 0, ptrA, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 5000, result)
SendMessageTimeout(CType(HWND_BROADCAST, System.IntPtr), WM_SETTINGCHANGE, 0, ptrU, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 5000, result)
Run Code Online (Sandbox Code Playgroud)

(如果你打算使用非托管代码,别忘了释放你的记忆.)