Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't SendMessageTimeout update the environment variables?

Question: I have an installer, and it installs some native dll's along with the program. The dll's are in a separate folder, which I added to the path environment variable.

That was done successfully, and the variable shows up in path if I check the windows system settings.

However, if I start the command line program/service, it says dll's not found...

I check the environment variable path with the set command, and my folder is not in there.

If I do

SET path = %path%;my/folder/here/

And start my program after that, then it works.

According to this MS KB article this is because the computer would need to be restarted.

unless I do

SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);            

Now I did just that, using the below code, but the error message persists. My folder in %path% is correctly spelled, I checked that.

What am I doing wrong ?

' 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
like image 204
Stefan Steiger Avatar asked Feb 11 '11 11:02

Stefan Steiger


1 Answers

I suspect it has to do with Unicode/ANSI processing; the base system seems to want "Environment" in ANSI but most apps including the shell want Unicode, if they acknowledge it at all. In C I just send it as:

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 );

Which gets the job done nicely.

In VB.Net I suppose the equivalent for you would be:

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)

(And don't forget to free your memory if you're going to use unmanaged code.)

like image 113
SilverbackNet Avatar answered Oct 20 '22 10:10

SilverbackNet