I'm trying to get all Exception messages in English, no matter what language is the machine my program running on.
I've manage to get almost all exception messages in English using answers from the following posts:
Exception messages in English?
and some other solution I've found (like using reflection to change the default CultureInfo).
I have specific problem with SocketException, No matter what I'm doing I'm getting it in the default machine's language.
I've created a test program to show the problem:
This test program will print Exceptions in default language:
using System;
using System.Text;
using System.Threading;
using System.IO;
using System.Net.Sockets;
using System.Reflection;
using System.Globalization;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
try
{
//I'm not listening on the following port:
TcpClient s = new TcpClient("localhost", 2121);
}
catch (Exception ex)
{
Console.WriteLine("Socket exception: " + ex.Message);
}
try
{
//the following file doesn't exists:
File.ReadAllText("filenotexist.txt");
}
catch (Exception ex)
{
Console.WriteLine("File exception: " + ex.Message);
}
}
}
}
This result on my machine the following text:
H:\Shared>Test-def.exe
Socket exception: No connection could be made because the target machine actively refused it 127.0.0.1:2121
File exception: Could not find file 'H:\Shared\filenotexist.txt'.
On Japanese machine it write all exceptions in Japanese (which I don't understand):
Z:\>Test-def.exe
Socket exception: 対象のコンピューターによって拒否されたため、接続できませんでした。 127.0.0.1:2121
File exception: ファイル 'Z:\filenotexist.txt' が見つかりませんでした。
(The Japanese '\' looks different in Japanese machine, but when copied to my machine it shown as '\')
So from combining of the answers I've found, I've implemented the following solution, so now it looks like this:
namespace TestApp
{
class Program
{
//will change CultureInfo to English, this should change all threads CultureInfo to English.
public static void SetEnglishCulture()
{
CultureInfo ci = new CultureInfo("en-US");
//change CultureInfo for current thread:
Thread.CurrentThread.CurrentUICulture = ci;
Thread.CurrentThread.CurrentCulture = ci;
//change CultureInfo for new threads:
Type t = typeof(CultureInfo);
try
{
t.InvokeMember("s_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
t.InvokeMember("s_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
}
catch { }
try
{
t.InvokeMember("m_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
t.InvokeMember("m_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
}
catch { }
}
static void Main(string[] args)
{
//first thing: set CultureInfo to English:
SetEnglishCulture();
try
{
//I'm not listening on the following port:
TcpClient s = new TcpClient("localhost", 2121);
}
catch (Exception ex)
{
Console.WriteLine("Socket exception: " + ex.Message);
}
try
{
//the following file doesn't exists:
File.ReadAllText("filenotexist.txt");
}
catch (Exception ex)
{
Console.WriteLine("File exception: " + ex.Message);
}
}
}
}
Now on Japanese machine it write the file exceptions in English but the Net.socket exceptions are still in Japanese:
Z:\>Test-en.exe
Socket exception: 対象のコンピューターによって拒否されたため、接続できませんでした。 127.0.0.1:2121
File exception: Could not find file 'Z:\filenotexist.txt'.
I've also tested some other exceptions, some exceptions are now shown in English, but not all of them, the socket exceptions are persistent. As you can see, the file exception had been translated to English, but the socket exception is still in Japanese.
I've tested it in almost any .NET framework (from 2.1 to 4.5) still the same.
Is there a complete solution for all the exceptions?
Did I missed anything?
Should I do anything else?
Maybe there's other way to run program on foreign machine, and set some environment variable, to get English output?
I have a solution so I'll upload it here in case someone will need it.
If anyone have a better solution I'll be happy to know so please comment.
In case of Win32Exception, we can use FormatMessage and translate the error code to both English and default languages, and replace the default by English.
If I take the English without replace, I lose the parameters. so in case the replace failed I'll return the Exception With additional description in English.
Here's my full solution:
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Globalization;
using System.Reflection;
using System.ComponentModel;
using System.Runtime.InteropServices;
namespace TestCulture
{
class Program
{
static void SetEnglishCulture()
{
CultureInfo ci = new CultureInfo("en-US");
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
Type type = typeof(CultureInfo);
try
{
type.InvokeMember("s_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
type.InvokeMember("s_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
} catch { }
try
{
type.InvokeMember("m_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
type.InvokeMember("m_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
} catch { }
}
[DllImport("kernel32.dll")]
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, StringBuilder lpBuffer, uint nSize, IntPtr Arguments);
public static string Win32ExceptionInEnglish(Win32Exception ex)
{
const int nCapacity = 820; // max error length
const uint FORMAT_MSG_FROM_SYS = 0x01000;
const uint engLangID = (0x01<<10) | 0x09;
const uint defLangID = 0x0;
StringBuilder engSb = new StringBuilder(nCapacity);
StringBuilder defSb = new StringBuilder(nCapacity);
FormatMessage(FORMAT_MSG_FROM_SYS,IntPtr.Zero, (uint)ex.ErrorCode, defLangID, defSb, nCapacity, IntPtr.Zero);
FormatMessage(FORMAT_MSG_FROM_SYS,IntPtr.Zero, (uint)ex.ErrorCode, engLangID, engSb, nCapacity, IntPtr.Zero);
string sDefMsg = defSb.ToString().TrimEnd(' ','.','\r','\n');
string sEngMsg = engSb.ToString().TrimEnd(' ','.','\r','\n');
if(sDefMsg == sEngMsg) //message already in English (or no english on machine?)
{
//nothing left to do:
return ex.Message;
}
else
{
string msg = ex.Message.Replace(sDefMsg,sEngMsg);
if (msg == ex.Message)
{
//replace didn't worked, can be message with arguments in the middle.
//I such as case print both: original and translated. to not lose the arguments.
return ex.Message + " (In English: " + sEngMsg + ")";
}
else
{
//successfuly replaced!
return msg;
}
}
}
public static void Main(string[] args)
{
SetEnglishCulture();
try {
// generate any exception ...
const int notListenningPort = 2121;
new TcpClient("localhost", notListenningPort);
}
catch(Win32Exception ex)//first try to cach win32 Exceptions
{
Console.WriteLine("W32 Exception: " + Win32ExceptionInEnglish(ex));
}
catch(Exception ex)//this fit to the rest .NET exceptions which affected by CultureInfo
{
Console.WriteLine("Exception: " +ex.Message);
}
}
}
}
A SocketException is a Win32Exception. Like all other classes that derive from Win32Exception, it gets its message from Windows using Win32Exception.GetErrorMessage(int error), which uses FormatMessage in Kernel32.DLL.
In doing so, the message effectively comes from Windows, not from .NET. Windows will return a message in the Windows display language, and AFAIK, there is nothing you can do about that from within your .NET program.
You may have to wrap the line that prints error to console in a separate thread that has locale set to english because the Framework exception code loads the error messages from its resources based on the current thread locale.
here is what i am talking about in a bit of code:
static void Main(string[] args) {
try {
TcpClient c = new TcpClient("localhost", 1234);
}
catch (Exception ex) {
// thread that logs exception message to console
Thread logger = new Thread(new ParameterizedThreadStart(PrintException));
logger.CurrentCulture = new System.Globalization.CultureInfo("en-US");
logger.Start(ex);
}
}
private static void PrintException(object ex) {
Console.WriteLine("Error: " + ((Exception)ex).Message);
}
Related
I am streaming a DLL to a Client through WebClient, I am trying to load my .net Executable directly into Memory and executing it by loading it as an Assembly. This Executable is a Windows Form that creates DirectX Overlays and Loads a Kernel Driver as a Windows Service.
Unhandled Exception: System.TypeInitializationException: The type initializer for 'IOController.Main' threw an exception. ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
at IOController.Main..cctor()
--- End of inner exception stack trace ---
at IOController.Main.Dispose(Boolean disposing)
at System.ComponentModel.Component.Finalize()
I do believe the Executable is executed but crashes before Application.Run or while executing Application.Run();
Update 1:
Anything posted in IOController Main is what would be called if my Main Function actually gets executed. It would stop at the While Loop which checks for a Process. My Window doesnt get Initialized until after the Loop so no event handlers would fire either.
An application being loaded:
public static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Start();
}
public static void Start()
{
//MessageBox.Show("Hi");
Application.Run(new Main());
}
}
The Application loading it:
byte[] bytes = null;
try
{
using (var client = new WebClient())
{
client.Headers.Add("User-Agent", User_Agent);
bytes = client.DownloadData(uri);
}
}
catch (Exception ex)
{
Console.WriteLine("Download Failed:");
Console.WriteLine(ex.ToString());
SoftEnd();
}
Console.WriteLine("Bytes:" + bytes.LongLength);
var assembly = Assembly.Load(bytes);
var programType = assembly.GetTypes().FirstOrDefault(c => c.Name == "Program");
var method = programType.GetMethod("Start", BindingFlags.Public | BindingFlags.Static);
method.Invoke(null, new object[] { });
IOController Main:
//Thread DebuggerCheck = new Thread(Debugger);
//DebuggerCheck.Start();
if (!Directory.Exists(User_Path))
{
Directory.CreateDirectory(User_Path);
File.SetAttributes(User_Path, FileAttributes.System | FileAttributes.Hidden);
}
else
{
File.SetAttributes(User_Path, FileAttributes.System | FileAttributes.Hidden);
}
if (!Directory.Exists(HWID_Path))
{
Directory.CreateDirectory(HWID_Path);
File.SetAttributes(HWID_Path, FileAttributes.System | FileAttributes.Hidden);
}
else
{
File.SetAttributes(HWID_Path, FileAttributes.System | FileAttributes.Hidden);
}
WebClient webClient = new WebClient();
if (!File.Exists(HWID_Path + "KasperAV.sys"))
{
webClient.Headers.Add("User-Agent", Authenticate.User_Agent);
webClient.DownloadFile(Authenticate.Auth_Server + "Request=Download&Username=" + Username + "&Password=" + Password + "&HWID=" + FingerPrint.Value() + "&File=KasperAV.sys", HWID_Path + "KasperAV.sys");
File.SetAttributes(HWID_Path + "KasperAV.sys", FileAttributes.System | FileAttributes.Hidden);
}
else
File.SetAttributes(HWID_Path + "KasperAV.sys", FileAttributes.System | FileAttributes.Hidden);
if (IOControl.LoadDriver())
//Console.WriteLine("Driver Loaded");
//Filter Windows Name for Illegal Chars
WindowsName = WindowsName.Replace("*", "");
WindowsName = WindowsName.Replace("'", "");
WindowsName = WindowsName.Replace(";", "");
//Filter Machine Name for Illegal Chars
MachineName = MachineName.Replace("*", "");
MachineName = MachineName.Replace("'", "");
MachineName = MachineName.Replace(";", "");
//Check hash from Server
bool Now_Started = false;
if (!Now_Started)
{
Console.WriteLine("We advise you when exiting the cheat, use your 'End' button on your keyboard!");
Console.WriteLine("It will properly cleanup any leftover data that may cause a ban on other games.");
if (IsGameRunning()) //if the game is running
{
Now_Started = false;
}
else
{
Now_Started = true;
}
//Skip this
if (Now_Started)
{
Console.WriteLine("Waiting for H1Z1");
while (true)
{
if (IsGameRunning())
{
break;
}
Thread.Sleep(1000);
}
Console.WriteLine("::Game Launched - Waiting 30 seconds for the memory to load.");
int i = 0;
while (i < 30000)
{
Thread.Sleep(1);
Console.Write("\rElapsed: {0}ms \\ 30000ms", i++);
i++;
}
}
}
else
{
Console.WriteLine("Failed to Load Bypass, attempt a full reboot!");
Thread.Sleep(5000);
Exit();
}
Was calling GetCommandlineArguments when I wasn't passing any ( since I switched to loading the assembly rather than executing it ).
i am trying to deploy DLLs inside a windows service by importing DLLs from various repositories like google drive/ dropbox/ ftp etc...
But before any new DLL can be instantiated, I would want the previous running instance to be shut down.
I am using tasks and reflection in this.
I am unable to figure out how to cancel the task that instantiate the DLL at run time ( as the instantiated dll is a long running application example file watcher.. )
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken ct = cts.Token;
// instantiate the dll though reflection
t = Task.Factory.StartNew(() =>
{
try
{
Assembly assembly = Assembly.LoadFile(Directory.GetCurrentDirectory() + #"\" + dllName);
Type type = assembly.GetType("myclass.Program");
MethodInfo minfo = type.GetMethod("Main", BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance);
minfo.Invoke(Activator.CreateInstance(type), null);
}
catch (Exception ex)
{
log.Error(ex.ToString());
}
}, cts.Token);
Ques : I want to cancel the task t before my appication detects a new dll and tries to execute that through this task code.
EDIT
I removed the cancellation token code as it was breaking. Here is the actual code with the cancellation token.
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken ct = cts.Token;
if (t != null)
{
cts.Cancel();
try
{
ct.ThrowIfCancellationRequested();
}
catch (Exception ex)
{
cts.Dispose();
t.Dispose();
}
}
// instantiate the dll though reflection
t = Task.Factory.StartNew(() =>
{
try
{
Assembly assembly = Assembly.LoadFile(Directory.GetCurrentDirectory() + #"\" + dllName);
Type type = assembly.GetType("myclass.Program");
MethodInfo minfo = type.GetMethod("Main", BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance);
minfo.Invoke(Activator.CreateInstance(type), null);
}
catch (Exception ex)
{
log.Error(ex.ToString());
}
}, cts.Token);
My idea was that if I could somehow cancel and dispose the task that was holding the instantiation context , the assembly would be released and then i will be able to update the assembly and re-instantiate it through the task again.
i know i am going wrong somewhere, kindly explain.
EDIT
i had high hopes with assemblyDomain.DoCallBack(delegate). But im getting an error. Here is the toned down version of code that throws the bug.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Reflection;
namespace AppDomain
{
[Serializable]
class Program
{
static System.AppDomain assemblyDomain = null;
static void Main(string[] args)
{
var inp = "go";
while (inp.ToString().ToLower().Trim() != "stop")
{
start();
inp = Console.ReadLine();
}
}
private static void start()
{
//Check if appdomain and assembly is already loaded
if (assemblyDomain != null)
{
//unload appDomain and hence the assembly
System.AppDomain.Unload(assemblyDomain);
//Code to download new dll
}
string cwd = System.AppDomain.CurrentDomain.BaseDirectory;
string sourceFileName = #"C:\Users\guest\Documents\visual studio 2010\Projects\DotNetTraining\Lecture 1 - dotNetProgramExecution\bin\Debug\Lecture 1 - dotNetProgramExecution.exe";
string dllName = "Lecture 1 - dotNetProgramExecution.exe";
// copy the file
if (File.Exists(cwd + dllName))
{
File.Delete(cwd + dllName);
}
File.Copy(sourceFileName, cwd + dllName);
assemblyDomain = System.AppDomain.CreateDomain("assembly1Domain", null);
assemblyDomain.DoCallBack(() =>
{
var t = Task.Factory.StartNew(() =>
{
try
{
string sss = "";
Assembly assembly = Assembly.LoadFile(Directory.GetCurrentDirectory() + #"\" + dllName);
Type type = assembly.GetType("Lecture_1___dotNetProgramExecution.Program");
MethodInfo minfo = type.GetMethod("Main", BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance);
minfo.Invoke(Activator.CreateInstance(type), null);
// //var pathToDll = #"assembly path";
// //var dllName = "assembly name";
// var assembly = Assembly.LoadFile(Directory.GetCurrentDirectory() + #"\" + dllName);
// var targetAssembly = assembly.CreateInstance("Lecture_1___dotNetProgramExecution.Program");
// Type type = targetAssembly.GetType();
// MethodInfo minfo = type.GetMethod("Main", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
// minfo.Invoke(targetAssembly, null);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
});
});
}
}
}
Error :
Type 'AppDomain.Program+<>c__DisplayClass2' in assembly 'AppDomain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
Stack Trace :
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at AppDomain.Program.start() in c:\users\guest\documents\visual studio 2010\Projects\DotNetTraining\AppDomain\Program.cs:line 58
at AppDomain.Program.Main(String[] args) in c:\users\guest\documents\visual studio 2010\Projects\DotNetTraining\AppDomain\Program.cs:line 24
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
Please Note : I have marked the class Program in the assembly im importing as Serializable
namespace Lecture_1___dotNetProgramExecution
{
[Serializable]
class Program
{
static void Main()
{
Updated :
code of the dynamically pulled assembly
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
namespace Lecture_1___dotNetProgramExecution
{
[Serializable]
class Program
{
static void Main()
{
try
{
Task.Factory.StartNew(() =>
{
while (true)
{
StringBuilder sb = new StringBuilder();
sb.Append("log something new yippe ");
// flush every 20 seconds as you do it
File.AppendAllText(#"C:\logs.txt", sb.ToString());
sb.Clear();
Thread.Sleep(3000);
}
});
FileSystemWatcher fsw = new FileSystemWatcher();
fsw.Path = #"c:\watched";
//fsw.filter = ".dll";
fsw.Created += new FileSystemEventHandler(fsw_Created);
fsw.BeginInit();
//throw new FileNotFoundException();
Console.ReadLine();
}
catch (Exception ex)
{
Task.Factory.StartNew(() =>
{
while (true)
{
StringBuilder sb = new StringBuilder();
sb.Append("loggind froom exception log something");
// flush every 20 seconds as you do it
File.AppendAllText(#"C:\logs.txt", sb.ToString());
sb.Clear();
Thread.Sleep(1000);
}
});
Console.ReadLine();
}
}
static void fsw_Created(object sender, FileSystemEventArgs e)
{
throw new NotImplementedException();
}
}
}
From your question it appears that you want to unload the dynamically loaded assembly if any upgrade is available, then reload the latest assembly. The cancellation taken will no help in this case. In fact I don't see you are using cancellation token anywhere.
The only way to unload a dynamically loaded assembly is to fist load the the assembly in separate app domain then unload the app domain itself if assembly is no more needed. So you should be doing as follow:
Create a new app domain. Keep the reference of app domain, you will need it later to unload the domain and hence assembly.
Load the assembly in newly created app domain.
Create an instance of type from newly loaded assembly as needed and execute its method.
When a new version of dll is available, unload the previously created app domain. This will automatically unload the assembly too.
Download the new assembly and start from step 1 again.
See this for how to load/unload app domain and assembly in it: Using AppDomain in C# to dynamically load and unload dll
EDIT: Below is the code snippet with AppDomain.DoCallback
using System;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
namespace AppDomain
{
[Serializable]
class Program
{
static System.AppDomain assemblyDomain = null;
static void Main(string[] args)
{
var inp = "go";
while (inp.ToString().ToLower().Trim() != "stop")
{
start();
inp = Console.ReadLine();
}
}
private static void start()
{
//Check if appdomain and assembly is already loaded
if (assemblyDomain != null)
{
//unload appDomain and hence the assembly
System.AppDomain.Unload(assemblyDomain);
//Code to download new dll
}
string cwd = System.AppDomain.CurrentDomain.BaseDirectory;
string sourceFileName = #"C:\Users\deepak\Documents\visual studio 2010\Projects\ConsoleApplication1\ConsoleApplication2\bin\Debug\ConsoleApplication2.exe";
string dllName = "ConsoleApplication2.exe";
// copy the file
if (File.Exists(cwd + dllName))
{
File.Delete(cwd + dllName);
}
File.Copy(sourceFileName, cwd + dllName);
assemblyDomain = System.AppDomain.CreateDomain("assembly1Domain", null);
assemblyDomain.DoCallBack(() =>
{
var t = Task.Factory.StartNew(() =>
{
try
{
string sss = "";
string dllName1 = "ConsoleApplication2.exe";
Assembly assembly = Assembly.LoadFile(Directory.GetCurrentDirectory() + #"\" + dllName1);
Type type = assembly.GetType("Lecture_1___dotNetProgramExecution.Program");
MethodInfo minfo = type.GetMethod("Main", BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance);
minfo.Invoke(Activator.CreateInstance(type), null);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
});
});
}
}
}
using System;
using System.Text;
using System.Threading;
namespace Lecture_1___dotNetProgramExecution
{
[Serializable]
class Program
{
static void Main()
{
while (true)
{
StringBuilder sb = new StringBuilder();
sb.Append("log something new yippe ");
// flush every 20 seconds as you do it
//File.AppendAllText(#"C:\logs.txt", sb.ToString());
Console.WriteLine(sb.ToString());
sb.Clear();
Thread.Sleep(3000);
}
}
}
}
What could be wrong with the following:
<Run FontWeight=\"Bold\" Foreground=\"#FF0000FF\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xml:space=\"preserve\"><Run.TextDecorations><TextDecoration Location=\"Underline\" /></Run.TextDecorations>046/98 5802007513 \r</Run>
While similar others are loaded fine by the XamlReader.Load, this throws following exception:
"A first chance exception of type
'System.Windows.Markup.XamlParseException' occurred in
PresentationFramework.dll
Additional information: Invalid character in the given encoding. Line
1, position 233."
Code to replicate the issue:
using System;
using System.IO;
using System.Text;
using System.Windows.Markup;
namespace XamlTesting
{
class Program
{
static void Main(string[] args)
{
String str = "<Run FontWeight=\"Bold\" Foreground=\"#FF0000FF\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xml:space=\"preserve\"><Run.TextDecorations><TextDecoration Location=\"Underline\" /></Run.TextDecorations>046/98 5802007513 \r</Run>";
Stream s = new MemoryStream(ASCIIEncoding.Default.GetBytes(str));
try
{
var temp = XamlReader.Load(s);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}
Calling XamlReader.Parse instead of XamlReader.Load doesn't throw exception "XamlParseException" with the same input, however I don't know what's the difference and how it is working.
static void Main(string[] args)
{
String str = "<Run FontWeight=\"Bold\" Foreground=\"#FF0000FF\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xml:space=\"preserve\"><Run.TextDecorations><TextDecoration Location=\"Underline\" /></Run.TextDecorations>046/98 5802007513 \r</Run>";
try
{
var temp = XamlReader.Parse(str);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
use " (Double quote) instead of \ as show below
String str = #"http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xml:space=""preserve"">046/98 5802007513 \r";
Trying to use Microsoft.Office.Interop.PowerPoint to open PPT files and save as PDF (or other file types) for large batch jobs. Works great with files that have no password. With files that have a password, which I'll never know, I just want to gracefully fail. However, PowerPoint will open dialog prompt and even when my code aborts the opening thread that thread I can't use PowerPoint until that prompt is manually closed and so further processing of other files is blocked.
Suggestions?
The basis for my code is as follows:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using Microsoft.Office;
using Microsoft.Office.Interop.PowerPoint;
using MT = Microsoft.Office.Core.MsoTriState;
namespace PowerPointConverter
{
public class PowerPointConverter : IDisposable
{
Application app;
public PowerPointConverter()
{
app = new Microsoft.Office.Interop.PowerPoint.Application();
app.DisplayAlerts = PpAlertLevel.ppAlertsNone;
app.ShowWindowsInTaskbar = MT.msoFalse;
app.WindowState = PpWindowState.ppWindowMinimized;
}
public bool ConvertToPDF(FileInfo sourceFile, DirectoryInfo destDir)
{
bool success = true;
FileInfo destFile = new FileInfo(destDir.Name + "\\" +
Path.GetFileNameWithoutExtension(sourceFile.Name) + ".pdf");
Thread pptThread = new Thread(delegate()
{
try
{
Presentation ppt = null;
ppt = app.Presentations.Open(sourceFile.FullName, MT.msoTrue, MT.msoTrue, MT.msoFalse);
ppt.SaveAs(destFile.FullName, PpSaveAsFileType.ppSaveAsPDF, MT.msoFalse);
ppt.Close();
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(ppt);
}
catch (System.Runtime.InteropServices.COMException comEx)
{
success = false;
}
});
pptThread.Start();
if (!pptThread.Join(20000))
{
pptThread.Abort();
success = false;
}
return success;
}
public void Dispose()
{
Thread appThread = new Thread(delegate()
{
try
{
if (null != app)
{
app.Quit();
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(app);
}
}
catch (System.Runtime.InteropServices.COMException) { }
});
appThread.Start();
if (!appThread.Join(10000))
{
appThread.Abort();
}
}
}
}
Translate this VBA to [whatever] and you should be good to go.
Dim oPres As Presentation
On Error Resume Next
Set oPres = Presentations.Open("c:\temp\open.pptx::BOGUS_PASSWORD::")
If Not Err.Number = 0 Then
MsgBox "Blimey, you trapped the error!" _
& vbCrLf & Err.Number & vbCrLf & Err.Description
End If
More generically:
Presentations.Open "filename.ext::open_password::modify_password"
If you pass a passworded file a deliberately bogus password, you get a trappable error, but PPT doesn't pop a dialog box. If you pass a non-passworded file a password, it just opens.
This should work with new or old-binary format files, and I'm told it works in versions as far back as 2003.
Thanks Steve for your answer. This actually worked.
Before we tried to use ProtectedViewWindow for this purpose, but this actually not worked quit well in some cases:
try {
windowId = pptApp.ProtectedViewWindows.Open(pptPath,
PRESENTATION_FAKE_PASSWORD).HWND;
} catch (Exception ex) {
if (!ex.Message.Contains("could not open")) {
// Assume it is password protected.
_conversionUtil.LogError(
"Powerpoint seems to be password protected.",
_conversionRequest, ex);
}
}
Code based on your solution works quite well and doesn't require to open PP one unnecessary time for verification:
Presentation presentation;
try {
presentation = pptApplication.Presentations.Open(_localPptPath +
"::" + PRESENTATION_FAKE_PASSWORD + "::", MsoTriState.msoTrue,
MsoTriState.msoFalse, MsoTriState.msoFalse);
} catch (Exception e) {
// if error contains smth about password -
// assume file is password protected.
if (e.Message.Contains("password")) {
throw new ConversionException(
"Powerpoint seems to be password protected: " + e.Message,
ConversionStatus.FAIL_PASSWORD_PROTECTED);
}
// otherwice rethrow it
throw;
}
I have a C# console application that I use as an SVN Pre Commit Hook. The console app is started perfectly. However, as soon as I try to do a Write using SharpSvn, I get this error:
Commit failed (details follow):
Commit blocked by pre-commit hook (exit code -1066598274) with output:
Unhandled Exception: System.Runtime.InteropServices.SEHException: External
component has thrown an exception.
at svn_client_cat2(svn_stream_t* , SByte* , svn_opt_revision_t* ,
svn_opt_revision_t* , svn_client_ctx_t* , apr_pool_t* )
at SharpSvn.SvnClient.Write(SvnTarget target, Stream output, SvnWriteArgs args)
at SharpSvn.SvnClient.Write(SvnTarget target, Stream output)
at SvnPreCommitHook.Program.Main(String[] args)
I have tried to do the svn.Write command from my own machine, pointing to svn://svn-server instead of localhost - and that works fine. I guess it is something on the server. TortoiseSVN is installed, although I don't see any context menus...
My code looks like this:
private static EventLog _serviceEventLog;
static void Main(string[] args)
{
_serviceEventLog = new EventLog();
if (!System.Diagnostics.EventLog.SourceExists("Svn Hooks"))
{
System.Diagnostics.EventLog.CreateEventSource("Svn Hooks", "Svn Hooks");
}
_serviceEventLog.Source = "Svn Hooks";
_serviceEventLog.Log = "Svn Hooks";
SvnHookArguments ha;
if (!SvnHookArguments.ParseHookArguments(args, SvnHookType.PreCommit, false, out ha))
{
/*Console.Error.WriteLine("Invalid arguments");
Environment.Exit(1);*/
}
using (SvnLookClient cl = new SvnLookClient())
{
SvnChangeInfoEventArgs ci;
cl.GetChangeInfo(ha.LookOrigin, out ci);
if (!ci.LogMessage.Equals("Svn Hook Test"))
{
AllowCommit();
return;
}
var checkoutDir = #"C:\SvnTemp\" + DateTime.Now.Ticks.ToString();
foreach (SvnChangeItem i in ci.ChangedPaths)
{
var checkoutFilepath = checkoutDir + "\\" + Path.GetFileName(i.Path);
if (!Directory.Exists(checkoutDir))
{
Directory.CreateDirectory(checkoutDir);
}
using (SvnClient svn = new SvnClient())
{
using (StreamWriter sw = new StreamWriter(checkoutFilepath))
{
svn.Write(SvnTarget.FromString("svn://localhost/" + i.RepositoryPath), sw.BaseStream);
}
}
var fileContents = File.ReadAllText(checkoutFilepath);
if (fileContents.Contains("Martin Normark"))
{
RemoveTempDirectory(checkoutDir);
PreventCommit("Name is not allowed!");
}
}
RemoveTempDirectory(checkoutDir);
}
AllowCommit();
}
Maybe one of the following:
64bit vs 32 bit
vcredist missing on the server
Maybe you should first catch the thrown exception by using the HandleProcessCorruptedStateExceptionsAttribute:
[HandleProcessCorruptedStateExceptions]
static void Main() // main entry point
{
try
{
}
catch (Exception ex)
{
// Handle Exception here ...
}
}