I embedded a PDF viewer in a C# Winform using AxAcroPDFLib.
However, the annotation buttons in the toolbar (comments...) are disabled.
I searched and found that they are disabled by default, but some reported enabling them using Javascript:
Collab.showAnnotToolsWhenNoCollab = True
Is there a way to do this here?
Edit: Is it possible to use the browser plugin in a WebBrowser Control? If so, how can this be done?
Update - The first section is relevant only to Acrobat Reader. For information on when using full versions of Acrobat, see the second section.
Acrobat Reader
I'll preface all of this by stating this is probably not the answer you're looking for, but I felt this warranted more of an explanation than just a comment.
A similar, self-answered question was asked on SO (here), where the OP came to the conclusion that this behavior is by design and nothing cannot be done about it, which I agree with, almost.
While I'm sure you've seen that Reader itself can add annotations, the only straightforward means of accomplishing this using the Reader Plugin (AcroPDFLib) is for the document being loaded to be "Reader Enabled," at which point annotations become available just as they are in Reader. If you have control of the documents you wish the plugin to load, this may be a solution for you.
To your question about possibly setting Collab.showAnnotToolsWhenNoCollab = True as a workaround, my searches only showed this being a viable workaround for those using a full version of Acrobat, not Reader. More specifically, on an Adobe forum (here), an Adobe staff commented on the use of this property directly:
No, it is not [about allowing commenting in Adobe Reader]. It is
about enabling commenting in a browser for Acrobat Standard or
Professional. If you wish to enable commenting in Reader, then you
need to "Reader Enable" the PDFs themselves using Acrobat professional
or Adobe Livecycle Reader Extension Server.
Granted, this comment was in reference to Acrobat 9, it appears to still be valid for Acrobat XI.
One last bit. I don't know the scope of your application, so this may be completely irrelevant, but if this is a commercial application, even if do you find a functional workaround, I'd be hesitant to use it, as it might violation the Adobe Reader license agreement (here); specifically section 4.3.3, Disabled Features. The short version is, as with most companies, they don't want you circumventing their protections.
Full versions of Acrobat
The following code will create a PDF viewer (using the Form's window for drawing), open a PDF, then set collab.showAnnotToolsWhenNoCollab = true to allow annotations on the open PDF. This requires a reference to the Acrobat type library.
void CreatePdfViewerAndOpenFile(string pdfFile)
{
short AV_DOC_VIEW = 2;
short PDUseBookmarks = 3;
short AVZoomFitWidth = 2;
Type AcroExch_AVDoc = Type.GetTypeFromProgID("AcroExch.AVDoc");
_acroExchAVDoc = (Acrobat.CAcroAVDoc)Activator.CreateInstance(AcroExch_AVDoc);
bool ok = _acroExchAVDoc.OpenInWindowEx(pdfFile, this.Handle.ToInt32(), AV_DOC_VIEW, -1, 0, PDUseBookmarks, AVZoomFitWidth, 0, 0, 0);
if (ok)
{
CAcroPDDoc pdDoc = (CAcroPDDoc)_acroExchAVDoc.GetPDDoc();
object jsObj = pdDoc.GetJSObject();
Type jsObjType = jsObj.GetType();
object collab = jsObjType.InvokeMember("collab",
BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance,
null, jsObj, null);
jsObjType.InvokeMember("showAnnotToolsWhenNoCollab",
BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance,
null, collab, new object[] { true });
}
}
Call this method from wherever you want to display the PDF. When finished, be sure to call the Close method or the PDF file will remain open in the Acrobat process in the background.
_acroExchAVDoc.Close(-1);
Bear in mind that a lot of "normal" functionality is left out of this example, like form resize handling, etc., but it should get you started. Because resizing isn't handled by this example, you'll probably want to maximize the form before invoking the method, so the viewer is big enough to be useful. For more information on how to use the viewer in this fashion, download the Acrobat SDK (here) and look at the ActiveViewVB sample project, which is what I used to build some of this example. For reference, I used the Acrobat XI SDK.
Related
I have the following code (simplified to show the problem):
var wdApp = new Application();
var wdDoc = wdApp.Documents.Open("C:\foo.docx");
wdApp.StatusBar = "Updating...";
var rng = wdDoc.Range(10, 10);
if ((bool)rng.Information(WdInformation.wdWithInTable))
{
}
//StatusBar value is gone...
What could be the reason?
How can I prevent it?
Do you know of other situations where this can happen?
Here screenshots of the problem
1 F10 (step over) later
Edit:
The provided code uses NetOffice and not the interop library from Microsoft directly, therefor the syntax is correct. You may notice in the provided screenshots that they are taken from a running application. Breakpoint, highlighting of current line of code executing, aswell as the actual result of the code in the word application on the right. Where at first there is the desired statusbar "Tabelle 8 von 17 wird neu erstellt." (Table 8 out of 17 is recreating) and at the next step my statusbar is gone and its the default stuff "165 von 8227 Wörtern" (165 out of 8227 words)
What could be the reason?
I believe this is to do with the library you are using. I tested your code but with the Word Interop library, and the only way I could get the status bar to reset was to manually click/type within the Word window.
How can I prevent it?
I would say take a look into the code base of library you are using. It is likely that it is doing something that is causing the behaviour. Unless there is a specific reason you are using NetOffice I would suggest switching to the either the standard Interop or VSTO.
Do you know of other situations where this can happen?
As above, I could only get the status bar to reset if I manually carried out some sort of input into the window.
My goal is to be able to use C# to programmatically open any .one section file and get all of the section's page ids. In a simple case (one where I have created and recently used the section), this can done with the following code:
using Microsoft.Office.Interop.OneNote;
class Program
{
public static void ProcessOnenoteFile()
{
Application onenoteApp = new Application();
string filepath = #"C:\Users\Admin\Documents\OneNote Notebooks\My Notebook\testsection.one";
string sectionId;
onenoteApp.OpenHierarchy(filepath, null, out sectionId);
string hierarchy;
onenoteApp.GetHierarchy(sectionId, HierarchyScope.hsPages, out hierarchy);
File.WriteAllText(#"C:\hierarchy.txt", hierarchy);
}
}
From here I can parse the xml to find all the pageIds and I am good to go.
The problem, however, is that I want to do this with files I am getting from somebody else and have never opened before. When I run the same code on those files, I cannot find any pageIds in the hierarchy, and therefore, I cannot process any pages. A fix that seems to work is to use the navigateTo method to open the section file in OneNote before trying to get the hierarchy.
...
string sectionId;
onenoteApp.OpenHierarchy(filepath, null, out sectionId);
onenoteApp.NavigateTo(sectionId);
string hierarchy
...
This, however, is quite annoying as I need to open the OneNote application. Since I have many .one section files to process it would be a lot of random information flashing across the screen which is not necessary and might confuse the end users of my program. Is there a way I can achieve the same result of adding pageIds to the hierarchy without needing to open the OneNote Application? At the very least, is there a way I can hide the application?
UPDATE:
I just noticed that using the Publish command also updates the hierarchy with pageIds, however, this solution is still not ideal as it requires me to make anotehr file.
Also, looking more closely at the xml export, I saw that there is a an attribute called "areAllPagesAvailable" which is set to false for me on all the files I have yet to open in OneNote.
WooHoo! After a couple hours of just playing around and Google Searching the different methods, I have found what I am after.
Solution: SyncHierarchy(sectionId);
...
string sectionId;
onenoteApp.OpenHierarchy(onenoteFile, null, out sectionId, CreateFileType.cftSection);
onenoteApp.SyncHierarchy(sectionId);
string hierarchy;
onenoteApp.GetHierarchy(sectionId, HierarchyScope.hsPages, out hierarchy);
...
Since Vista, Windows is shipped with WIA 2.0 (wiaaut.dll).
According to the following KB article and many of my findings on various forums, duplex scanning is no longer possible using WIA 2.0. Yet, the article mentions the use of native WIA 2.0, what would make duplex scanning possible.
(https://support.microsoft.com/en-us/kb/2709992)
According to the WIA 2.0 documentation (https://msdn.microsoft.com/en-us/library/windows/desktop/ms630196(v=vs.85).aspx), duplex scanning is possible but using the new WIA_IPS_DOCUMENT_HANDLING_SELECT (3088) property.
My issues are:
I have no idea how to use native WIA, I suspect when using C# its just not possible.
I cant find a way to set the new WIA_IPS_DOCUMENT_HANDLING_SELECT property, as the property is not present in my wiaDevice properties. According to WiaDef.h, its property id is still 3088 and the only possible value is 0x400 (1024).
If anyone could help me (and I think many others) out on this, it would be much appreciated!
Greetings,
M.
After a few more hours of searching I found a clue in the following post.
https://stackoverflow.com/a/7580686/3641369
As I used a one-pass duplex scanner, both front and back sides where scanned at the same time. By setting the device properties (device properties, not item properties) Document_Handling_Select to 5 (Feeder + Duplex) and Pages to 1 and calling the transfer method 2 times, I finally got the font and back side of the scan.
Setting wiaDev.Properties["Document Handling Select"] = 5 specifies the use of the feeder and scanning duplex.
Setting wiaDev.Properties["Pages"] = 1 specifies that the scanner should keep 1 page in memory, this allowing to keep both front side and back side of the page in memory during 1 scan pass.
if (duplex)
{
wiaDev.Properties["Document Handling Select"].set_Value(5);
wiaDev.Properties["Pages"].set_Value(1);
}
Getting the Wia item and setting item properties such as color and dpi.
var item = wiaDev.Items[1];
item.Properties["6146"].set_Value((int)clr);
item.Properties["6147"].set_Value(dpi);
item.Properties["6148"].set_Value(dpi);
Then calling the transfer method twice returns two different images
var img = (ImageFile)wiaCommonDialog.ShowTransfer(item, FormatID.wiaFormatJPEG);
ImageFile imgduplex = null;
if(duplex)
imgduplex = (ImageFile)wiaCommonDialog.ShowTransfer(item, FormatID.wiaFormatJPEG);
Hope this helps someone!
I am working from the sample project here: http://www.codeproject.com/Articles/8086/Extending-the-save-file-dialog-class-in-NET
I have hidden the address/location bar at the top and made other modifications but I can't for the life of me manage to disable the button that lets you go up to the parent folder. Ist is in the ToolbarWindow32 class which is the problem. This is what I have at the moment but it is not working:
int parentFolderWindow = GetDlgItem(parent, 0x440);
//Doesn't work
//ShowWindow((IntPtr)parentFolderWindow, SW_HIDE);
//40961 gathered from Spy++ watching messages when clicking on the control
// doesn't work
//SendMessage(parentFolderWindow, TB_ENABLEBUTTON, 40961, 0);
// doesn't work
//SendMessage(parentFolderWindow, TB_SETSTATE, 40961, 0);
//Comes back as '{static}', am I working with the wrong control maybe?
GetClassName((IntPtr)parentFolderWindow, lpClassName, (int)nLength);
Alternatively, if they do use the parent folder button and go where I don't want them to, I'm able to look at the new directory they land in, is there a way I can force the navigation to go back?
Edit: Added screenshot
//Comes back as '{static}', am I working with the wrong control maybe?
You know you are using the wrong control, you expected to see "ToolbarWindow32" back. A very significant problem, a common one for Codeproject.com code, is that this code cannot work anymore as posted. Windows has changed too much since 2004. Vista was the first version since then that added a completely new set of shell dialogs, they are based on IFileDialog. Much improved over its predecessor, in particular customizing the dialog is a lot cleaner through the IFileDialogCustomize interface. Not actually what you want to do, and customizations do not include tinkering with the navigation bar.
The IFileDialogEvents interface delivers events, the one you are looking for is the OnFolderChanging event. Designed to stop the user from navigating away from the current folder, the thing you really want to do.
While this looks good on paper, I should caution you about actually trying to use these interfaces. A common problem with anything related to the Windows shell is that they only made it easy to use from C++. The COM interfaces are the "unfriendly" kind, interfaces based on IUnknown without a type library you can use the easily add a reference to your C# or VB.NET project. Microsoft published the "Vista bridge" to make these interfaces usable from C# as well, it looks like this. Yes, yuck. Double yuck when you discover you have to do this twice, this only works on later Windows versions and there's a strong hint that you are trying to do this on XP (judging from the control ID you found).
This is simply not something you want to have to support. Since the alternative is so simple, use the supported .NET FileOk event instead. A Winforms example:
private void SaveButton_Click(object sender, EventArgs e) {
string requiredDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
using (var dlg = new SaveFileDialog()) {
dlg.InitialDirectory = requiredDir;
dlg.FileOk += (s, cea) => {
string selectedDir = System.IO.Path.GetDirectoryName(dlg.FileName);
if (string.Compare(requiredDir, selectedDir, StringComparison.OrdinalIgnoreCase) != 0) {
string msg = string.Format("Sorry, you cannot save to this directory.\r\nPlease select '{0}' instead", requiredDir);
MessageBox.Show(msg, "Invalid folder selection");
cea.Cancel = true;
}
};
if (dlg.ShowDialog() == DialogResult.OK) {
// etc...
}
}
}
I don't this is going to work. Even if you disable the button they can type ..\ and click save and it will take them up one level. You can't exactly disable the file name text box and maintain the functionality of the dialog.
You'd be better off either using the FolderBrowserDialog and setting it's RootFolder property and asking the user to type the filename in or auto generating it.
If the folder you are wanting to restrict the users to isn't an Environment.SpecialFolder Then you'll need to do some work to make the call to SHBrowseForFolder Manually using ILCreateFromPath to get a PIDLIST_ABSOLUTE for your path to pass to the BROWSEINFO.pidlRoot
You can reflect FolderBrowserDialog.RunDialog to see how to make that call.
Since you want such custom behaviors instead of developing low level code (that is likely yo break in the next versions of windows) you can try to develop your file picker form.
Basically it is a simple treeview + list view. Microsoft has a walk-through .
It will take you half a day but once you have your custom form you can define all behaviors you need without tricks and limits.
I have an application which writes HTML to a WebBrowser control in a .NET winforms application.
I want to detect somehow programatically if the Internet Settings have Javascript (or Active Scripting rather) disabled.
I'm guessing you need to use something like WMI to query the IE Security Settings.
EDIT #1: It's important I know if javascript is enabled prior to displaying the HTML so solutions which modify the DOM to display a warning or that use tags are not applicable in my particular case. In my case, if javascript isn't available i'll display content in a native RichTextBox instead and I also want to report whether JS is enabled back to the server application so I can tell the admin who sends alerts that 5% or 75% of users have JS enabled or not.
Thanks to #Kickaha's suggestion. Here's a simple method which checks the registry to see if it's set. Probably some cases where this could throw an exception so be sure to handle them.
const string DWORD_FOR_ACTIVE_SCRIPTING = "1400";
const string VALUE_FOR_DISABLED = "3";
const string VALUE_FOR_ENABLED = "0";
public static bool IsJavascriptEnabled( )
{
bool retVal = true;
//get the registry key for Zone 3(Internet Zone)
Microsoft.Win32.RegistryKey key = Registry.CurrentUser.OpenSubKey(#"Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3", true);
if (key != null)
{
Object value = key.GetValue(DWORD_FOR_ACTIVE_SCRIPTING, VALUE_FOR_ENABLED);
if( value.ToString().Equals(VALUE_FOR_DISABLED) )
{
retVal = false;
}
}
return retVal;
}
Note: in the interest of keep this code sample short (and because I only cared about the Internet Zone) - this method only checks the internet zone. You can modify the 3 at end of OpenSubKey line to change the zone.
If you are having troubles with popups popping up, i've included a solution for you, and if you want to disable/enable javascript on th client machine (or even just read/query if it is enabled/disabled) ive included that answer for you as well, here we go:
Which popup message do you want to disable? If it's the alert message, try this, obviously resolving the window or frame object to your particular needs, I’ve just assumed top-level document, but if you need an iframe you can access it using window.frames(0). for the first frame and so on... (re the JavaScript part)... here is some code, assuming WB is your webbrowser control...
WB.Document.parentWindow.execScript "window.alert = function () { };", "JScript"
You must run the above code only after the entire page is done loading, i understand this is very difficult to do (and a full-proof version hasn't been published yet) however I have been doing it (full proof) for some time now, and you can gather hints on how to do this accurately if you read some of my previous answers labelled "webbrowser" and "webbrowser-control", but getting back to the question at hand, if you want to cancel the .confirm JavaScript message, just replace window.alert with window.confirm (of course, qualifying your window. object with the correct object to reach the document hierarchy you are working with). You can also disable the .print method with the above technique and the new IE9 .prompt method as well.
If you want to disable JavaScript entirely, you can use the registry to do this, and you must make the registry change before the webbrowser control loads into memory, and every time you change it (on & off) you must reload the webbrowser control out and into memory (or just restart your application).
The registry key is \HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\ - the keyname is 1400 and the value to disable it is 3, and to enable it is 0.
Of course, because there are 5 zones under the Zones key, you need to either change it for the active zone or for all zones to be sure. However, you really don't need to do this if all you want to do is supress js dialog popup messages.
Let me know how you go, and if I can help further.
Here is a suggestion - Encode the warning into your webpage as default. Create a javascript that runs on page load which removes that element. The warning will be there when ever javascript is not allowed to run.
It's a long while since I coded client side HTML javascript to interact with the DOM so I may be a little out of date. i.e. you will need to fix details, but I hope I get the general idea across.
<script>
document.getElemntByID("noJavascriptWarning").innerHTML="";
</script>
and in your HTML body
<DIV id="noJavascriptWarning" name="noJavaScriptWarning">Please enable Javascript</DIV>