Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Getting an HWND from an HINSTANCE

Getting an HWND from an HINSTANCE

Scheduled Pinned Locked Moved C / C++ / MFC
comloungequestion
13 Posts 4 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    Harold Bamford
    wrote on last edited by
    #1

    Greetings, I need to get an HWND but all I have is an HINSTANCE. There must be some simple way to make the conversion but my brain is blocked. This can't be that difficult! :(( What I am doing is using ShellExecuteEx() to open up a PDF file. I then want to send keyboard messages to this new process to make it go to Page XXX. (Yes, I know that if I had the full Acrobat I could do this with OLE or even DDE. But I don't. And the alleged pdf ActiveX control is only intended to work within a browser. Sigh...) I need to be able to take the hProcess field from the SHELLEXECUTEINFO, as filled in by ShellExecuteEx(), and use it to wait for the new process to stabilize and then send the appropriate WM_KEYDOWN and WM_CHAR messages. Failing that, I would like to be able to enumerate all the windows and find the one corresponding to the one I spawned. I am looking for a general solution rather than looking for a window containing "Acrobat Reader" in its title bar. Can anybody give me a clue? Thanks a lot!void CIOGuidesView::OnButton1() { CString filename("PDF Files\\751018a.pdf"); HANDLE hProcess = NULL; SHELLEXECUTEINFO shellInfo; ::ZeroMemory(&shellInfo, sizeof(shellInfo)); shellInfo.cbSize = sizeof(shellInfo); shellInfo.lpVerb = "open"; shellInfo.lpFile = filename; shellInfo.fMask = SEE_MASK_NOCLOSEPROCESS; if(::ShellExecuteEx(&shellInfo)) { /* success */ hProcess = shellInfo.hProcess; } /* success */ else { ShowLastError("ShellExecuteEx Failed"); return; } // I'm not convinced this is actually working. I think that it may // actually be interfering with AcroRd32 int reason = WaitForInputIdle(hProcess,INFINITE); switch(reason) { case 0: MessageBox("subprocess now accepting user input"); break; case WAIT_TIMEOUT: MessageBox("Wait timeout"); break; case 0xFFFFFFFF: ShowLastError("WaitForInputIdle Failure"); break; } // This doesn't seem to work. It gets random text from current process // rather than new process. And it changes each time I try it! char title[1000]; ::GetWindowText((HWND)hProcess,title,sizeof(title)); MessageBox(title,"Subprocess Window Title"); }

    P 1 Reply Last reply
    0
    • H Harold Bamford

      Greetings, I need to get an HWND but all I have is an HINSTANCE. There must be some simple way to make the conversion but my brain is blocked. This can't be that difficult! :(( What I am doing is using ShellExecuteEx() to open up a PDF file. I then want to send keyboard messages to this new process to make it go to Page XXX. (Yes, I know that if I had the full Acrobat I could do this with OLE or even DDE. But I don't. And the alleged pdf ActiveX control is only intended to work within a browser. Sigh...) I need to be able to take the hProcess field from the SHELLEXECUTEINFO, as filled in by ShellExecuteEx(), and use it to wait for the new process to stabilize and then send the appropriate WM_KEYDOWN and WM_CHAR messages. Failing that, I would like to be able to enumerate all the windows and find the one corresponding to the one I spawned. I am looking for a general solution rather than looking for a window containing "Acrobat Reader" in its title bar. Can anybody give me a clue? Thanks a lot!void CIOGuidesView::OnButton1() { CString filename("PDF Files\\751018a.pdf"); HANDLE hProcess = NULL; SHELLEXECUTEINFO shellInfo; ::ZeroMemory(&shellInfo, sizeof(shellInfo)); shellInfo.cbSize = sizeof(shellInfo); shellInfo.lpVerb = "open"; shellInfo.lpFile = filename; shellInfo.fMask = SEE_MASK_NOCLOSEPROCESS; if(::ShellExecuteEx(&shellInfo)) { /* success */ hProcess = shellInfo.hProcess; } /* success */ else { ShowLastError("ShellExecuteEx Failed"); return; } // I'm not convinced this is actually working. I think that it may // actually be interfering with AcroRd32 int reason = WaitForInputIdle(hProcess,INFINITE); switch(reason) { case 0: MessageBox("subprocess now accepting user input"); break; case WAIT_TIMEOUT: MessageBox("Wait timeout"); break; case 0xFFFFFFFF: ShowLastError("WaitForInputIdle Failure"); break; } // This doesn't seem to work. It gets random text from current process // rather than new process. And it changes each time I try it! char title[1000]; ::GetWindowText((HWND)hProcess,title,sizeof(title)); MessageBox(title,"Subprocess Window Title"); }

      P Offline
      P Offline
      Phil J Pearson
      wrote on last edited by
      #2

      Casting hProcess to an HWND will certainly not do what you want. You may need to EnumWindows and examine each one somehow to see if it's the one you want. I can't think of a way to get a process handle or a process id from a window handle but there must be a way. Then for each window handle EnumWindows gives you you could just see if it belongs to the process you just started. Simple! ;)


      The opinions expressed in this communication do not necessarily represent those of the author (especially if you find them impolite, discourteous or inflammatory).

      C 1 Reply Last reply
      0
      • P Phil J Pearson

        Casting hProcess to an HWND will certainly not do what you want. You may need to EnumWindows and examine each one somehow to see if it's the one you want. I can't think of a way to get a process handle or a process id from a window handle but there must be a way. Then for each window handle EnumWindows gives you you could just see if it belongs to the process you just started. Simple! ;)


        The opinions expressed in this communication do not necessarily represent those of the author (especially if you find them impolite, discourteous or inflammatory).

        C Offline
        C Offline
        Chris Richardson
        wrote on last edited by
        #3

        GetWindowThreadProcessId will give you the process ID/thread ID of the process/thread that created the window handle. Chris Richardson

        H 1 Reply Last reply
        0
        • C Chris Richardson

          GetWindowThreadProcessId will give you the process ID/thread ID of the process/thread that created the window handle. Chris Richardson

          H Offline
          H Offline
          Harold Bamford
          wrote on last edited by
          #4

          Chris, Well, I tried enumerating all the windows and using GetWindowThreadProcessId() and it doesn't seem to give me the same process id as obtained from the SHELLEXECUTEINFO structure (updated by ShellExecuteEx()): The enumeration callback:

          class WININFO
          {
          public:
          	CWnd *hWnd;
          	HINSTANCE hInst;
          	CString title;
          	WININFO(CWnd *wnd = NULL, HINSTANCE inst = NULL) {hWnd = wnd; hInst = inst; title = "";}
          };
          typedef CArray<WININFO,WININFO> CArrayWinInfo;
          
          BOOL CALLBACK CIOGuidesView::enumwndfn(HWND hWnd, LPARAM lParam)
          {
          	CIOGuidesView *me = (CIOGuidesView *)lParam;
          	return me->enumwndfn(CWnd::FromHandle(hWnd));
          }
          
          BOOL CIOGuidesView::enumwndfn(CWnd * wnd)
          {
          	WININFO wininfo(wnd);
          
          	wnd->GetWindowText(wininfo.title);
          
          	DWORD ProcessId; 
          	GetWindowThreadProcessId (wnd->GetSafeHwnd(), &ProcessId ); 
          	wininfo.hInst = (HINSTANCE)ProcessId;
          
          	m_WinInfoArray.Add(wininfo);
          
          	return TRUE;
          }
          

          The ShellExecuteEx() call:

          void CIOGuidesView::OnButton1() 
          {
          	CString filename("PDF Files\\751018a.pdf");
          
          	HANDLE hProcess = NULL;
          	SHELLEXECUTEINFO shellInfo;
          	::ZeroMemory(&shellInfo, sizeof(shellInfo));
          	shellInfo.cbSize = sizeof(shellInfo);
          	shellInfo.lpVerb = "open";
          	shellInfo.lpFile = filename;
          	shellInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
          	if(::ShellExecuteEx(&shellInfo))
          	{ /* success */
          		hProcess = shellInfo.hProcess;
          	} /* success */
          	else
          	{
          		ShowLastError("ShellExecuteEx Failed");
          		return;
          	}
          
          
          	int reason = WaitForInputIdle(hProcess,INFINITE);
          	// blah, blah
          

          And then I dumped all the windows whose title began with "Acro" OR those whose hInst matched my hProcess:

          	hProcess=0x01D8  hInst=0x045C  title='Acrobat Reader'
          

          If I understand this, the hProcess and hInst values should have been identical. Ideas?

          C 1 Reply Last reply
          0
          • H Harold Bamford

            Chris, Well, I tried enumerating all the windows and using GetWindowThreadProcessId() and it doesn't seem to give me the same process id as obtained from the SHELLEXECUTEINFO structure (updated by ShellExecuteEx()): The enumeration callback:

            class WININFO
            {
            public:
            	CWnd *hWnd;
            	HINSTANCE hInst;
            	CString title;
            	WININFO(CWnd *wnd = NULL, HINSTANCE inst = NULL) {hWnd = wnd; hInst = inst; title = "";}
            };
            typedef CArray<WININFO,WININFO> CArrayWinInfo;
            
            BOOL CALLBACK CIOGuidesView::enumwndfn(HWND hWnd, LPARAM lParam)
            {
            	CIOGuidesView *me = (CIOGuidesView *)lParam;
            	return me->enumwndfn(CWnd::FromHandle(hWnd));
            }
            
            BOOL CIOGuidesView::enumwndfn(CWnd * wnd)
            {
            	WININFO wininfo(wnd);
            
            	wnd->GetWindowText(wininfo.title);
            
            	DWORD ProcessId; 
            	GetWindowThreadProcessId (wnd->GetSafeHwnd(), &ProcessId ); 
            	wininfo.hInst = (HINSTANCE)ProcessId;
            
            	m_WinInfoArray.Add(wininfo);
            
            	return TRUE;
            }
            

            The ShellExecuteEx() call:

            void CIOGuidesView::OnButton1() 
            {
            	CString filename("PDF Files\\751018a.pdf");
            
            	HANDLE hProcess = NULL;
            	SHELLEXECUTEINFO shellInfo;
            	::ZeroMemory(&shellInfo, sizeof(shellInfo));
            	shellInfo.cbSize = sizeof(shellInfo);
            	shellInfo.lpVerb = "open";
            	shellInfo.lpFile = filename;
            	shellInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
            	if(::ShellExecuteEx(&shellInfo))
            	{ /* success */
            		hProcess = shellInfo.hProcess;
            	} /* success */
            	else
            	{
            		ShowLastError("ShellExecuteEx Failed");
            		return;
            	}
            
            
            	int reason = WaitForInputIdle(hProcess,INFINITE);
            	// blah, blah
            

            And then I dumped all the windows whose title began with "Acro" OR those whose hInst matched my hProcess:

            	hProcess=0x01D8  hInst=0x045C  title='Acrobat Reader'
            

            If I understand this, the hProcess and hInst values should have been identical. Ideas?

            C Offline
            C Offline
            Chris Richardson
            wrote on last edited by
            #5

            The HINSTANCE is not the same as the ID of the process. What you need to do, is use the ID of the process to get a handle to the process, which can be compared directly to the hProcess member of SHELLEXECUTEEX. Something like this:

            BOOL CIOGuidesView::enumwndfn(CWnd * wnd)
            {
            WININFO wininfo(wnd);

            wnd->GetWindowText(wininfo.title);

            DWORD ProcessId;
            GetWindowThreadProcessId (wnd->GetSafeHwnd(), &ProcessId );
            // We open a handle to the process, which can be compared with the handle returned by ShellExecuteEx.
            // Sometime in the future, we must call CloseHandle with the handle returned by OpenProcess...
            HANDLE a_hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, ProcessID );
            wininfo.hInst = (HINSTANCE)a_hProcess;

            m_WinInfoArray.Add(wininfo);

            return TRUE;
            }

            Chris Richardson

            P H 2 Replies Last reply
            0
            • C Chris Richardson

              The HINSTANCE is not the same as the ID of the process. What you need to do, is use the ID of the process to get a handle to the process, which can be compared directly to the hProcess member of SHELLEXECUTEEX. Something like this:

              BOOL CIOGuidesView::enumwndfn(CWnd * wnd)
              {
              WININFO wininfo(wnd);

              wnd->GetWindowText(wininfo.title);

              DWORD ProcessId;
              GetWindowThreadProcessId (wnd->GetSafeHwnd(), &ProcessId );
              // We open a handle to the process, which can be compared with the handle returned by ShellExecuteEx.
              // Sometime in the future, we must call CloseHandle with the handle returned by OpenProcess...
              HANDLE a_hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, ProcessID );
              wininfo.hInst = (HINSTANCE)a_hProcess;

              m_WinInfoArray.Add(wininfo);

              return TRUE;
              }

              Chris Richardson

              P Offline
              P Offline
              Phil J Pearson
              wrote on last edited by
              #6

              Chris Richardson wrote: // We open a handle to the process, which can be compared with the handle returned by ShellExecuteEx. // Sometime in the future, we must call CloseHandle with the handle returned by OpenProcess... Why not close it immediately? Once you got the handle all you need it its value to use for comparison, you don't need to do anything else with it.


              The opinions expressed in this communication do not necessarily represent those of the author (especially if you find them impolite, discourteous or inflammatory).

              C 1 Reply Last reply
              0
              • P Phil J Pearson

                Chris Richardson wrote: // We open a handle to the process, which can be compared with the handle returned by ShellExecuteEx. // Sometime in the future, we must call CloseHandle with the handle returned by OpenProcess... Why not close it immediately? Once you got the handle all you need it its value to use for comparison, you don't need to do anything else with it.


                The opinions expressed in this communication do not necessarily represent those of the author (especially if you find them impolite, discourteous or inflammatory).

                C Offline
                C Offline
                Chris Richardson
                wrote on last edited by
                #7

                Whoops. I guess I had a momentary lapse of brain activity :zzz:. Chris Richardson

                1 Reply Last reply
                0
                • C Chris Richardson

                  The HINSTANCE is not the same as the ID of the process. What you need to do, is use the ID of the process to get a handle to the process, which can be compared directly to the hProcess member of SHELLEXECUTEEX. Something like this:

                  BOOL CIOGuidesView::enumwndfn(CWnd * wnd)
                  {
                  WININFO wininfo(wnd);

                  wnd->GetWindowText(wininfo.title);

                  DWORD ProcessId;
                  GetWindowThreadProcessId (wnd->GetSafeHwnd(), &ProcessId );
                  // We open a handle to the process, which can be compared with the handle returned by ShellExecuteEx.
                  // Sometime in the future, we must call CloseHandle with the handle returned by OpenProcess...
                  HANDLE a_hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, ProcessID );
                  wininfo.hInst = (HINSTANCE)a_hProcess;

                  m_WinInfoArray.Add(wininfo);

                  return TRUE;
                  }

                  Chris Richardson

                  H Offline
                  H Offline
                  Harold Bamford
                  wrote on last edited by
                  #8

                  Chris, I suspected I was mixing apples and oranges. But it still doesn't seem to work.

                  BOOL CIOGuidesView::enumwndfn(CWnd * wnd)
                  {
                  	WININFO wininfo(wnd);
                  		
                  
                  	wnd->GetWindowText(wininfo.title);
                  		
                  
                  	DWORD ProcessId; 
                  	GetWindowThreadProcessId (wnd->GetSafeHwnd(), &ProcessId ); 
                  		
                  
                  	// We open a handle to the process, which can be compared with the handle
                  	// returned by ShellExecuteEx.
                  	HANDLE a_hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, ProcessId );
                  	wininfo.hInst = (HINSTANCE)a_hProcess;
                  	CloseHandle(a_hProcess);  // only need it for comparison purposes
                  		
                  	//wininfo.hInst = (HINSTANCE)ProcessId;  // the wrong way...
                  
                  	m_WinInfoArray.Add(wininfo);
                  
                  	return TRUE;
                  }
                  

                  This still yields no exact matches on hProcess (from ShellExecuteEx) and a_hProcess (from OpenProcess). I am beginning to wonder if AcroRd32.exe does something especially weird. I'll try something with another type of file... I appreciate you looking at this. It has me bamboozled!

                  C 1 Reply Last reply
                  0
                  • H Harold Bamford

                    Chris, I suspected I was mixing apples and oranges. But it still doesn't seem to work.

                    BOOL CIOGuidesView::enumwndfn(CWnd * wnd)
                    {
                    	WININFO wininfo(wnd);
                    		
                    
                    	wnd->GetWindowText(wininfo.title);
                    		
                    
                    	DWORD ProcessId; 
                    	GetWindowThreadProcessId (wnd->GetSafeHwnd(), &ProcessId ); 
                    		
                    
                    	// We open a handle to the process, which can be compared with the handle
                    	// returned by ShellExecuteEx.
                    	HANDLE a_hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, ProcessId );
                    	wininfo.hInst = (HINSTANCE)a_hProcess;
                    	CloseHandle(a_hProcess);  // only need it for comparison purposes
                    		
                    	//wininfo.hInst = (HINSTANCE)ProcessId;  // the wrong way...
                    
                    	m_WinInfoArray.Add(wininfo);
                    
                    	return TRUE;
                    }
                    

                    This still yields no exact matches on hProcess (from ShellExecuteEx) and a_hProcess (from OpenProcess). I am beginning to wonder if AcroRd32.exe does something especially weird. I'll try something with another type of file... I appreciate you looking at this. It has me bamboozled!

                    C Offline
                    C Offline
                    Chris Richardson
                    wrote on last edited by
                    #9

                    It seems that on my machine, OpenProcess is always returning the same value, no matter which ID you give it. That's pretty strange, but there's another way to do this. You could use CreateProcess, instead of ShellExecuteEx. CreateProcess will give you the ID of the process as well as it's handle, so you could directly compare the process ID gotten from GetWindowThreadProcessId with the process ID returned in the PROCESS_INFORMATION struct (from CreateProcess). I'll mess with this approach for a little while longer, and if I can get it to work, I'll let you know. Chris Richardson

                    H 1 Reply Last reply
                    0
                    • C Chris Richardson

                      It seems that on my machine, OpenProcess is always returning the same value, no matter which ID you give it. That's pretty strange, but there's another way to do this. You could use CreateProcess, instead of ShellExecuteEx. CreateProcess will give you the ID of the process as well as it's handle, so you could directly compare the process ID gotten from GetWindowThreadProcessId with the process ID returned in the PROCESS_INFORMATION struct (from CreateProcess). I'll mess with this approach for a little while longer, and if I can get it to work, I'll let you know. Chris Richardson

                      H Offline
                      H Offline
                      Harold Bamford
                      wrote on last edited by
                      #10

                      Chris, I was just about to post a message here saying pretty much the same thing: OpenProcess() is giving the same value for different windows. I checked that they were truly different processes via the Task Manager. I was hoping to avoid CreateProcess() as I like the idea of ShellExecuteEx()'s looking up the default program based on the file type. So I just use an lpVerb of "open" and the lpFile points to the .pdf file and ShellExecuteEx() takes care of everything else. I suppose I can write the code to search the registry and duplicate this but it doesn't sound fun. :(( I don't suppose CreateProcess() does this kind of thing, does it?

                      C J 2 Replies Last reply
                      0
                      • H Harold Bamford

                        Chris, I was just about to post a message here saying pretty much the same thing: OpenProcess() is giving the same value for different windows. I checked that they were truly different processes via the Task Manager. I was hoping to avoid CreateProcess() as I like the idea of ShellExecuteEx()'s looking up the default program based on the file type. So I just use an lpVerb of "open" and the lpFile points to the .pdf file and ShellExecuteEx() takes care of everything else. I suppose I can write the code to search the registry and duplicate this but it doesn't sound fun. :(( I don't suppose CreateProcess() does this kind of thing, does it?

                        C Offline
                        C Offline
                        Chris Richardson
                        wrote on last edited by
                        #11

                        CreateProcess won't do it for you, but you can use a function called SHGetFileInfo to get the exe path for you. Take a look at the SHGFI_ICONLOCATION flag of that function. It will get you the path to the .exe file containing the icon for the passed in .pdf file. Almost assuredly Acrobat Reader stores it's icon inside it's exe file, but this could be verified. If this sounds a little hackish and risky, then the registry stuff isn't all that bad anyways. Good luck with it, Chris Richardson

                        1 Reply Last reply
                        0
                        • H Harold Bamford

                          Chris, I was just about to post a message here saying pretty much the same thing: OpenProcess() is giving the same value for different windows. I checked that they were truly different processes via the Task Manager. I was hoping to avoid CreateProcess() as I like the idea of ShellExecuteEx()'s looking up the default program based on the file type. So I just use an lpVerb of "open" and the lpFile points to the .pdf file and ShellExecuteEx() takes care of everything else. I suppose I can write the code to search the registry and duplicate this but it doesn't sound fun. :(( I don't suppose CreateProcess() does this kind of thing, does it?

                          J Offline
                          J Offline
                          JT Anderson
                          wrote on last edited by
                          #12

                          You might find the FindExecutable function useful.

                          H 1 Reply Last reply
                          0
                          • J JT Anderson

                            You might find the FindExecutable function useful.

                            H Offline
                            H Offline
                            Harold Bamford
                            wrote on last edited by
                            #13

                            OK, thanks to all you folks giving me help, I think I have it. I now use FindExecutable() to get the default program, then CreateProcess() to spawn it:

                            	// Get the name of the program that runs on a .pdf file
                            	char *filename = "C:\\src\\IOGuides\\PDF Files\\751018a.pdf";
                            	TCHAR szExe[MAX_PATH];
                            	::FindExecutable(filename, _T(""), szExe);
                             
                            	HANDLE hProcess = NULL;	// Use for WaitForInputIdle()
                            	STARTUPINFO startupInfo;
                            	PROCESS_INFORMATION processInfo;
                            	::ZeroMemory(&startupInfo, sizeof(startupInfo));
                            	startupInfo.cb = sizeof(startupInfo);
                            	::ZeroMemory(&processInfo, sizeof(processInfo));  // better safe than sorry
                             
                            	char cmd[MAX_PATH + MAX_PATH + 5];
                            	sprintf(cmd,"\"%s\" \"%s\"", szExe, filename);
                            	BOOL startedOK = CreateProcess(
                            		NULL,
                            		cmd,	// "acrord32.exe file.pdf"
                            		NULL,	// Process security
                            		NULL,	// Thread security
                            		FALSE,	// Inheritance
                            		0,	// no special startup flags
                            		NULL,	// no special environment
                            		NULL,	// no default startup directory
                            		&startupInfo,
                            		&processInfo);
                             
                            	if(!startedOK)
                            	{
                            		ShowLastError(filename);
                            		return;
                            	}
                             
                            	hProcess = processInfo.hProcess; 
                            	WaitForInputIdle(hProcess,INFINITE);
                            

                            I then get the process ID from processInfo.dwProcessId and enumerate all the windows, using GetWindowThreadProcessId() to get the associated process ID.

                            BOOL CIOGuidesView::enumwndfn(CWnd * wnd)
                            {
                            	WININFO wininfo(wnd);
                             
                            	wnd->GetWindowText(wininfo.title);
                             
                            	DWORD ProcessId; 
                            	GetWindowThreadProcessId (wnd->GetSafeHwnd(), &ProcessId ); 
                            	wininfo.Pid = ProcessId;
                             
                            	m_WinInfoArray.Add(wininfo);
                             
                            	return TRUE;
                            }
                            

                            Comparing processInfo.dwProcessId against the value from GetWindowThreadProcessId() gives me the match-up I needed. Unfortunately, AcroRd32.exe is cutesy and allows only one instance to run at a time. If I already have the Reader running, the new process just closes down. Presumably after talking to its counterpart and giving the new filename. Sigh. I guess I can kill the old one first, but that won't alway work if the user manually started up AcroRd32. Thanks for all your help. I'll probably make a "beginner" level article showing all of this in the next few weeks since doing this is not so obvious. I suspect the trick in making the article will be coming up with keywords and phrases to allow people to find it when they are looking to do this kind of thing. All the information I needed was in the articles; I just couldn't find it. Again, many thanks for all of your

                            1 Reply Last reply
                            0
                            Reply
                            • Reply as topic
                            Log in to reply
                            • Oldest to Newest
                            • Newest to Oldest
                            • Most Votes


                            • Login

                            • Don't have an account? Register

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • World
                            • Users
                            • Groups