WM_SETTINGSCHANGE

Started by JTaylor, August 11, 2015, 10:23:41 AM

Previous topic - Next topic

JTaylor

The goal is to make a change to the registry regarding proxy settings (turn on/off) and it take effect without reloading the browser.   The following code seems to return a valid response and there are no errors so I like to think I am doing it right.  The problem is that it doesn't accomplish the goal.  Some possible reasons are:


  • This change is not considered a "top-level window" change.
  • I'm doing it wrong.
  • Something else I'm not considering.


Anyone have a suggestion?  Thanks.

Jim

Code (winbatch) Select

  GoSub Load_Routines
  Load_SetChange()
  SetChangeLoader = ObjectClrNew( 'SetChange.User32Utils' )
  msg = SetChangeLoader.Notify_SettingChange
  Message("HEY",msg)

:LOAD_ROUTINES

#DefineSubRoutine Load_SetChange()

;***************************************************************************
;**  Run C# in memory using WinBatch - Use Namespace.Class defined in CSharpeSource
;**
;** Purpose:  Run C# in memory using WinBatch - Using Namespace.Class defined in CSharpeSource
;** Inputs:
;** Outputs: Results in message
;**
;** Developer: Deana Falk 2014.04.14
;***************************************************************************

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Load assemblies into the WinBatch process.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; mscorlib assembly is automatically loaded by WinBatch when the CLR is loaded.

  ObjectClrOption("use","System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Compiles the c# code in Memory
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  objCSharp = ObjectClrNew('Microsoft.CSharp.CSharpCodeProvider')
  objParams = ObjectClrNew('System.CodeDom.Compiler.CompilerParameters')
  objParams.GenerateInMemory = ObjectType( "VT_BOOL", 1 ) ;TRUE
 
  objParams.ReferencedAssemblies.Add("System.dll")

;Make sure the cSharp code includes both namepspace and class that can be later used by ObjectCLRNew
  cSharpSource =               `using System;                                                                        `:@LF
  cSharpSource = cSharpSource :`using System.Runtime.InteropServices;                                                `:@LF
  cSharpSource = cSharpSource :`namespace SetChange                                                                  `:@LF
  cSharpSource = cSharpSource :`{                                                                                    `:@LF
  cSharpSource = cSharpSource :`public static  class User32Utils                                                     `:@LF
  cSharpSource = cSharpSource :`    {                                                                                `:@LF
  cSharpSource = cSharpSource :`        static IntPtr HWND_BROADCAST = new IntPtr(0xffffL);                          `:@LF
  cSharpSource = cSharpSource :`        static IntPtr WM_SETTINGCHANGE = new IntPtr(0x1a);                           `:@LF
  cSharpSource = cSharpSource :`        enum SendMessageTimeoutFlags : uint                                          `:@LF
  cSharpSource = cSharpSource :`        {                                                                            `:@LF
  cSharpSource = cSharpSource :`            SMTO_NORMAL = 0x0000,                                                    `:@LF
  cSharpSource = cSharpSource :`            SMTO_BLOCK = 0x0001,                                                     `:@LF
  cSharpSource = cSharpSource :`            SMTO_ABORTIFHUNG = 0x2,                                                  `:@LF
  cSharpSource = cSharpSource :`            SMTO_NOTIMEOUTIFNOTHUNG = 0x0008                                         `:@LF
  cSharpSource = cSharpSource :`        }                                                                            `:@LF
  cSharpSource = cSharpSource :`        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]       `:@LF
  cSharpSource = cSharpSource :`        static extern IntPtr SendMessageTimeout(IntPtr hWnd,                         `:@LF
  cSharpSource = cSharpSource :`                                                uint Msg,                            `:@LF
  cSharpSource = cSharpSource :`                                                UIntPtr wParam,                      `:@LF
  cSharpSource = cSharpSource :`                                                UIntPtr lParam,                      `:@LF
  cSharpSource = cSharpSource :`                                                SendMessageTimeoutFlags fuFlags,     `:@LF
  cSharpSource = cSharpSource :`                                                uint uTimeout,                       `:@LF
  cSharpSource = cSharpSource :`                                                out UIntPtr lpdwResult);             `:@LF
  cSharpSource = cSharpSource :`        internal static IntPtr Notify_SettingChange()                                `:@LF
  cSharpSource = cSharpSource :`        {                                                                            `:@LF
  cSharpSource = cSharpSource :`            UIntPtr result;                                                          `:@LF
  cSharpSource = cSharpSource :`            IntPtr  sresult;                                                         `:@LF
  cSharpSource = cSharpSource :`            sresult = SendMessageTimeout(HWND_BROADCAST, (uint)WM_SETTINGCHANGE, UIntPtr.Zero, UIntPtr.Zero, SendMessageTimeoutFlags.SMTO_NORMAL, 1000, out result);                                                                                              `:@LF
  cSharpSource = cSharpSource :`            return sresult;                                                          `:@LF
  cSharpSource = cSharpSource :`        }                                                                            `:@LF
  cSharpSource = cSharpSource :`    }                                                                                `:@LF
  cSharpSource = cSharpSource :`}                                                                                    `:@LF

  objResult = objCSharp.CompileAssemblyFromSource(objParams,cSharpSource)

  ;Compiler Output
  If objResult.Output.Count > 0 Then
    strOutput = ''
    For x = 0 to objResult.Output.Count-1
       If strOutput == "" Then
         strOutput = objResult.Output.Item(x)
       Else
         strOutput = strOutput:@LF:objResult.Output.Item(x)
       EndIf
    Next
    Pause('Compiler Output',strOutput)
  Endif
 
  ; Compiler Errors
  If objResult.Errors.Count > 0 Then
    strErrors = ''
    ForEach ce In objResult.Errors
      ;Pause("Error", ce.ToString())
      If strErrors == "" Then
        strErrors = ce.ToString()
      Else
        strErrors = strErrors:@LF:ce.ToString()
      EndIf
    Next
    Pause('Compiler Errors',strErrors)
    Exit
  EndIf


#EndSubRoutine


Return

....IFICantBYTE

Hi Jim,
maybe you want or need to do it using in memory compilation of c# script???

BUT if not, and you just want to get the actual job done (accept any registry proxy changes without reloading the browser) then there are a couple of examples in the Tech Database using a dll call to Wininet.dll and the InternetSetOptionA function in it.

Do a search for articles:
W18412 "Refresh Active Internet Explorer Session"
and
W17790 "Dynamically Change Proxy Settings for an Existing IE Session"

Regards,
....IFICantBYTE

Nothing sucks more than that moment during an argument when you realize you're wrong. :)

JTaylor

Hmmmmmmmmmmm....maybe I'm misunderstanding but that is what the code I posted does.   I'm was hoping someone could tell me why it doesn't work even though it acts like it does.

Thanks for the other links.  I'll take a look.   Would still be interested in making the other work though.

Thanks again.

Jim

....IFICantBYTE

I would tend to disagree. .. it only looks like it does half of what the others do.., it appears to only send a general systems setting change to all open windows, not the internet options set change found in the wininet.dll
Regards,
....IFICantBYTE

Nothing sucks more than that moment during an argument when you realize you're wrong. :)

JTaylor

Okay.  That is what I was wondering.  I knew one possibility was that it didn't see these changes as part of the "top-level windows" changes but I have found numerous postings which say this approach works for what I was wanting to do.

Thanks again for the reminder on the other links.  I had forgotten about those and actually used that approach in a few scripts in years past.

Jim

td

And the entire C# source could be accomplished with a WinBatch Script one liner...
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

Which would be?



Here is what I used for the moment but happy to shorten it.

Code (winbatch) Select



   hWinInet = DllLoad(DirWindows(1):"WININET.DLL")
   INETOPT_SETTINGS_CHANGED  = 39
   INETOPT_REFRESH           = 37
   DllCall(hWinInet, long:"InternetSetOptionA", long:0, long:INETOPT_SETTINGS_CHANGED, long:0, long:0)
   DllCall(hWinInet, long:"InternetSetOptionA", long:0, long:INETOPT_REFRESH,          long:0, long:0)
   DllFree(hWinInet)
   

td

I was referring specifically to the user32 function SendMessageTimeout in the C# source you posted.  That can be done in a single line DllCall or perhaps simply using IntControl 59. The WinBatch DllCalls you just posted perform a slightly different task and appear to be based on one of the Tech Database article mentioned above.  I probably shouldn't admit to it but FWIW, the example in the second article looks like it is lifted from  a script I wrote many years ago.  Didn't even know it was placed in the the Tech Database and it is kind of amazing that it still works.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

IntControl 59 *may* work.  Seems to be a long delay which kills it for my needs.  Could be something else making it happen I guess???

In any event...the last thing I posted does the job.  Thanks all.

Jim

td

IntControl 59 has a maximum 5 second delay that would only go into affect if a process with a message pump is not pulling messages from its message queue.  In other words the process is hung for some reason.  A one line DllCall would still do what all the c# code does.    But as you indicated SendMessageTimeout  does not perform what the InternetSetOption function does.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

DAG_P6

Jim,

Quote from: JTaylor on August 12, 2015, 08:43:01 PM

In any event...the last thing I posted does the job.  Thanks all.

As I scrolled my way down, I kept asking myself why you had all that dynamically compiled C# code to do something that would be so much more simply accomplished by DLLCall. I'm glad to know that the simpler solution worked for you. I have successfully used the same scheme to register, then immediately use, event source IDs.
David A. Gray
You are more important than any technology.