Announcement

Collapse
No announcement yet.

Open and Close Browser Fails

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Open and Close Browser Fails

    With the code below I open a browser with ShellExecuteEX. Then, to close the browser, I tried TerminateProcess and ExitProcess with the returned .hProcess value. Neither worked and I'm not sure why.

    To do the same task in EZFree, I opened the browser with ShellExecute. Then, to close the browser I detected the Window in the center of the screen and sent it an SC_Close message. It almost always works, but the assumption that the center of the desktop is covered by the browser is not guaranteed, hence the reason for trying something different.

    Code:
    'Compilable Example:
    #Compile Exe
    #Dim All
    %Unicode = 1
    #Include "Win32API.inc"
    
    Enum Equates Singular
       IDC_Open = 500
       IDC_Close
    End Enum
    
    Global hDlg As Dword
    Global SEI As ShellExecuteInfo
    
    Function PBMain() As Long
       Dialog New Pixels, 0, "ShellExecuteEX Test",300,300,400,50, %WS_OverlappedWindow To hDlg
       Control Add Button, hDlg, %IDC_Open,"Open", 20,10,70,20
       Control Add Button, hDlg, %IDC_Close,"Close", 100,10,70,20
       Dialog Show Modal hDlg Call DlgProc
    End Function
    
    CallBack Function DlgProc() As Long
       Select Case Cb.Msg
          Case %WM_Command
             Select Case Cb.Ctl
                Case %IDC_Open  : OpenBrowser
                Case %IDC_Close : Beep
                   'TerminateProcess SEI.hProcess, 0  'does not close the browser
                   'ExitProcess SEI.hProcess          'does not close the browser
    
             End Select
       End Select
    End Function
    
    Sub OpenBrowser
       Local iResult As Long
       Local lpVerb, lpFile, lpParameters As WStringZ * 256
    
       lpVerb = "Open"
       lpFile ="http://www.garybeene.com"
    
       SEI.cbSize       = SizeOf(SEI)
       SEI.fmask        = %SEE_MASK_NOCLOSEPROCESS
       SEI.hWnd         = hDlg
       SEI.lpVerb       = VarPtr(lpVerb)
       SEI.LpFile       = VarPtr(lpFile)
       SEI.lpParameters = VarPtr (lpParameters)
       SEI.lpDirectory  = %NULL
       SEI.nShow        = %SW_ShowMaximized
       SEI.hInstApp     = 0
       SEI.lpIdList     = %NULL
       SEI.lpClass      = %NULL
       SEI.hkeyClass    = %NULL
       SEI.dwHotKey     = %NULL
    '   SEI.item         = %NULL
       SEI.hProcess     = 0       ' will be updated by ShellExecuteEx
    
       iResult = ShellExecuteEx(SEI)
    
       Dialog Set Text hDlg, "ShellExecuteEX Test: " + Str$(iResult) + Str$(SEI.hProcess)
    
    End Sub

  • #2
    Take a look at Task Manager or Process Explorer and see how many instances of your browser are running

    Comment


    • #3
      Good grief - Task Manager says 6 copies are open.

      When I use "Close" in the code above, the count in does not change.

      The number of copies of Chrome in Task Manager sometimes, but not always, changes with the addition or removal of a TAB.

      What does all that mean?

      So what would be the appropriate was of programmatically closing Chrome (or whichever browser is the default that opens with ShellExecuteEX?

      There must be a gap in my education somewhere!

      Comment


      • #4
        To quote one of millions of explanations you can find on the web:
        "There is nothing actually wrong with your browsers. It is quite normal nowadays for a browser to start many processes.

        Browsers nowadays are among the most resource hungry applications on your PC. They are multi-threaded, the main exe is on one process, video processing on another, audio on another each tab will have its own process and so on . . .

        This is done so your browser does not crash your system, with 6 - 8 tabs open a modern browser can have 12 processes running and use 1GB of RAM!


        I suppose you "could" iterate through running processes and terminate any that have the browser's name?

        Comment


        • #5
          You can try controlling that browser by running it in its own thread of execution, as I did here:

          https://forum.powerbasic.com/forum/u...pb-cc-programs

          (Ignore the "PB/CC" in the thread title. This will work in a GUI program exactly the same way).. No reason no to use this additional thread for the ShellExecuteEx() call.

          That might make controlling the browser easier.

          OR....

          The process handle returned by ShellExecuteEx() may not have terminate permission.. Try something like GetProcessID() against the handle returned by ShellExeciuteEx and obtaining a new handle with the correct permissions using OpenProcess()

          It's a thought.
          Michael Mattias
          Tal Systems (retired)
          Port Washington WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #6
            Hi Gary

            When trying TerminateProcess and ExitProcess, what are the return values of those functions? Your code doesn’t seem to capture or evaluate that.

            Comment


            • #7
              Use of embedded browser to give you total control?
              <b>George W. Bleck</b>
              <img src='http://www.blecktech.com/myemail.gif'>

              Comment


              • #8
                Howdy, George!

                While I use an embedded browser in many apps, my experience is that it has limits on how well it displays some websites, particularly when accessing financial websites. So, I try to limit the use of an embedded browser to situations where I control the information to be displayed.



                Comment


                • #9
                  Howdy, Stuart!

                  Yes, I could iterate but first I'd have to do some checking to figure out which browser was opened. Or, I suppose I could just iterate for all "known" browser names.

                  ... added ... but I read on various websites that both TerminateProcess and ExitProcess both have potential undesirable secondary effects. Not sure I understand them clearly at this point, but the use of either doesn't seem to be an easy, automatic decision.

                  Comment


                  • #10
                    Hey Gary

                    This is from MS about ShellExecuteInfo and might explain why TerminateProcess and ExitProcess aren’t working for you. Is it returning a handle or a NULL?

                    hProcess

                    Type: HANDLE

                    A handle to the newly started application. This member is set on return and is always NULL unless fMask is set to SEE_MASK_NOCLOSEPROCESS. Even if fMask is set to SEE_MASK_NOCLOSEPROCESS, hProcess will be NULL if no process was launched. For example, if a document to be launched is a URL and an instance of Internet Explorer is already running, it will display the document. No new process is launched, and hProcess will be NULL.

                    Note: ShellExecuteEx does not always return an hProcess, even if a process is launched as the result of the call. For example, an hProcess does not return when you use SEE_MASK_INVOKEIDLIST to invoke IContextMenu.

                    Comment


                    • #11
                      Howdy, MCM.

                      After a quick look at your code, I'm not sure if I understand your suggestion. Can you expand on your thought?

                      Comment


                      • #12
                        Howdy, Michael!

                        The code does post the value of hProcess in the Dialog caption. It shows as a positive value.(around 1500) so I take that to mean that the process was started (we know it was because the browser starts) and that hProcess was valid.

                        I assume there is a way to validate whether hProcess is a valid process?

                        Comment


                        • #13
                          Hey Gary

                          I’m working from my iPad with no access to Windows or compiler. If the return value isn’t NULL, I’d say you have a valid process handle. So that answers that.

                          I’m glad I’m not the only one confused by MCM thought/code example. I couldn’t tell if he’s suggesting using a thread to open another Window and using said window to ShellExecuteEx or use thread to do a ShellExecuteEx. So I’ll also be interested in his response.

                          As far as Stuart’s suggestion, wouldn’t that close all the browsers and not just the one that you started from your app? I was confused about that, but I get confused easily sometimes!!

                          Comment


                          • #14
                            Originally posted by Gary Beene View Post
                            Howdy, Stuart!

                            Yes, I could iterate but first I'd have to do some checking to figure out which browser was opened. .
                            I've posted code here a few times that gives the full path and exe name of the default broswer

                            Comment


                            • #15
                              Howdy, Stuart!

                              Yep, and now that you've made me think about it, I've previously used a function from Jose called AfxGetDefaultBrowserPath from afxpath.inc that does the trick.

                              Code:
                              #Include "AfxPath.inc"
                              BrowserEXE$$ = AfxGetDefaultBrowserpath
                              And, Michael,
                              I posted about the same time as you that I would have to get the default browser ... which would solve the dilemma you mention.

                              Comment


                              • #16
                                Hey Gary

                                I haven’t done a search for it. But isn’t there a function that returns all the Window handles and a part of what’s returned is the process handle. Meaning you loop through the Window Handles until you find your matching process handle. From there you know the Window handle and can send it the SC_Close message. I could be completely wrong about that, but for some reason it seems like I’ve seen that here in the forums before.

                                Comment


                                • #17
                                  Originally posted by Michael Rice View Post
                                  I’m glad I’m not the only one confused by MCM thought/code example. I couldn’t tell if he’s suggesting using a thread to open another Window and using said window to ShellExecuteEx or use thread to do a ShellExecuteEx. So I’ll also be interested in his response.
                                  Just another one of his links to 20 year old code that's irrelevant to the issue at hand.

                                  Comment


                                  • #18
                                    Hey Gary

                                    I still don’t have access to my Windows computer or the compilers and won’t for several days yet. But I “think” I’ve found the pieces of the puzzle that had jumped into my mind (see post #16).

                                    First, I’m making the assumption that if you had the window handle for the browser that your program started...you could send it a close message to close that same browser. Is that true?

                                    ShellExecuteEx in your program is giving you a Process ID, but not a Window Handle. There’s no WinAPI function (that I’m aware of) for getting a Window Handle from a Process ID for the simple reason that a process could have more than one window...

                                    So the WinAPI functions that I think that you need are:

                                    One from this family:
                                    FindWindowA,FindWindowExA,FindWindowW,FindWindowExW
                                    and
                                    GetWindowThreadProcessId

                                    I think the logic goes something like this:
                                    You call FindWindow to enumerate the windows and pass each Window Handle returned to GetWindowThreadProcessId until the Process ID matches the same Process ID that you received back from ShellExecuteEx. Once you have a match on that...you now have your Window Handle. Clear as mud...right???

                                    I’m like 99.9% sure there’s example code here on the forum. Didn’t one of the major contributors here on the PB forum write a utility called gbThreads? 😂 I’m thinking a search using that utility with FindWindow AND GetWindowThreadProcessId appearing in the same PB thread would probably find you examples of what you’re looking for.

                                    Since your code contains this statement:
                                    SEI.hWnd = hDlg
                                    I believe that you want to use that handle in your call to FindWindow.

                                    If I’m wrong about sending a message to a Window Handle to close the browser...well heck NONE of this really applies!! :-((

                                    I know there’s a whole lot of assuming that I’m doing here. I wish I had some way to test before posting any of this.

                                    Comment


                                    • #19
                                      Originally posted by Stuart McLachlan View Post
                                      Just another one of his links to 20 year old code that's irrelevant to the issue at hand.
                                      Hey Stuart

                                      I really didn’t want to just immediately jump to that conclusion... A few weeks back a member here on the forums was asking for help figuring something out. On at least 3 occasions across 2 threads, I directed them to what I believed was example code that could be updated and used to do exactly what they were looking for. Each time, I was responded to by the OP stating that wasn’t what they were trying to do. Finally I gave up, grabbed the example code I had directed them to...changed the code as I had suggested and posted a total working example for them. I also grabbed some code from yet another member that just happened to get posted at that same time...and created yet another version using drag-n-drop.

                                      I’m sad to say that it wasn’t until 5 minutes ago that I see now that the OP acknowledged that it was indeed what they were trying to do and posted a big thank you!! Unfortunately that doesn’t say much positive about me for not checking back before just now!!

                                      So no, I really didn’t want to just assume something about MCM’s suggestion. So I was glad when Gary asked him to elaborate on his suggested code. Who knows maybe he’s seeing something we are missing.

                                      Comment


                                      • #20
                                        but I read on various websites that both TerminateProcess and ExitProcess both have potential undesirable secondary effects. Not sure I understand them clearly at this point, but the use of either doesn't seem to be an easy, automatic decision.
                                        TerminateProcess() ends another process. ExitProcess() ends THIS process. Should not really be a decision which to use. If you want to terminate an external process, you use TerminateProcess().


                                        First, I’m making the assumption that if you had the window handle for the browser that your program started...you could send it a close message to close that same browser. Is that true?
                                        A browser application may have many windows; there is no "The" window handle. While WM_CLOSE will likely cause the external app to end, there is no guarantee. From your own experience you (should) know you can intercept and 'eat' any WM_CLOSE message your programs' windows may receive.

                                        I’m glad I’m not the only one confused by MCM thought/code example. I couldn’t tell if he’s suggesting using a thread to open another Window and using said window to ShellExecuteEx or use thread to do a ShellExecuteEx.
                                        I am just offering options. I am saying it MAY be easier to manage the external (browser) program if it is running in it's own thread of execution.

                                        Or maybe, the attempt to TerminateProcess() is failing because the process handle returned by ShellExecuteEx() in the SHELLEXECUTEINFO structure does not have sufficient permissions.

                                        Of course, coding to obtain the success or failure of TerminateProcess(), and on failure getting the value of of GetLastError() would probably be a better place to start debugging.

                                        MCM
                                        Michael Mattias
                                        Tal Systems (retired)
                                        Port Washington WI USA
                                        [email protected]
                                        http://www.talsystems.com

                                        Comment

                                        Working...
                                        X