Trying to create a new tab from notepad++ .NET plugin - c#

I am writing a Notepad++ plugin, and need to create a new tab, for a new file. I haven't been able to find anything covering this in the documentation.
The closest I have come is:
IntPtr curScintilla = PluginBase.GetCurrentScintilla();
IntPtr documentPtr = Win32.SendMessage(curScintilla, SciMsg.SCI_CREATEDOCUMENT, 1, 1);
Win32.SendMessage(curScintilla, SciMsg.SCI_SETDOCPOINTER, 0, documentPtr);
but this acts in the current tab (I think it's creating a new document and pointing the current tab at that).
I was reading the "Multiple views" section of http://www.scintilla.org/ScintillaDoc.html but am unable to get any further than the above. I don't normally work in C# or even Windows, so I might be missing something obvious. I tried looking at existing plugins for examples but most of them seem to be written in C++, rather than C#.
Any guidance appreciated.
Thanks.

I have not gone through scintilla. But I used simple approach. I used this for creating, you may need to look for more information for sending the message.
Create file if it doesn't exist in the directory before you start. Else it will ask for user confirmation.
Arguments for the process should differ from the first and next tabs:
File.Create(yourNewFile); //or yourNextNewFile in case of second, third, so on..
Process notepadPlus = new Process();
notepadPlus.StartInfo.FileName = "notepad++.exe";
For the first file use as (new instance with new session - without any old tabs):
notepadPlus.StartInfo.Arguments = #"-multiInst -nosession yourNewFile";
For next files use as (only new tabs will be created):
notepadPlus.StartInfo.Arguments = #"yourNextNewFile";
/* Start the process */
notepadPlus.Start();

You have to send a message not to the Scintilla control, but to Notepad itself.
Like this:
Win32.SendMessage(PluginBase.nppData._nppHandle, NppMsg.NPPM_MENUCOMMAND, 0, NppMenuCmd.IDM_FILE_NEW);
More informations here including the used constants.

Related

WinForms WebBrowser HtmlDocument.Write behaves differently in different solutions

Recently, my application has crashed when trying to display a rather lengthy (but otherwise simple) HTML e-mail.
The crash was caused by mshtml.dll getting a stack overflow (exception code 0xc00000fd). Of note here is that this didn't throw an exception but it actually just crashed the program as a whole. The error was retrieved from the Windows event log.
In the process of debugging, I created a smaller sample solution to try and narrow down the issue. However, not only does it work fine in the sample solution, it behaves completely different from the main program despite running the same code even for the simplest of HTML strings.
The code is as follows:
var webBrowser1 = new System.Windows.Forms.WebBrowser();
webBrowser1.AllowNavigation = false;
webBrowser1.AllowWebBrowserDrop = false;
webBrowser1.Navigate("about:blank");
var doc = webBrowser1.Document.OpenNew(true);
doc.Write("<HTML><BODY>This is a new HTML document.</BODY></HTML>");
var count = doc.All.Count;
var html = doc.All[0].OuterHtml;
In the sample solution this evaluates to:
count = 4; // [HTML, HEAD, TITLE, BODY]
html = "<HTML><HEAD></HEAD>\r\n<BODY>This is a new HTML document.</BODY></HTML>";
Meanwhile in the main program it comes out to:
count = 3; // [HTML, HEAD, BODY]
html = "<html><head></head><body>This is a new HTML document.</body></html>";
These are small discrepancies but that is largely due to the simple HTML used. The one that causes the crash has rather significant differences.
I am absolutely stumped as to how the result can be so vastly different.
The documentation for HtmlDocument.Write(string) states that:
It is recommended that you write an entire valid HTML document using the Write method, including HTML and BODY tags. However, if you write just HTML elements, the Document Object Model (DOM) will supply these elements for you.
But I have no idea how the DomDocument is provided nor why they would be different in the first place. Both solutions are running in x64 Debug mode and Net-Framework 4.6.2.
Both load the module: C:\WINDOWS\assembly\GAC\Microsoft.mshtml\7.0.3300.0__b03f5f7f11d50a3a\Microsoft.mshtml.dll
How is it possible that these produce different results?!
Any and all help welcome.
Thanks in advance.
The difference in behavior stems from the registry entry as proposed by Jimi and linked here
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION
To reiterate, in the above registry the main program had an entry "ApplicationFileName.exe"=dword:00002af9 while my new test-application didn't.
This, in and for itself, does not explain the crashing of mshtml.dll itself but since the question was about the difference in behavior I'll post this as the answer. The crash is most likely linked to the outdated version used by Visual Studio but I haven't yet had the chance to look into some of the proposed fixes for that.

Cannot access same source HTML as a browser

I am coming back to work on a BOT that scraped data from a site once a day for my personal use.
However they have changed the code during COVID and now it seems they are loading in a lot of the content with Ajax/JavaScript.
I thought that if I did a WebRequest and obtained the response HTML from a URL, it should match the same content that I see in a browser (FF/Chrome) when I right click and "view source". I thought the actual DOM and generated source code would come later when those files were loaded as onload events fired, scripts lazily loaded and so on.
However the source HTML I obtain with my BOT is NOT the same as the HTML I see when viewing the source code. So my regular expressions that find certain links are not available to me.
Why am I seeing a difference between "view source" and a download of the HTML?
I can only think that when the page loads, SCRIPTS run that load other content into the page and that when I view source I am actually seeing a partial generated source rather than the original source code. Therefore is there a way I can call the page with my BOT, wait X seconds before obtaining the response to get this "onload" generated HTML?
Or even better a way for MY BOT (not using someone elses), to view generated source.
This BOT runs as a web service. I can find another site to scrape but it's just painful when I have all the regular expressions working on the source I see, except it's NOT the source my BOT obtains.
A bit confused at why my browser is showing me more content with a view source (not generated source), than my BOT gets when making a valid request.
Any help would be much appreciated this is almost an 8 year project that I have been doing on/off and this change has ruined one of the core parts of the system.
In response to OP's comment, here is the Java code for how to click at different parts on the screen to do this:
You could use Java's Robot class. I just learned about it a few days ago:
// Import
import java.awt.Robot;
// Code
void click(int x, int y, int btn) {
Robot robot = new Robot();
robot.mouseMove(x, y);
robot.mousePress(btn);
robot.mouseRelease(btn);
}
You would then run the click function with the x and y position to click, as well as the button (MouseEvent.BUTTON1, MouseEvent.BUTTON2, etc.)
After stringing together the right positions (this will vary depending on the screen) you could do just about anything.
To use shortcuts, just use the keyPress and keyRelease functions. Here is a good way to do this:
void key(int keyCode, boolean ctrl, boolean alt, boolean shift) {
if (ctrl)
robot.keyPress(KeyEvent.VK_CONTROL);
if (alt)
robot.keyPress(KeyEvent.VK_ALT);
if (shift)
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress(keyCode);
robot.keyRelease(keyCode);
if (ctrl)
robot.keyRelease(KeyEvent.VK_CONTROL);
if (alt)
robot.keyRelease(KeyEvent.VK_ALT);
if (shift)
robot.keyRelease(KeyEvent.VK_SHIFT);
}
Thus, something like Ctrl+Shift+I to open the inspect menu would look like this:
key(KeyEvent.VK_I, true, false, true);
Here are the steps to copy a website's code (from the inspector) with Google Chrome:
Ctrl + Shift + I
Right click the HTML tag
Select "Edit as HTML"
Ctrl + A
Ctrl + C
Then, you can use the technique from this StackOverflow to get the content from the clipboard:
Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
String text = (String) c.getData(DataFlavor.stringFlavor);
Using something like FileOutputStream to put the info into a file:
FileOutputStream output = new FileOutputStream(new File( PATH HERE ));
output.write(text.getBytes());
output.close();
I hope this helps!
I have seemed to have fixed it by just turning on the ability to store cookies in my custom HTTP (Bot/Scraper) class, that was being called from the class trying to obtain the data. Probably the site has a defense system to prevent visitors requesting pages and not the JS/CSS with a different session ID on each request.
However I would like to see some other examples because if it is just cookies then they could use JavaScript to test for JavaScript e.g an AJAX call to log if JS is actually on or some DOM manipulation to determine if you are really Human or not which would break it again.
Every site uses different methods to prevent scrapers, email harvesters, job rapists, link harvesters etc inc working out the standard time between requests for 100% verifiable humans and BOTS and then using those values to help determine spoofed user-agents etc. I wrote a whole system to stop BOTS at my last place of work and its a layered approach, just glad the cookies being enabled solved it on this site but it could easily be beefed up with other tricks to test for BOTS vs HUMANS.
I do know some Java, enough to work out what is going on anyway. My BOT is in C#.

FOP and IKVM in .NET - Images Not Working

UPDATE2: I got it working completely now! Scroll way down to find out how...
UPDATE: I got it working! Well... partially. Scroll down for the answer...
I'm trying to get my FO file to show an external image upon transforming it to PDF (or RTF for that matter, but I'm not sure whether RTFs are even capable of displaying images (they are)) with FOP, but I can't seem to get it working. (The question asked here is different than mine.)
I am using IKVM 0.46.0.1 and have compiled a FOP 1.0 dll to put in .NET; this code worked fine when I didn't try to add images:
private void convertFoByMimetype(java.io.File fo, java.io.File outfile, string mimetype)
{
OutputStream output = null;
try
{
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// configure foUserAgent as desired
// Setup outputput stream. Note: Using BufferedOutputStream
// for performance reasons (helpful with FileOutputStreams).
output = new FileOutputStream(outfile);
output = new BufferedOutputStream(output);
// Construct fop with desired output format
Fop fop = fopFactory.newFop(mimetype, foUserAgent, output);
// Setup JAXP using identity transformer
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(); // identity transformer
// Setup input stream
Source src = new StreamSource(fo);
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
transformer.transform(src, res);
}
catch (Exception ex)
...
}
However, when I (or rather a DocBook2FO transformation) added the following code:
<fo:external-graphic src="url(images/interface.png)" width="auto" height="auto" content-width="auto" content-height="auto" content-type="content-type:image/png"></fo:external-graphic>
into the FO file, the image did not show. I read through a bit of the FAQ on Apache's site, which says:
3.3. Why is my graphic not rendered?
Most commonly, the external file is not being found by FOP. Check the
following:
Empty or wrong baseDir setting.
Spelling errors in the file name (including using the wrong case).
...
Other options did not seem to be my case (mainly for the reason below - "The Weird Part"). I tried this:
...
try
{
fopFactory.setBaseURL(fo.getParent());
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
foUserAgent.setBaseURL(fo.getParent());
FOURIResolver fourir = fopFactory.getFOURIResolver();
foUserAgent.setURIResolver(fourir);
// configure foUserAgent as desired
...
with no avail.
The Weird Part
When I use the command-line implementation of FOP, it works fine and displays my image with no problem. (I don't want to go the run-command-line-from-program route, because I don't want to force the users to install Java AND the .NET framework when they want to use my program.)
The png file is generated from GDI+ from within my application (using Bitmap.Save). I also tried different png files, but none of them worked for me.
Is there anything I might be missing?
Thanks a bunch for getting this far
UPDATE and possible answer
So I might have figured out why it didn't work. I put some time into studying the code (before I basically just copypasted it without thinking about it much). The problem is indeed in the wrong basedir setting.
The key is in this chunk of code:
// Setup JAXP using identity transformer
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(); // identity transformer
// Setup input stream
Source src = new StreamSource(fo);
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
transformer.transform(src, res);
What happens here is an identity transformation, which routes its own result into an instance of FOP I've created before. This effectively changes the basedir of the routed FO into that of the application's executable. I have yet to figure out how to do this without a transformation and route my input directly into FOP, but for the moment I worked around this by copying my images into the executable's directory.
Which is where another problem came in. Now whenever I try to execute the code, I get an exception at the line that says transformer.transform(src, res);, which confuses the pants out of me, because it doesn't say anything. The ExceptionHelper says:
java.lang.ExceptionInInitializerError was caught
and there is no inner exception or exception message. I know this is hard to debug just from what I wrote, but I'm hoping there might be an easy fix.
Also, this e-mail seems vaguely related but there is no answer to it.
UPDATE2
Finally, after a few sleepless nights, I managed to get it working with one of the simplest ways possible.
I updated IKVM, compiled fop with the new version and replaced the IKVM references with the new dlls. The error no longer occurs and my image renders fine.
I hope this helps someone someday
I'm using very similar code, although without the FOUserAgent, Resolvers, etc. and it works perfectly.
Did you try setting the src attribute in the XSLT without the url() function?
What might help you diagnose the problem further are the following statements:
java.lang.System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog")
java.lang.System.setErr(New java.io.PrintStream(New TraceStream(TraceStream.Level.Error)))
java.lang.System.setOut(New java.io.PrintStream(New TraceStream(TraceStream.Level.Info)))
Where TraceStream is a .NET implementation of a java.io.OutputStream which writes to your favorite logger.
I posted a version for the Common.Logging package at http://pastebin.com/XH1Wg7jn.
Here's a post not to leave the question unanswered, see "Update 1" and "Update 2" in the original post for the solution.

using OpenFileDialog for directory, not FolderBrowserDialog

I want to have a Folder browser in my application, but I don't want to use the FolderBrowserDialog. (For several reasons, such as it's painful to use)
I want to use the standard OpenFileDialog, but modified for the directories.
As an example, µTorrent has a nice implementation of it (Preferences/Directories/Put new downloads in:). The standard Open File Dialog enable the user to:
paste full paths in the text field at bottom
use "Favorite Links" bar on Vista
use Search on Vista
auto remember last directory
more...
Does anybody know how to implement this? In C#.
I am not sure about uTorrent but this sounds pretty much like new Vista's IFileDialog with FOS_PICKFOLDERS option set. Generic C# code for it would go something like:
var frm = (IFileDialog)(new FileOpenDialogRCW());
uint options;
frm.GetOptions(out options);
options |= FOS_PICKFOLDERS;
frm.SetOptions(options);
if (frm.Show(owner.Handle) == S_OK) {
IShellItem shellItem;
frm.GetResult(out shellItem);
IntPtr pszString;
shellItem.GetDisplayName(SIGDN_FILESYSPATH, out pszString);
this.Folder = Marshal.PtrToStringAuto(pszString);
}
Full code can be found here.
WindowsAPICodePack
var dlg = new Microsoft.WindowsAPICodePack.Dialogs.CommonOpenFileDialog();
dlg.IsFolderPicker = true;
See this answer by leetNightShade for a working solution.
There are three things I believe make this solution much better than all the others.
It is simple to use.
It only requires you include two files (which can be combined to one anyway) in your project.
It falls back to the standard FolderBrowserDialog when used on XP or older systems.
The author grants permission to use the code for any purpose you deem fit.
There’s no license as such as you are free to take and do with the code what you will.
Download the code here.

How do I popup the compose / create mail dialog using the user's default email client?

The use case is simple. At a certain point of time, I need to be able to show the user his familiar compose email dialog (Outlook or other) with
fields like from, to, Subject already filled up with certain application determined values.
The email would also have an attachment along with it.
The mail should not be sent unless the user explicitly okays it.
I did this once back in the ol' VB6 days.. can't figure out how now.. I just remember that it was quite easy.
Managed app, C#, .net 3.0+
Update#1: Yeah seems like mailto removed support for attachments (as a security risk?). I tried
You need to include ShellExecute signature as described here. All I got from this was a 5 SE_ERR_ACCESSDENIED and a 2 just for some variety
string sMailToLink = #"mailto:some.address#gmail.com?subject=Hey&body= yeah yeah yeah";
IntPtr result = ShellExecute(IntPtr.Zero, "open", sMailToLink, "", "", ShowCommands.SW_SHOWNORMAL);
Debug.Assert(result.ToInt32() > 32, "Shell Execute failed with return code " + result.ToInt32());
The same MailtoLink works perfectly with Process.Start... but as long as thou shalt not mention attachments.
System.Diagnostics.Process.Start(sMailToLink);
The other options are using the Outlook Object model to do this.. but I've been told that this requires you to add assembly references based to the exact version of Outlook installed. Also this would blow up if the user doesn't prefer MS for email.
The next option are Mapi and something called Mapi33.. Status still IN PROGRESS. Ears still open to suggestions.
You can create a process object and have it call "mailto:user#example.com?subject=My+New+Subject". This will cause the system to act on the mailto with its default handler, however, while you can set subjects and such this wont handle adding an attachment. I'll freely admit im not entirely sure how you'd go about forcing an attachment without writing some mail plugin.
The process code is:
System.Diagnostics.Process.Start("mailto:user#example.com?subject=My+New+Subject");
It's probably not the most efficient or elegant way, but shelling a "mailto:" link will do what you want, I think.
EDIT: Sorry, left out a very important "not".
Since mailto does not support attachments, and since MAPI is not supported within managed code, your best bet is to write (or have someone write) a small non-managed program to call MAPI functions that you can call with command-line arguments. Pity that .NET does not have a cleaner alternative.
See also : MAPI and managed code experiences?
Could it be that you used the mailto: protocol?
Almost all of what you highlight can be done, but I am quite sure, that you cant do attachments.
Microsoft MailTo Documentation
Starting process with mailto: arguments is the simplest approach. Yet, it does not allow anything more or less complex.
Slightly different approach involves creating email template and then feeding it to the Process.Start:
var client = new SmtpClient();
var folder = new RandomTempFolder();
client.DeliveryMethod =
SmtpDeliveryMethod.SpecifiedPickupDirectory;
client.PickupDirectoryLocation = folder.FullName;
var message = new MailMessage("to#no.net",
"from#no.net", "Subject","Hi and bye");
// add attachments here, if needed
// need this to open email in Edit mode in OE
message.Headers.Add("X-Unsent", "1");
client.Send(message);
var files = folder.GetFiles();
Process.Start(files[0].FullName);
Scenarios for the default email handler:
Outlook express opens
Windows: Outlook - does not handle by default, Outlook Express is called instead
Windows: The Bat! - message is opened for viewing, hit Shift-F6 and Enter to send
I've also tested with Mono and it worked more or less.
Additional details are available in this post: Information integration - simplest approach for templated emails
PS: in the end I went for slightly more complex scenario:
Defined interface IEmailIntegraton
Code above went into the DefaultEmailIntegration
Added implementations for OutlookEmailIntegration (automation) and theBat! email integration (using their template format).
Allowed users of the SmartClient to select their scenario from the drop-down (alternatively this could've been implemented as "Check the system for the default email handler and decide automatically")
You're making the assumption that they will have an email client installed, of course.
The option I've taken in the past (in a corporate environment where everyone has at least one version of Outlook installed) was to use the Outlook interop - you only need to reference the earliest version you need to support.
You could look at P/Invoking MAPISendDocuments (which I'd try and avoid, personally), or the other option would be to create your own "compose" form and use the objects from the System.Net.Mail namespace.
you can use a trick if you intend to use Outlook[this code is based on outlook 2010[v14.0.0.]]
Create Outlook MailItem
and transmit file (ie download)
if user opens the file (.msg) the compose message dialog opens automatically
here is the code ...
Microsoft.Office.Interop.Outlook.Application outapp = new Application();
try
{
_NameSpace np = outapp.GetNamespace("MAPI");
MailItem oMsg = (MailItem)outapp.CreateItem(OlItemType.olMailItem);
oMsg.To = "a#b.com";
oMsg.Subject = "Subject";
//add detail
oMsg.SaveAs("C:\\Doc.msg", OlSaveAsType.olMSGUnicode);//your path
oMsg.Close(OlInspectorClose.olSave);
}
catch (System.Exception e)
{
status = false;
}
finally
{
outapp.Quit();
}
then transmit the file you created say "Doc.msg"
string filename ="Doc.msg";//file name created previously
path = "C:\\" + filename; //full path ;
Response.ContentType="application/outlook";
Response.AppendHeader("Content-Disposition", "filename=\"" + filename + "\"");
FileInfo fl = new FileInfo(path);
Response.AddHeader("Content-Length", fl.Length.ToString());
Response.TransmitFile(path,0,fl.Length);
Response.End();

Categories