note: I already looked at the following question but it provided no insight: PDF file does not get open from ShellExecute function in Visual Studio, C++
I have the same problem as the poster in the above question.
Trying to open a PDF file from an MFC Application using ShellExecute. Adobe XI on Win 8 64 bit system.
hReturn = ::ShellExecuteA(NULL,"open",sPath,NULL,NULL,SW_SHOWMAXIMIZED);
sPath is a CString although I've tried alternatives with the same result. I've also tried SW_SHOW, SW_SHOWNORMAL. ShellExecute returns 42 when I cast the HINSTANCE to an int. I understand that means it opens successfully.
In fact, if I watch the task manager when executing the command, Adobe Reader opens in response in Task Manger but the Adobe window never opens.
When I exit my application, Adobe is still open.
If I try to open the target PDF file, the O/S says it can't be opened because it is already open in another application. When I "End Task" on the Adobe Reader in task manager, it frees up the file.
If I then click on the file, it opens fine in Adobe Reader.
So, I'm inferring from this that the ShellExecute is launching Adobe, that it is getting the right file, and that the file is, indeed, readable.
I've also confirmed that ShellExecute is working by directly referencing a txt file. It opens fine in Notepad.
hReturn = ::ShellExecuteA(NULL,"open","d:\\develop\\readme.txt", NULL, NULL, SW_SHOWMAXIMIZED);
Any ideas?
Thanks
try disable "Protected mode"
Adobe Reader - Protected Mode
This seems to be a known problem with opening a PDF file on Win8 via ShellExecuteEx. I had the same issue with an installer that would try to open a PDF at the end of the install process. On Win7 it worked fine. On Win8, it displayed the symptoms you describe. I was able to track it down to a problem with elevated privileges on our install program. I'm not sure why that would adversely affect things, but, it did. As an alternative, we looked at opening the file as an HTML document instead. We are still looking for a better solution.
Related
I'm using System function System(mypath/test.xls) to open and edit an excel sheet in C++ run time. It opens my excel sheet, allows me to edit ans close the same. After closing the excel sheet, the control goes to the code again. Everything works fine unless there is already some other excel sheet opened. If there is some other excel sheet already opened in the machine, I will not able to edit and close so that control goes to code. Can anyone suggest any solutions for this issue.
What is happening is your System(..) function call is asking the Windows shell to find the application associated with your file (test.xls) , which is Excel. Then if Excel is already running it is asked to open file. If the application is not running, then Windows starts the application for you.
So if the application is not already running and it is started for you it becomes associated with your program as a 'child' process. Therefore your System(..) call waits for it to end before continuing. If however Excel is already running then once Windows informs that instance of your desire to open the file test.xls, your call to System(..) returns immediately.
You can avoid this by explicitly running the Excel program by giving the full path to the Excel EXE file. And including the /x command line argument and full path to your file. The /x causes Excel to open a new process and then open your file. This new process is a child of your program's so the System(..) call will wait..
I'm not familiar with the System(..) call (is it like the system(..) one?) you may have to provide the switch /x, and path arguments as distinct arguments to this call rather than in one long string. Also there may be options on how your child process is launched, so waiting for it to return may be optional and so forth.
I am trying to open a local html document using Shell Execute(). But, what i need is, Suppose if that particular document is already opened and if ShellExecute is triggered again, then that particular file should not be opened again instead bring the already opened file into foreground. Can you please suggest how can i do this?
void main()
{
ShellExecute(NULL, "open", "C:\\prograomgiles\\help.html",
NULL, NULL, SW_SHOWNORMAL);
}
It's nearly impossible, because it depends on which program processes the html files and how does it work. Suppose, that my OS opens html files by printing them directly on a printer. How would you bring opened file into foreground?
If you want to display HTML content in the way specified by you, write your own browser (It's quite easy, you can - for example - embed IE in C#.NET application) and run it instead of default system browser. You would have then full control on how your files are displayed.
Many web browsers respond to DDE messages, particularly the WWW_OpenURL message. Not sure about other browsers, but IE also responds to WWW_GetWindowInfo and WWW_Activate messages, which you could use to enumerate open windows and their URLs, and then activate a particular window.
I'm writing a Win32 DLL with a function that adds a directory to the Windows PATH environment variable (to be used in an installer).
Looking at the environment variables in Regedit or the Control Panel after the DLL has run shows me that my DLL has succeeded in adding the path to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment and HKEY_CURRENT_USER\Environment.
But when I start up a new Command Prompt (after running the DLL), the directory I added does not show up in the output of echo %PATH% and I can not access the executable that lives in that directory by typing its name.
I think my program is not doing a good job of notifying the system that the PATH has changed, or maybe it is notifying them before the change has fully taken effect. I read an article by Microsoft that says to broadcast the WM_SETTINGCHANGE message after changing an environment variable, and I am doing that with this code:
DWORD result2 = 0;
LRESULT result = SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
(LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, &result2);
if (result == 0){ /* ... Display error message to user ... */ }
The order of my calls is: RegCreateKeyEx, RegSetValueEx, RegCloseKey, SendMessageTimeout
If I press "OK" in the Control Panel "Environment Variables" window, the changes made by my DLL to the PATH show up in newly-created command prompts, so there is something that the Control Panel is doing to propagate PATH changes; I want to figure out what it is and do the same thing.
Does anyone know what I should do?
I'm running 64-bit Windows Vista but I want this to work on all Windows XP, Vista and Windows 7 operating systems.
Update: The problem with the code I posted above is that I did not put the L prefix on the "Environment" string. Although it does not say it explicitly anywhere in the Microsoft documentation that I can find, the LPARAM needs to be a pointer to a WCHAR string (2-byte characters) as opposed to a CHAR string, which is what Visual Studio's compiler generates by default when I write a string literal. The solution to my problem was to change "Environment" to L"Environment". (I thought I already tried that before posting this question, but apparently I didn't try it correctly!) But anyone who wants a complete C++ solution for this task should look at Dan Moulding's answer.
It turns out there really isn't anything new under the sun. This has already been done before, at least once. By me. I created a DLL very much like what you describe for exactly the same purpose (for use in modifying the path from an NSIS installer). It gets used by the Visual Leak Detector installer.
The DLL is called editenv.dll. The source is available at github. I just tested the installer and it updated the system PATH environment variable, no problem. Based on what you've written, I don't see anything that stands out as being wrong. I also don't see anything obvious that's missing. But it may be worth a look at the editenv.dll source (you'd be most interested in EnvVar::set() in EnvVar.cpp, and possibly the pathAdd() and pathRemove() C APIs in editenv.cpp).
I have a program which calls the same Win32 API to yours to update the environment, and it works fine.
One thing to be careful of is how you are opening up the command prompt.
If you open up the command prompt by doing this:
Start -> Run -> cmd.exe
then the environment in the prompt shows that the new variable is set.
However, I also have a programmable function key on my keyboard which I have set to run the cmd.exe process. If I open a command prompt via that function key and then type env, it doesn't show the variable as being set.
I'm not sure why it works differently, but it must have something to do with the way the cmd.exe process is launched (although both are running under my user name, not SYSTEM).
How are you opening up the command prompt?
I have an C++ app I built which is registered as the default handler for a file with a specific extension. So when I download one of these files with Firefox from a website, it downloads it to a temp directory and then shell executes my app while passing the full path to the downloaded file on the command line.
What is the best way to figure out from the external app what the original download url of the file was, given only it's path on disk? Can I use XPCOM API calls to inspect the FireFox download manager database?
I've figured out that this data get's stored in the "%APPData%\Mozilla\Firefox\($profile)\downloads.sqlite" file which is a SqlLite db file, but I really rather not try to open this file directly as FireFox has an open write handle to the file while running.
After perusing the Mozilla developer center for a while, I ran accross the nsIDownloadManager service, which seems to be just the thing. But I can't seem to get access to it from XPCOM in a separate process?
Here's the code I am using:
nsresult rv;
//init XPCOM
nsCOMPtr<nsIServiceManager> servMgr;
rv = NS_InitXPCOM2(getter_AddRefs(servMgr), nsnull, nsnull);
NS_ENSURE_SUCCESS(rv, rv);
//Get a download manager instance
nsCOMPtr<nsIDownloadManager> downloadMgr;
rv = servMgr->GetServiceByContractID(NS_DOWNLOADMANAGER_CONTRACTID,
nsIDownloadManager::GetIID(), getter_AddRefs(downloadMgr));
NS_ENSURE_SUCCESS(rv, rv);
When I run this, the GetServiceByContractID() call returns 0x8007000e, which is defined in nsError.h as NS_ERROR_OUT_OF_MEMORY. (which I find very weird).
Any ideas here? Am I barking up the right tree?
No, you can't access Firefox's XPCOM objects from an external process, and you also shouldn't open the sqlite database while Firefox has it open. I don't know that there's any straightforward way to do what you want without writing a Firefox extension that has access to the Firefox internals.
I'm a little hazy on the details right now, but, assuming that your download is served with a custom MIME type, it's possible to register a handler for that type; your handler can then cancel the download and pass the URL to your application.
I'm wondering how I can open a file literally in C++ (like double clicking it)?
Provided you have the ".txt" extension registered (and text files should be associated with Notepad in a default installation, or something else if you've changed it from Explorer - you'd have to work pretty hard to disassociate them), Windows will open it for you without you having to specify the executable name:
ShellExecute (hwnd,"open","c:\\x.txt",NULL,NULL,SW_SHOW);
or, for a web page in your browser of choice:
ShellExecute (hwnd,"open","http://www.microsoft.com",NULL,NULL,SW_SHOW);
You mean like open explorer?
How about using
system("explorer.exe file.to.open");
Use the ShellExecute function with the "open" operation.
Use ShellExecute with the "open" verb.
See this article for more information.
easy way: system("notepad.exe [location to file]");