System.NullReferenceException at Process.start - c#

I have an application that uses Process.Start to execute an exe. It works fine for all the .exe that I have tested except when the .exe has a configuration file where it gets a connectionstring, when this happens I get a System.NullReferenceException. this is my code.
to execute the exe:
string eucApp = #"C:\Temp\app.exe"
startInfo = new ProcessStartInfo(eucApp);
using (Process execProcess = Process.Start(startInfo))
{
execProcess.WaitForExit();
}
then the exe starts and the first thing that does is get the a connection string with this code line
strCadena = ConfigurationManager.ConnectionStrings("ConnectionString")
If I replace this with the connectionstring like this, it works fine
strCadena = "Data Source=HostName;Initial Catalog=MyDB;Integrated security=True"
I would remove the config file and put its values into the .exe code but the trouble is that I have more than 500 .exe's that uses config files so if any one knows a way to avoide this please tell me!

thanks for your help. I figured out the problem. Somehow the .exe was pointing to the app.config of the aplication that start's the process. I added this class to the .exe that is developed in VB .Net
Imports System.Configuration
Imports System.Reflection
Public Class AppConfig
Implements IDisposable
Public Shared Function Change(ByVal path As String) As AppConfig
Return New ChangeAppConfig(path)
End Function
Public Overridable Sub Dispose() Implements IDisposable.Dispose
End Sub
Private Class ChangeAppConfig
Inherits AppConfig
Private ReadOnly oldConfig As String = AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE").ToString
Private disposedValue As Boolean
Public Sub New(ByVal path As String)
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", path)
ResetConfigMechanism()
End Sub
Public Overrides Sub Dispose()
If (Not disposedValue) Then
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", oldConfig)
ResetConfigMechanism()
disposedValue = True
End If
GC.SuppressFinalize(Me)
End Sub
Private Shared Sub ResetConfigMechanism()
GetType(ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic Or BindingFlags.Static).SetValue(Nothing, 0)
GetType(ConfigurationManager).GetField("s_configSystem", BindingFlags.NonPublic Or BindingFlags.Static).SetValue(Nothing, Nothing)
Dim assemblies() As Type = GetType(ConfigurationManager).Assembly.GetTypes()
For Each assembly As Type In assemblies
If (assembly.FullName = "System.Configuration.ClientConfigPaths") Then
assembly.GetField("s_current", BindingFlags.NonPublic Or BindingFlags.Static).SetValue(Nothing, Nothing)
Exit For
End If
Next
End Sub
End Class
End Class
I call Change function at the begining of the program
AppConfig.Change(Application.StartupPath & "\app.exe.Config")
This way it take the right config file

Related

Inno Setup - External .NET DLL with dependencies

I am trying to use a custom DLL in a Inno Setup script during installation. I wrote a very simple function that basically checks a connection string for a MySQL database using MySQL .NET connector (there is no MySQL client on the target server). The code of this exported function is:
public class DbChecker
{
[DllExport("CheckConnexion", CallingConvention.StdCall)]
public static int CheckConnexion([MarshalAs(UnmanagedType.LPStr)] string connexionString)
{
int success;
try
{
MySqlConnection connection = new MySqlConnection(connexionString);
connection.Open();
connection.Close();
success = 0;
}
catch (Exception)
{
success = 1;
}
return success;
}
}
The function is imported this way in Inno Setup :
[Files]
Source: "..\..\MyDll\bin\x86\Release\*"; Flags: dontcopy;
and
[Code]
function CheckConnexion(connexionString: AnsiString): Integer;
external 'CheckConnexion#files:MyDll.dll,MySql.Data.dll stdcall setuponly loadwithalteredsearchpath';`
The problem is that the setup throws an exception at runtime:
Runtime Error (at 53:207):
External exception E0434352.
I think I have to use the files prefix because the function is called in the NextButtonClick event handler, before files are copied to the {app} directory.
Both MyDll.dll and MySql.Data.dll are correctly extracted to the {tmp} directory at runtime.
I tried both with and without the loadwithalteredsearchpath flag with the same result.
What I found is that this error code is a generic .NET runtime error code.
If I remove the part using MySql.Data it works perfectly fine (except that it does nothing...)
As advised on other threads I've been trying to log the error in my .NET code using EventLog and UnhandledException but I have the same exception no matter what (and no log source is created), even without the MySQL part. I checked EventLog permissions on my computer.
It seems that the exception is thrown as soon as I use anything else that "basic" C# code (whenever I try to load another DLL).
There is probably a better way, but this will do.
Implement an initialization function (Init here) that sets up AppDomain.AssemblyResolve handler that looks for an assembly in the path of the main (executing) assembly:
[DllExport("Init", CallingConvention.StdCall)]
public static void Init()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);
}
private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
string location = Assembly.GetExecutingAssembly().Location;
AssemblyName name = new AssemblyName(args.Name);
string path = Path.Combine(Path.GetDirectoryName(location), name.Name + ".dll");
if (File.Exists(path))
{
return Assembly.LoadFrom(path);
}
return null;
}
Import it to the Inno Setup:
procedure Init(); external 'Init#files:MyDll.dll stdcall setuponly';
And call it before calling the function that needs the dependency (CheckConnexion).
Another solution might be this:
Embedding DLLs in a compiled executable
Btw, no need for the loadwithalteredsearchpath flag. It has no effect on .NET assemblies imo. They are needed for native DLL dependencies: Loading DLL with dependencies in Inno Setup fails in uninstaller with "Cannot import DLL", but works in the installer.
I found something else that might be helpful for anyone stumbling upon this page.
In my scenario, I have several C# methods that I call from InnoSetup using DllExport. In one of those methods, I call another of the methods. This caused Inno to throw "External exception E0434352".
If I moved the code to a method not called by InnoSetup, everything worked fine.
So...
[DllExport("Fu", CallingConvention = CallingConvention.StdCall)]
public static int Fu()
{
// Stuff
}
[DllExport("Bar", CallingConvention = CallingConvention.StdCall)]
public static int Bar()
{
Fu();
}
...causes InnoSetup to cry, but:
[DllExport("Fu", CallingConvention = CallingConvention.StdCall)]
public static int Fu()
{
LocalFu();
}
private static int LocalFu()
{
// Stuff
}
[DllExport("Bar", CallingConvention = CallingConvention.StdCall)]
public static int Bar()
{
// Stuff
LocalFu();
// Other stuff
}
...is fine.
I don't know if this is caused by Inno or DllExport, so I'll forgo direct derision and blame society as a whole for my lost morning. (Or myself for being a new to this thing.)
I would like to expand upon Martin's answer. There is a way to resolve the assemblies without having to call an Init method first and that is by including a static constructor in your .NET class:
public class MyClass
{
static MyClass()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += MyResolveEventHandler;
}
private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
var location = Assembly.GetExecutingAssembly().Location;
var assemblyName = new AssemblyName(args.Name);
var path = Path.Combine(Path.GetDirectoryName(location), assemblyName.Name + ".dll");
if (File.Exists(path))
{
return Assembly.LoadFrom(path);
}
return null;
}
}

How do I use FileOpen (VB.NET) in C#?

So, I'm working on converting this code from VB.NET to C#:
Public Class Form1
Const filesplit As String = "|split|"
Dim stub, opt() As String
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
On Error Resume Next
FileOpen(1, Application.ExecutablePath, OpenMode.Binary, OpenAccess.Read, OpenShare.Shared)
stub = Space(LOF(1))
FileGet(1, stub)
FileClose(1)
opt = Split(stub, filesplit)
End Sub
End Class
I've used a series of online converters, and they don't really work for me.
How do I do it? I'm trying to understand VB.NET source code so I can use it in.
Those methods are in the Microsoft.VisualBasic Namespace.
So you could just add a reference to that in your project and then use virtually the exact same code with a small amount of extra qualification on the methods used:
using Microsoft.VisualBasic; //add this statement
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
string filesplit = "|split|";
string stub;
string[] opt;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
FileSystem.FileOpen(1, Application.ExecutablePath, OpenMode.Binary, OpenAccess.Read, OpenShare.Shared);
stub = Strings.Space(Convert.ToInt32(FileSystem.LOF(1)));
FileSystem.FileGet(1, ref stub);
FileSystem.FileClose(1);
opt = Strings.Split(stub, filesplit);
}
}
}
However you should really look into using the File.xxx methods in the System.IO namespace in both your VB.NET and C# code going forward, but this will get it working for you.
Use File.Open. That should get you what you want.
Your VB code is essentially doing this:
// The using clause ensures the StreamReader is properly disposed after the closing block.
using (StreamReader sr = File.OpenText(Application.ExecutablePath))
{
stub = sr.ReadToEnd();
opt = stub.Split(filesplit).ToArray();
}
This assumes filesplit is a char, string or something like Environment.NewLine
Basically you would use :
Dim content = File.ReadAllText("c:\temp\MyTest.txt")
However it would be more correct to use:
Dim path As String = "c:\temp\MyTest.txt"
If File.Exists(path) Then
Dim content = File.ReadAllText(path)
Rem do something with content
End If

Using a .Net DLL in Microsoft Access VBA

Ok so I have an assembly, written in C#, using Visual Studio 2010.
This Assembly contains one class, which contains one method which returns the word Result, the code is below:
using System.Runtime.InteropServices;
namespace TestDLL
{
public class Class1
{
[ComVisible(true)]
public string TestMethod()
{
return "Result";
}
}
}
The output section in the Build tab on the properties window looks like so:
When I click on Build, I get a DLL file and a TLB file. I can add this TLB file to Microsoft Access simply by browsing to it.
Now, in Access I have a button and a label. I want to make the Caption property of my label equal to the result of testMethod. I'm thinking I need to do something similar to below but I'm not sure, any help would be much appreciated:
Private Sub btnMain_Click()
Dim tm As TestDLL
Dim foo As String
foo = tm.testMethod
lblBarr.Caption = foo
End Sub
Thankyou
Maybe next will work:
Private Sub btnMain_Click()
Dim tm As TestDLL.Class1
Dim foo As String
Set tm = New TestDLL.Class1
foo = tm.testMethod
lblBarr.Caption = foo
End Sub

Dynamically call web service!

I need to dynamically call web service! For this I made simple web service Service1.asmx
Then I created the proxy class for the Service1 Web Service, I use the WSDL.exe utility and following command at the command prompt:
wsdl /language:VB /out:myclass.vb http://localhost:3245/Service1.asmx?WSDL
This command create class myclass.vb. That class I include in my Windows Application project, but when I do this I get lot of errors.
This is the how created class look like:
Imports System
Imports System.ComponentModel
Imports System.Diagnostics
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Xml.Serialization
'
'This source code was auto-generated by wsdl, Version=2.0.50727.1432.
'
'''<remarks/>
<System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.1432"), _
System.Diagnostics.DebuggerStepThroughAttribute(), _
System.ComponentModel.DesignerCategoryAttribute("code"), _
System.Web.Services.WebServiceBindingAttribute(Name:="Service1Soap", [Namespace]:="http://tempuri.org/")> _
Partial Public Class Service1
Inherits System.Web.Services.Protocols.SoapHttpClientProtocol
Private HelloWorldOperationCompleted As System.Threading.SendOrPostCallback
'''<remarks/>
Public Sub New()
MyBase.New
Me.Url = "http://localhost:3245/Service1.asmx"
End Sub
'''<remarks/>
Public Event HelloWorldCompleted As HelloWorldCompletedEventHandler
'''<remarks/>
<System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/HelloWorld", RequestNamespace:="http://tempuri.org/", ResponseNamespace:="http://tempuri.org/", Use:=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle:=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)> _
Public Function HelloWorld() As String
Dim results() As Object = Me.Invoke("HelloWorld", New Object(-1) {})
Return CType(results(0),String)
End Function
'''<remarks/>
Public Function BeginHelloWorld(ByVal callback As System.AsyncCallback, ByVal asyncState As Object) As System.IAsyncResult
Return Me.BeginInvoke("HelloWorld", New Object(-1) {}, callback, asyncState)
End Function
'''<remarks/>
Public Function EndHelloWorld(ByVal asyncResult As System.IAsyncResult) As String
Dim results() As Object = Me.EndInvoke(asyncResult)
Return CType(results(0),String)
End Function
'''<remarks/>
Public Overloads Sub HelloWorldAsync()
Me.HelloWorldAsync(Nothing)
End Sub
'''<remarks/>
Public Overloads Sub HelloWorldAsync(ByVal userState As Object)
If (Me.HelloWorldOperationCompleted Is Nothing) Then
Me.HelloWorldOperationCompleted = AddressOf Me.OnHelloWorldOperationCompleted
End If
Me.InvokeAsync("HelloWorld", New Object(-1) {}, Me.HelloWorldOperationCompleted, userState)
End Sub
Private Sub OnHelloWorldOperationCompleted(ByVal arg As Object)
If (Not (Me.HelloWorldCompletedEvent) Is Nothing) Then
Dim invokeArgs As System.Web.Services.Protocols.InvokeCompletedEventArgs = CType(arg,System.Web.Services.Protocols.InvokeCompletedEventArgs)
RaiseEvent HelloWorldCompleted(Me, New HelloWorldCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState))
End If
End Sub
'''<remarks/>
Public Shadows Sub CancelAsync(ByVal userState As Object)
MyBase.CancelAsync(userState)
End Sub
End Class
'''<remarks/>
<System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.1432")> _
Public Delegate Sub HelloWorldCompletedEventHandler(ByVal sender As Object, ByVal e As HelloWorldCompletedEventArgs)
'''<remarks/>
<System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.1432"), _
System.Diagnostics.DebuggerStepThroughAttribute(), _
System.ComponentModel.DesignerCategoryAttribute("code")> _
Partial Public Class HelloWorldCompletedEventArgs
Inherits System.ComponentModel.AsyncCompletedEventArgs
Private results() As Object
Friend Sub New(ByVal results() As Object, ByVal exception As System.Exception, ByVal cancelled As Boolean, ByVal userState As Object)
MyBase.New(exception, cancelled, userState)
Me.results = results
End Sub
'''<remarks/>
Public ReadOnly Property Result() As String
Get
Me.RaiseExceptionIfNecessary
Return CType(Me.results(0),String)
End Get
End Property
End Class
And some of errors are:
Type 'System.Web.Services.WebServiceBindingAttribute' is not defined. C:\Documents and Settings\Owner\My Documents\Visual Studio 2008\Projects\WindowsApplication3\WindowsApplication3\class.vb 16 2 WindowsApplication3
Error 4 Type 'System.Web.Services.Protocols.SoapHttpClientProtocol' is not defined. C:\Documents and Settings\Owner\My Documents\Visual Studio 2008\Projects\WindowsApplication3\WindowsApplication3\class.vb 18 14 WindowsApplication3
etc....
Update:
I'm doing this because this service need to be on server and this windows application only call this web service from server. The problem is that I need to write address of server in some kind of config file and later read that address and then call web service! So I can't simple add web reference, because I need to read address of server where service is run from config file.
Any idea?
You must to add reference to System.Web.Services assembly.
For your convenience, you can also to right-click your Visual Studio 2008 project, click "Add Service Reference", "Advanced..." and "Add Web Reference..."
If you are using VS 2005 adding a web reference allows you to specify the URL behavior of the web reference. By setting this to 'dynamic' it will store the url in the config file of the application, there by allowing you to change it if necessary.

Custom Trace Listener with the Enterprise Application Blocks

The project I'm currently working on uses Enterprise Libraries V3.1 framework for logging.
I need to take the log file that's generated and archive it off at specific points. The built in Trace Listeners seem to keep the file open in-between logging events. I've set up a custom Trace Listener which will append to a file and close it, so that the file is always shiftable.
It looks like this (minus error handling for clarity):
[ConfigurationElementType(typeof(CustomTraceListenerData))]
public class AlwaysClosedTextFileTraceListener : CustomTraceListener
{
private string logFilePath;
public AlwaysClosedTextFileTraceListener ()
{
logFilePath = #"hardcodedpath\log.txt";
}
public override void Write(string message)
{
using (StreamWriter logFile = File.AppendText(logFilePath))
{
logFile.Write(message);
logFile.Flush();
logFile.Close();
}
}
public override void WriteLine(string message)
{
using (StreamWriter logFile = File.AppendText(logFilePath))
{
logFile.WriteLine(message);
logFile.Flush();
}
}
public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
{
if (data is LogEntry && this.Formatter != null)
{
WriteLine(this.Formatter.Format(data as LogEntry));
}
else
{
WriteLine(data.ToString());
}
}
}
This works fine, but I'd much rather be passing in the path as a parameter somehow, rather than hardcoding it.
For fun, I tried adding it to the constructor, to see what happens:
public LogFolderTraceListener(string logFilePath)
{
this.logFilePath = logFilePath;
}
When I do this, I get returned an error message hinting towards what I'm doing wrong:
System.InvalidOperationException : The type 'AlwaysClosedTextFileTraceListener' specified for custom trace listener named 'MyLogFile' does not a default constructor, which is required when no InitData is specified in the configuration.
From here on in, my investigations have very much come to, the opposite of dead ends, infinite probability problems.
I have found this thumbing through the source code for the inbuilt RollingTraceListener
There is a class RollingFlatFileTraceListenerData : TraceListenerData which seems to contain all the settings passed into the constructor
Camped out at the bottom of the file for RollingFlatFileTraceListenerData is the class RollingTraceListenerAssembler : TraceListenerAsssembler which seems to be a factory
There is another class SystemDiagnosticsTraceListenerNode : TraceListenerNode which seems to make the Data class presentable to the configuration application
My question is this: how do I create a CustomTraceListener with a configurable parameter of path?
The CustomTraceListener derives from TraceListener, this has a StringDictionary called Attributes.
This will contain all the attributes in the configuration line for your TraceListener and can be gotten out by name, eg.
string logFileName= Attributes["fileName"]
I suspect that perhaps the Enterprise Application Blocks although (probably) wonderful, seem unnecessarily complicated and ultimately more trouble than their worth for this kind of customisation.
the problem is typical microsoft .. (add your own adjectives here) ..
1) when you add a custom trace listener, the 'raw' app.config statement added is:
name="Custom Trace Listener" initializeData="" formatter="Text Formatter" />
2) notice the 'initializeData' - this is what the cryptic error message is calling'InitData'.
3) So what its all saying is that you need to have a constructor that accepts initialization data - in vb parlance:
sub new (byval initstuff as string)
4) OR remove the 'initializeData=""' and have a default constructor:
sub new()
I suspect the P&P folks live in a bubble.
riix.
For what it is worth this is how I implemented it. In my this.buildCurrPath() I can read from a config file or in this case I just get the "launch pad" for the web app. But it works fine for me. I have not put it into any production code yet, but it should go out soon.
[ConfigurationElementType(typeof(CustomTraceListenerData))]
public class CustomListener: CustomTraceListener
{
#region Fields (3) 
private int logSize;
StreamWriter sw;
#endregion Fields 
#region Constructors (1) 
public CustomListener ():base()
{
string startPath = this.buildCurrPath();
sw = new StreamWriter(startPath + "\\Logs\\test.log");
sw.AutoFlush = true;
}
I have just had the same issue (except with Enterprise Library v4.1).
The solution I've found is to remove the default constructor and the only have a constructor with a string parameter for the filename i.e.
public AlwaysClosedTextFileTraceListener (string pathParameter)
{
logFilePath = pathParameter;
}
Then in the app.config put your path in the initializeData parameter
<add ... initializeData="C:\Logs\myLog.log" />
Whilst this isn't recognised by the Entriprise Library configuration editor and isn't as neat as it could be, it works as long as there is only one parameter.
If someone works out how to do it properly, please post and let us know - it's not supposed to be this difficult, surely.

Categories

Resources