As of this article I want to write a little C# scripting engine to work. I have tried this code:
System.IO.StreamReader sr = new System.IO.StreamReader("example.txt");
var prog = sr.ReadToEnd();
sr.Close();
ScriptOptions so = ScriptOptions.Default;
Console.WriteLine(CSharpScript.RunAsync(prog, so).Result.GetVariable("sum").Value);
Console.ReadKey();
And the file content of example.txt is:
System.IO.StreamReader sr = new System.IO.StreamReader("foo.txt");
string s = sr.ReadToEnd();
int sum = System.Convert.ToInt32(s);
Now I want to restrict the user to only basic functions of C# (using int, string, while, for) and some self defined functions but NOT the whole .NET library. But even if I don't include System.IO als reference the user can type System.IO.something and will get the right thing.
Is there a possibility to remove the access to "System" from the script?
I'm glad with any answer.
You'll need to set up the ScriptingOptions properly, meaning that a custom MetadataReferenceResolver needs to be used instead of the default one, which is resolving the missing references automatically. I don't know if there is already a resolver that only resolves assemblies based on its parameters, but you can certainly implement yours. Check out the TestMetadataReferenceResolver, which does something similar.
Update
This won't work for things that are defined in mscorlib.
Related
I need to create a registry entry based on finding of 32/64-bit system from cake script. I can see the File operations reference, Directory operations reference in C# cake site. But i could not find the registry related reference in C# cake. Could anyone please let me know is there any option to make a registry entry using C# cake? If so, please specify the reference link. This will help me a lot to continue in cake script.
An alternative to using C# you could also be using the Reg.exe shipped with all major versions of Windows.
You could use this tool with Cake using StartProcess alias.
An example of doing this below:
DirectoryPath system32Path = Context.Environment
.GetSpecialPath(SpecialPath.Windows)
.Combine("System32");
FilePath regPath = system32Path.CombineWithFilePath("reg.exe");
string keyName = "HKEY_CURRENT_USER\\Software\\Cake";
string valueName = "Rocks";
string valueData = "1";
ProcessSettings regSettings = new ProcessSettings()
.WithArguments(
arguments => arguments
.Append("add")
.AppendQuoted(keyName)
.Append("/f")
.AppendSwitchQuoted("/v", valueName)
.AppendSwitchQuoted("/t", "REG_DWORD")
.AppendSwitchQuoted("/d", valueData)
);
int result = StartProcess(regPath, regSettings);
if (result == 0)
{
Information("Registry value successfully set");
}
else
{
Information("Failed to set registry value");
}
Currently, there are no Cake aliases for working with the registry. Having said that, there is nothing to stop you manipulating the Registry directly using that standard C# types.
An example of one such approach is here:
Writing to registry in a C# application
Cake provides a number of aliases for things that are more complicated to do, however, remember that almost everything that is provided in an alias could be done directly with C# in your main script. The aliases are simply there as a convenience.
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.
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.
I have a WCF which I can call from a VB.NET application like this:
Dim tcp As New TCPService2.Service1Client
ExStreamPath = "C:\Program Files\Exstream\Dialogue 6.1\Engine.exe"
datPath = "-FILEMAP=DataFile,\\Dev-srv1\Exstream\LetterWriterApp\Input Files\Data Files\SAVEezkazivaftf40s452ndayb45.dat"
optPath = "-CONTROLFILE=C:\Exstream\Development\LetterWriter\ControlFiles\Letter.opt"
tcp.StartExStream(datPath, optPath, ExStreamPath)
The previous code kicks off a subroutine in a WCF (written in VB.NET), which uses the process object to start a 3rd party executable (with the arguments listed above). The code works great.
But, I'm having problems making the same type of call with C#. I think it might have something to do with a VB WCF being passed C# filepaths (the whole double-\\ thing), but I'm not sure. When trying to run the following code, I'm getting a 'File Not Found' error. The paths have been copied and pasted, so I know the paths are identical. Here's the C#:
tcpExstream.Service1Client MyTCP = new tcpExstream.Service1Client();
string ExStreamPath;
string datPath;
string optPath;
ExStreamPath = #"C:\Program Files\Exstream\Dialogue 6.1\Engine.exe";
datPath = #"-FILEMAP=DataFile,\\Dev-srv1\Exstream\LetterWriterApp\Input Files\Data Files\SAVEezkazivaftf40s452ndayb45.dat";
optPath = #"-CONTROLFILE=C:\Exstream\Development\LetterWriter\ControlFiles\Letter.opt";
MyTCP.StartExStream(ExStreamPath, datPath, optPath);
Any ideas?
Thanks in advance,
Jason
Your arguments appear in a different order between the two.
Compare:
tcp.StartExStream(datPath, optPath, ExStreamPath)
With:
MyTCP.StartExStream(ExStreamPath, datPath, optPath);
Back in .NET 1.0 days I wrote a method to return the target of a shortcut on MS Windows. It did this through using an interop to the Windows Script Hosting Object Model and brute forced through the COM interface:
private FileInfo GetFileFromShortcut(FileInfo shortcut)
{
FileInfo targetFile = null;
try
{
IWshRuntimeLibrary.WshShell wShell = new IWshRuntimeLibrary.WshShellClass();
IWshRuntimeLibrary.WshShortcut wShortcut = (IWshRuntimeLibrary.WshShortcut)wShell.CreateShortcut(shortcut.FullName);
// if the file wasn't a shortcut then the TargetPath comes back empty
string targetName = wShortcut.TargetPath;
if (targetName.Length > 0)
{
targetFile = new FileInfo(targetName);
}
}
catch (Exception)
{ // will return a null targetFile if anything goes wrong
}
return targetFile;
}
This still bugs me, and I was looking to replace this with something more elegant, but only if the replacement actually works at least as well. I still can't find a native C# way of finding the target of a shortcut. Is there one, or is this still the best way of doing this type of thing?
It looks like someone has written a class to manipulate shortcut files in C# called ShellLink, but it too uses COM.
Can't you just open the .lnk or .url file and parse it?
This talks about the same thing and shows what the files look like:
http://www.programmingtalk.com/showthread.php?t=7335
I got interested in this as well a while ago.
Here is the accepted response with a link to a (informal) description of the format of LNK files. Apparently, all available methods yet go through some API.