I have a static class which implements Excel-related functions (Class Library).
This dll is added as a reference to other applications, where I'm trying to use those functions.
I know that static objects are disposed when the main program terminates. Can I somehow dispose it before?
In my code, If I call CreateExcelDocument(excelFile), and instance of Excel is running in the background (I can see it in windows' processes manager). But, when I call DisposeExcelDocument(); the instance remains. How can I dispose it?
My goal is to open multiple Excel files, one by one, create graphs from the file currently open, and then close and move on to the next one. Is it even possible?
Here is the code:
public static class ExcelUtils
{
#region Private Members
private static Application m_excelApp;
private static Workbook m_excelWorkBook;
private static Worksheet m_excelWorkSheet;
#endregion Private Members
#region Properties
public static Worksheet ExcelWorkSheet
{
get { return m_excelWorkSheet; }
set { m_excelWorkSheet = value; }
}
#endregion Properties
#region Public Functions
public static void CreateExcelDocument(string excelFile)
{
try
{
m_excelApp = new Application();
m_excelApp.DisplayAlerts = false;
m_excelWorkBook = m_excelApp.Workbooks.Add(Type.Missing);
m_excelWorkSheet = (Worksheet)m_excelApp.ActiveSheet;
m_excelApp.DefaultSheetDirection = (int)Constants.xlLTR;
m_excelWorkSheet.DisplayRightToLeft = false;
if (excelFile.CompareTo("") != 0)
{
m_excelWorkBook = m_excelApp.Workbooks.Open(excelFile);
m_excelWorkSheet = (Worksheet)m_excelApp.Worksheets.get_Item(1);
m_excelWorkSheet.Columns.ClearFormats();
m_excelWorkSheet.Rows.ClearFormats();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
}
public static void DisposeExcelDocument()
{
try
{
m_excelApp.Quit();
ReleaseObject(m_excelWorkSheet);
ReleaseObject(m_excelWorkBook);
ReleaseObject(m_excelApp);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
}
public static void ReleaseObject(object currentObject)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(currentObject);
currentObject = null;
}
catch (Exception ex)
{
currentObject = null;
Console.WriteLine(ex.ToString());
return;
}
finally
{
GC.Collect();
}
}
public static uint GetNumberOfRowsOrCols(string excelFile, bool getRows)
{
CreateExcelDocument(excelFile);
uint rowColNum = 0;
if (getRows)
rowColNum = (uint)m_excelWorkSheet.UsedRange.Rows.Count;
else
rowColNum = (uint)m_excelWorkSheet.UsedRange.Columns.Count;
DisposeExcelDocument();
return rowColNum;
}
#endregion Public Functions
}
First of all I agree with the comments regarding making this as non-static class.
But as far as your question is concerned, the Garbage Collector is not collecting the objects as you are not setting null to the class members, but just the local reference in ReleaseObject method.
To null the class members with least changes, will be to pass currentObject parameter to ReleaseObject method as ref, and have to use generics instead of object data type. So the method will become:
public static void ReleaseObject<T>(ref T currentObject) where T : class
and to call this method you will change like this:
ReleaseObject(ref m_excelWorkSheet);
You can leave the body of ReleaseObject method as it is, but I think calling GC.Collect() is not needed, and if you really have to, then call in from DisposeExcelDocument only once in the end, after you have called ReleaseObject for all the objects.
Related
Preconditions:
I have to fix synchonization issues in very big legacy spaghetty codebase. There are some classes that must be synchronized. But there are lots of usages for these classes. It is why I am looking for way to catch issues with debug guards.
There is one of ideas to report problem in usage of some classes.
Class for debug purposes:
public class AsyncChecker {
private readonly Thread myThread;
private volatile bool myTurnedOn;
public AsyncChecker() {
myThread = Thread.CurrentThread;
myTurnedOn = false;
}
public void turnOn() {
myTurnedOn = true;
}
public void checkThread() {
if ( myTurnedOn && Thread.CurrentThread != myThread ) {
Debug.LogError( "illegal thread" );
}
}
public void checkMultiThreadSafety() {
if ( myTurnedOn ) {
//there is code that can determine if method called from critical
//section or not even if we call from the same thread
//Monitor.IsEntered( ) works only if there is call from another thread
}
}
}
Some legacy class that can or cannot be accessed in concurrency:
public class SomeLogic {
private readonly AsyncChecker myAsyncChecker = new AsyncChecker();
public void logicOne() {
myAsyncChecker.checkMultiThreadSafety();
//some logic A
}
public void logicTwo() {
myAsyncChecker.checkMultiThreadSafety();
//some logic B
}
}
There is purpose:
public void someMethodInDeepLegacyCode() {
lock (someLock) {
someLogicClassInstance.logicOne();
}
}
public void anotherSomeMethodInDeepLegacyCode() {
someLogicClassInstance.logicTwo(); //there is access without synchronization,
//would like to have exception, or assertion, or error log or something else
}
Monitor.IsEntered can be used only partially. Only if we called from different thread but not for the same.
Using the CSCore library, I wrote the code for playing an mp3 file in the class BGM in a seperate file called BGM.cs and the method for playback is BGM.Play("file directory");, which is called in the Form. But somehow I can't manage to get any sound out of it. I've already checked volume, codec and output, and I can't think of anything else that might cause this problem.
This is the code of the class file:
public class BGM
{
public static void Play(string file)
{
using (IWaveSource soundSource = GetSoundSource(file))
{
using (ISoundOut soundOut = GetSoundOut())
{
soundOut.Initialize(soundSource);
soundOut.Volume = 0.8f;
soundOut.Play();
}
}
}
private static ISoundOut GetSoundOut()
{
if (WasapiOut.IsSupportedOnCurrentPlatform)
return new WasapiOut();
else
return new DirectSoundOut();
}
private static IWaveSource GetSoundSource(string file)
{
return CodecFactory.Instance.GetCodec(file);
}
There are actually a couple reasons why your mp3 isn't playing.
The first reason is you haven't specified a device for the sound to play on. The code below gets the first device that can render sound, but that won't always be correct if the user has multiple devices attached to their computer. You'll have to handle that appropriately. The device has to be set on the WasapiOut object.
The second reason is your use of using statements in your Play method. While it's always a good idea to clean up objects that implement IDisposable, you can't always do so immediately. In this case, soundOut.Play() is not a blocking method, which meant that control was exiting the method immediately, causing Dispose() to be called on soundOut and soundSource. This meant that the sound would effectively never be played (maybe it would start for a short moment, but not enough to really hear it). Essentially, you need to hold onto the references and only dispose of them once playback is complete.
Have a look at the AudioPlayerSample for an idea on how to implement a complete solution. My code should get you started.
void Main()
{
using(var player = new BGM(#"D:\Test.mp3"))
{
player.Play();
// TODO: Need to wait here in order for playback to complete
// Otherwise, you need to hold onto the player reference and dispose of it later
Console.ReadLine();
}
}
public class BGM : IDisposable
{
private bool _isDisposed = false;
private ISoundOut _soundOut;
private IWaveSource _soundSource;
public BGM(string file)
{
_soundSource = CodecFactory.Instance.GetCodec(file);
_soundOut = GetSoundOut();
_soundOut.Initialize(_soundSource);
}
public void Play()
{
if(_soundOut != null)
{
_soundOut.Volume = 0.8f;
_soundOut.Play();
}
}
public void Stop()
{
if(_soundOut != null)
{
_soundOut.Stop();
}
}
private static ISoundOut GetSoundOut()
{
if (WasapiOut.IsSupportedOnCurrentPlatform)
{
return new WasapiOut
{
Device = GetDevice()
};
}
return new DirectSoundOut();
}
private static IWaveSource GetSoundSource(string file)
{
return CodecFactory.Instance.GetCodec(file);
}
public static MMDevice GetDevice()
{
using(var mmdeviceEnumerator = new MMDeviceEnumerator())
{
using(var mmdeviceCollection = mmdeviceEnumerator.EnumAudioEndpoints(DataFlow.Render, DeviceState.Active))
{
// This uses the first device, but that isn't what you necessarily want
return mmdeviceCollection.First();
}
}
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
if(_soundOut != null)
{
_soundOut.Dispose();
}
if(_soundSource != null)
{
_soundSource.Dispose();
}
}
_isDisposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
}
Let's assume we have the following two classes, How can we listen for Errors and if any error occurred, recreate the singleton? I have put together the following code, but would like to know if there is a pattern for safely raise error, dispose object and recreate it automatically?
`
static void Main(string[] args)
{
MyFirstClass.Instance.SayHello();
}
}
class MySecondClass
{
public int ID { get; set; }
public void SayHelloFromSecondClass()
{
Console.WriteLine("Say Hello From Second Class");
}
public MySecondClass(int id)
{
ID = id;
}
}
public sealed class MyFirstClass
{
private static readonly MyFirstClass instance = new MyFirstClass();
private static MySecondClass msc;
public event EventHandler ErrorOccuredEvent;
private MyFirstClass() { }
public static MyFirstClass Instance
{
get
{
msc = new MySecondClass(id: 1);
return instance;
}
}
public void SayHello()
{
Console.WriteLine("Hello World...");
}
static void ErrorOccured(object sender, EventArgs e)
{
Console.WriteLine("Oops");
msc = null;
Thread.Sleep(5000);
GC.Collect();
msc = new MySecondClass(id: 2);
}
}
`
If I understand well, MyFirstClass (which is a singleton) is a kind of wrapper around MySecondClass that turns MySecondClass into a singleton as well.
Let's call MyFirstClass: Wrapper
Let's call MySecondClass: Service
If the clients always consume the Service through the single instance of Wrapper, then re-creating a Wrapper will not help, because the clients might keep a reference to Wapper. Re-creating Service can help if the clients don't see it and cannot keep a reference to it. Therefore they must consume the service indirectly.
It's easiest to achieve this through an interface:
public interface IHelloService
{
void SayHello();
}
public class HelloService : IHelloService
{
public void SayHello()
{
Console.WriteLine("Hello");
}
}
public class HelloServiceWrapper : IHelloService
{
public static readonly IHelloService Instance = new HelloServiceWrapper();
private HelloServiceWrapper () {}
private IHelloService _service;
public void SayHello()
{
EnsureServiceAvailable();
_service.SayHello();
}
private void EnsureServiceAvailable()
{
if(_service == null) {
_service = new HelloService();
}
}
private void HandleError()
{
_service = null;
}
}
But if the error happens when the client is using the service ...
HelloServiceWrapper.Instace.SayHello();
... this call might fail.
You would have to re-create the service instantly in order to make succeed the client's call (assuming that re-creating the service will solve the problem and that the error will not occur again immediately):
public void SayHello()
{
try {
_service.SayHello();
} catch {
_service = new HelloService();
_service.SayHello();
}
}
Note: Disposing the service invalidates the object and makes any reference a client has to it invalid. But re-creating a new one does not give the client a new reference! You would need to have a reference to the clients reference in order to be able to give the client a new instance.
This question already has answers here:
Use Unity API from another Thread or call a function in the main Thread
(5 answers)
Closed 6 years ago.
I am working on a project where I am having two Unity Projects that need to communicate with each other. I am trying to solve this by using the .net Remoting Framework.
For That I created a dll which both Unity projects will use. The dll consists of:
MyRemotableObject.cs
public class MyRemotableObject : MarshalByRefObject
{
public MyRemotableObject()
{
}
public void NotifyStatusChange(int status)
{
Cache.GetInstance().Status = 0;
}
public int GetCreditCount()
{
return Cache.GetInstance().CreditCount;
}
}
Cache.cs
public class Cache
{
private static Cache myInstance;
public static IObserver Observer;
private Cache()
{
}
public static void Attach(IObserver observer)
{
Observer = observer;
}
public static Cache GetInstance()
{
if(myInstance==null)
{
myInstance = new Cache();
}
return myInstance;
}
public int Status
{
set
{
Observer.NotifyFinished(value);
}
}
public int CreditCount
{
get
{
return Observer.QueryCreditCount();
}
}
}
IObserver.cs
public interface IObserver
{
void NotifyFinished(int status);
int QueryCreditCount();
}
Now I have my Menu - Unity project, acting as the remoting server
MenuController.cs
public class MenuController : MonoBehaviour, IObserver
{
private object lockObject;
List<ControllerBase> controllers;
private MyRemotableObject remotableObject;
private System.ComponentModel.Container components = null;
void Awake()
{
lockObject = new object();
try
{
remotableObject = new MyRemotableObject();
//für fehler: //http://www.mycsharp.de/wbb2/thread.php?postid=199935
//************************************* TCP *************************************//
// using TCP protocol
TcpChannel channel = new TcpChannel(124);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(MyRemotableObject), "TargetShooterMenu", WellKnownObjectMode.SingleCall);
//************************************* TCP *************************************//
RemotableObjects.Cache.Attach(this);
}
catch (Exception e)
{
Debug.Log(e.ToString());
}
controllers = new List<ControllerBase>();
foreach (GameObject controllerObject in GameObject.FindGameObjectsWithTag(GlobalNames.Tags.CONTROLLEROBJECT))
{
if (controllerObject.GetComponent<ControllerBase>())
controllers.Add(controllerObject.GetComponent<ControllerBase>());
}
}
delegate void PresentNameInputControllerDelegate(int status);
private void PresentNameInputController(int status)
{
if (status == (int)LevelStatusCode.OK)
foreach (ControllerBase controller in controllers)
{
controller.Hide();
if (controller.GetType() == typeof(NameInputController))
controller.Show();
}
}
public void NotifyFinished(int status)
{
Debug.Log("Notify");
lock (lockObject)
{
PresentNameInputControllerDelegate d = PresentNameInputController;
d(status);
}
}
public int QueryCreditCount()
{
Debug.Log("Query");
return 100;
}
}
This Server implements the IObserver Functions NotifyFinished and QueryCreditCount (returns dummy value for the moment)
When calling the NotifyFinished function from the client, following error occurs:
get_animation can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
Can someone tell me, how to solve this problem?
Thanks in advance,
Hoffmanuel
After lots of searching, i came to the solution: Using the Loom Unity Package from:
Unity Gems entry about threading
and using it like mentioned in Unity answers entry about threading:
void Start()
{
var tmp = Loom.Current;
...
}
//Function called from other Thread
public void NotifyFinished(int status)
{
Debug.Log("Notify");
try
{
if (status == (int)LevelStatusCode.OK)
{
Loom.QueueOnMainThread(() =>
{
PresentNameInputController();
});
}
}
catch (Exception e)
{
Debug.LogError(e.ToString());
}
}
I am doing a project including a custom OPC Client.
The Class Main represents the MainWindow in a WPF application.
The private field _opcServer will hold an object for further use.
Only one _opcServer object is allowed at any time.
I came up with this (it's all sample code and works fine)
// "Main" Class --> it's a WPF Window
public class Main
{
// the "global" server object
private OpcServer _opcServer = new OpcServer();
public Main() {}
private void connectOpcServer()
{
if(this._opcServer == null)
{
// the "global" server object
this._opcServer = this.opcClientFactory().connectOpcServer("someOpcServer");
if(this._opcServer != null)
{
// we made the connection
}
else
{
// connection failed
}
}
}
private void disconnectOpcServer()
{
if(this._opcServer != null)
{
if(this.opcClientFactory().disconnectOpcServer(this._opcServer))
{
// disconnected
this._opcServer = null;
}
else
{
// something went wrong
}
}
}
private OpcClient ocpClientFactory()
{
OpcClient opcClient = new opcClient();
return opcClient;
}
}
// Client Class
public class OpcClient
{
// the server object
private OpcServer _opcServer = new OpcServer();
public OpcClient() {}
public OpcServer connectOpcServer(string progID)
{
bool madeConnection = this._opcServer.Connect(progID);
if(madeConnection)
{
return this._opcServer;
}
else
{
return null;
}
}
public bool disconnectOpcServer(OpcServer opcServer)
{
this._opcServer = opcServer;
if(this._opcServer.disconnect())
{
this._opcServer = null;
return true;
}
return false;
}
}
Not much comments in the code but I think you get the point.
Every time connect or disconnect is triggered via user action, a new object of the OPC Client is created and the Server Object is passed in the one or the other direction.
There will be more methods (like read tags, etc ...) like this, but since the user should use them only once or twice per day, I see no problem with creating new objects and passing something between them.
But what if there is a real funny user who thinks he has to use these things (connect/disconnect/ etc...) all the time. Then I will end up creating many objects!
I gave it a thought and came up with this.
public class Main
{
// the client object
private OpcClient _opcClient = OpcClient.Instance;
public Main(){}
private void connectOpcServer()
{
if(this._opcClient.connectOpcServer("someOpcServer"))
{
// we made the connection and can now use
// this._opcClient.opcServer
}
else
{
// connection failed
}
}
private void disconnectOpcServer()
{
if(this._opcClient.disconnect())
{
// disconnected
}
else
{
// something went wrong
}
}
}
public class OpcClient
{
private static OpcClient _instance;
public static OpcClient Instance
{
get
{
if(instance == null)
{
_instance = new OpcClient();
}
return _instance;
}
}
private OpcClient()
{
this.opcServer = new OpcServer();
}
public OpcServer opcServer
{
get;
private set;
}
public bool connectOpcServer(string progID)
{
return this.opcServer.Connect(progID);
}
public bool disconnectOpcServer()
{
return this.opcServer.disconnect();
}
}
Now I create a singelton of the OPC Client and pass it to the main class. Now only one object will be created, the user can click connect/disconnect all day long.
What is the best way to proceed here?
Store the Server Object in the main class
Store the Class Object in the main class
Depends
Both are bad ideas (if so, why? What can I do instead?)
I am choosing the 2nd option.
By choosing the singleton approach I can make sure that there is only one Server Object.
This is very important.