Our application, write in Delphi, generates a series of reports, most of then in PDF format, that opens automatically when it is generated. Adobe X introduced a feature that is enabled by default "Enable Protected Mode at Startup". The report pdf files are opened using "ShelExecute".
var
pdfFile: string;
begin
pdfFile := 'C:\Users\Ronaldo\Documents\appName\reports\file.pdf';
ShellExecute(0, 'open', PChar(pdfFile), '', '', SW_SHOW);
//
end;
Because of this new Adobe Reader new setting, under Win 7 or Vista, we are getting an error message when opening the document. Double clicking the document to open it does not give any problem. Is there a way to disable the protected method - or another way to open the document without getting the error (a workaround)?
*Some more information *
The PDF file is being generated on our server application, streamed to the client and the client generates the pdf (using Write) - First I though that could be the problem - but again, why the double click works fine.
I have create a dummy app that do nothing but use the same above code to open the pdf, and it works. I have checked the privileges of the application - all the same - the only difference is that the one that is not working is being installed on the OS using a proper installer - the other (the dummy one) I just created and dropped it there.
One of the comments ask about the file association - this should not be an issue since the application succeed in launching Adobe reader - Adobe reader then gives me the "access denied" error message. A double click on the same file works fine.
New info - 30/03/2011 - 2:50pm - New Zealand time
I have made a change to the code just to test the only one difference between the app itself and the dummy app. Instead of getting the file path and file name automatically, it now opens a OpenDialog - the Filename property of the opendialog is used as parameter to ShellExecute (as the comment after Ken answer states) - it works. Why is it that, when you get the file name from an open dialog, it works - note that I am not openning the file from the dialog - I'm getting the filename, and using it as a parameter to ShellExecute.
Updated code sample
When the user clicks the "generate report" button, the report is opened automatically after it is generated. Apart from that, there is a grid, showing all the generated reports so far, for that user - this is the code on the double click for that grid:
if GetSelectedReport <> nil then // this will check if the user selected an report
if TReportItemState(GetSelectedReport.State) in [risGenerated,risViewed] then // checks if the report selected is in the correct state to be displayed.
begin
fileName := TClientReportManager.Singleton.Directory+'\'+GetSelectedReport.Filename; // a string with the filePath + fileName
ShellExecute(0, 'open', pchar(fileName), '','', SW_MAXIMIZE); // command to open the file
end;
My first guess with the Opendialog working is that, the open dialog changes the CurrentDir - So I tried already the SetCurrentDir and ChDir to change the current directory to the one where the files are. No success.
Under Win 7, the file path is translated to C:\Users\Ronaldo\Documents\CompanyName\AppName
I don't think you can totally disable it in code; if you could, it would defeat the whole purpose of the Protected Mode (preventing malware from exploiting the .pdf file association). You may be able to work around it in a legal way, though. :)
I suspect it has to do with the open
verb you're using with ShellExecute
. You're assuming (maybe incorrectly) that the open
verb does the same in Protected Mode on Win7 as it did on prior versions of Adobe Reader and Windows. (NOTE: I don't have that version of Acrobat installed on my system; this is all speculation.)
The first thing I'd try is changing the call to ShellExecute
as follows:
ShellExecute(0, nil, PChar(pdfFile), nil, nil, SW_NORMAL);
The first change is to pass nil
as the second parameter. This tells Windows you want whatever the default action is to occur. This may, for example, be view
instead of open
.
I also changed the two parameters after the filename to nil as well. This is more readable than using the empty string ('').
The final change is in the last parameter; I typically use SW_NORMAL
instead of SW_SHOW
, simply because this tells Windows to show it at whatever the default size and position would be; this may be something saved by the application and will take into effect the user's preferences (if any).
If this doesn't work, it's time to prowl around (carefully!!) in the Windows registry. Open regedit
in the Start Menu's Search control, and navigate to HKEY_CLASSES_ROOT. Scroll down the file extensions until you find the entry for .pdf
, and double-click that branch. You'll see the Default
, which is (on my system, anyway) AcroExch.Document
with a Content Type
of application/pdf
.
Continue down the tree in the left pane until you find AcroExch.Document
, and expand it. You'll see a few values there (again, from my machine), as you can see in the image below. Expand the Shell
branch, and you'll see the defined verbs, as well as the command associated with them. On my machine (again), I have a single Open
verb, whose command is set to "C:\Program Files (x86)\Adobe\Reader 9.0\Reader\AcroRd32.exe" "%1"
.
(Bear with me - we're almost there. I promise.)
You can see what the double-click is doing differently by examining the default value (click Shell
in the left pane, and then see what's set as (Default)
in the right. Then examine the command-line (in the second image above, it's Open
) to see what switches if any are passed to the Acrobat Reader app. (If you can't figure out which one's the default, right-click a .pdf file in Windows Explorer and see what the bolded item is in the context menu.)
If there's a parameter other than "%1"
passed, you'll need to add the same parameter to the command line provided to ShellExecute
. For instance, if the parameter is /v
, you'd modify your call to ShellExcute
to something like this:
ShellExecute(0, nil, PChar(pdfFile), PChar('/v'), nil, SW_NORMAL);
I have left this behind but now I got time I went back to try to solve the problem.
I found out that, the client application is using GetEnvironmentVariable('USERPROFILE') to get part of the folder where the reports are. This give me something like 'c:\users\user_name\' on Windows 7 - and then adding a constant with something like "My Documents\CompanyFolder\ProductFolder".
Under win XP this was working fine, but under Win 7, it looks like UAC will not allow you, for some reason, to direct and specifically refer to "My Documents" - instead you need to use the "Documents".
I have changed the constant to remove the "My Documents" part and have added a function to retrieve the private user document folder using the parameter CSIDL_Personal and the function:
function GetSpecialFolderPath(folder : integer) : string;
const
SHGFP_TYPE_CURRENT = 0;
var
path: array [0..MAX_PATH] of char;
begin
if SUCCEEDED(SHGetFolderPath(0,folder,0,SHGFP_TYPE_CURRENT,@path[0])) then
Result := path
else
Result := '';
end;
and calling the function like GetSpecialFolderPath(CSIDL_Personal).
Thanks all for the time you got to post comments and answers.
Just want to add that this answer is the right answer in my case. It could be the case @Ken White answer is the right answer for someone else.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With