How to release serial COM port from dll - c#

I'm using .dll to in my code so i create object for that, in which .dll open the serial com port but after use it not release the comport. but in my application i want to open comport again but comport occupied by the .dll so it gives error.
please give the solution.

Your tags got it right - this is the Dispose pattern. The class you are looking for is propably SerialPort:
https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.serialport
You should be using the using Syntax to make sure it is closed. C# 8 even has a new, simpler one for limited scope variables.
The tags confuse me a bit:
on the one hand, it can be beneficial to keep such a port open and use the DataReceived() event to react to incomming stuff. In that case the Dispose point depends on the Display technology used/kind of Application.
But you also got the ASP.Net tag. And keeping stuff open and ASP.Net do not mix that good. Nevermind the part where COm Ports are not usually controled from a Web Application.
As you said you are using it only for a single write operation, this is the slight modification to the sample code:
// Create a new SerialPort object with default settings.
//make a local variable for this
using (var _serialPort = new SerialPort()){
// Allow the user to set the appropriate properties.
_serialPort.PortName = SetPortName(_serialPort.PortName);
_serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate);
_serialPort.Parity = SetPortParity(_serialPort.Parity);
_serialPort.DataBits = SetPortDataBits(_serialPort.DataBits);
_serialPort.StopBits = SetPortStopBits(_serialPort.StopBits);
_serialPort.Handshake = SetPortHandshake(_serialPort.Handshake);
// Set the read/write timeouts
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
_serialPort.Open();
//Do stuff with the open port
}
//using has it Disposed when you get here. Or otherwise leave the block

Related

Serial Port "SerialPort.GetPortNames" not reading anything

Trying to code up a little serial port communications/control panel in C# with Visual Studio 2022. I'm making it up as a WindowsForm app using .Net Framework 4.8. When launching the code all the other aspects work fine (as far as I can test them without being able to choose and connect to a paired serial port). In the window it creates I'm able to navigate without a problem but the combo box that should have the serial ports listed in it instead remains blank. Debugging and monitoring the value of "ports" also has it responding with either "error CS0103: The name 'ports' does not exist in the current context" or just "null". Another similar program uses the same logic to obtain the ports created with the virtual port emulator software I am using and this works without a worry.
Early Relevant Code Blocks
public partial class Form1 : Form
{
string dataOUT;
string sendWith;
string dataIN;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string[] ports = SerialPort.GetPortNames();
cBoxCOMPORT.Items.AddRange(ports);
btnOpen.Enabled = true;
btnClose.Enabled = false;
chBxDTR.Checked = false;
serialPort1.DtrEnable = false;
chBxRTS.Checked = false;
serialPort1.RtsEnable = false;
btnSendOut.Enabled = true;
sendWith = "Both";
toolStripComboBox1.Text = "Add to Old Data";
toolStripComboBox2.Text = "Both";
toolStripComboBox3.Text = "BOTTOM";
}
~additional non-relevant functions
}
I'm sure the ports are available as the previous code solution can still find them so I don't think it's a problem with drivers or my virtual comm ports and I've check them on HKEY_LOCAL_MACHINE and they are present. The old solution was made around a week ago so it might be using .NET Framework 4.7.2 instead of 4.8. Regardless I have just copied and adjusted snippets of relevant code across and remade the design layout. There are no compilation errors or warnings either and I am for sure including the "using System.IO.Ports;" line.
I was following a guide provided on YouTube (https://www.youtube.com/watch?v=I6uhMIFTF24) and it worked. I did however have to remake it on a fresh solution and for whatever reason now the same lines of code don't obtain any of the ports made available.
Any help or ideas would be appreciated. No clue where to look or what to fiddle with to get it to find them in this solution.
I think I've found the issue. The Form1 was not triggering the Form1_Load event when launching the program and creating the window Form1 is the main window in the [Design] tab and under its properties the 'Load' box option had no event tied to it. Changed that to be 'Form1_Load' and this now gets that block of code working so it's finding/displaying the COM Ports as well as all the other related set up. Not sure why this wasn't happening by default or if I missed a step creating it. Will add anything else that develops if a similar issue pops up but hopefully that's the end of that.

WPF Printing (XpsDocumentWriter) working in debug but not in deployment

Hopefully some of the experienced WPF developers have come across this issue before.
BACKGROUND: This information is probably not necessary to helping fixing the problem, but in case it is relevant.
My solution consists of three projects. A front-end GUI, a business logic service, and a printer service. The three projects have IPC via named pipes. The business logic hands the printing logic a label type and a pallet id.
The Problem: The printing logic then creates the label and prints it (by adding it to the print queue of a printer) As the title suggests this all works fine when I am debugging in visual studio. However when I deploy / install the services on my developer pc it is not working.
Update: It is not throwing an exception but I am only logging "About to send doc to printer" and not the line "Sent doc to printer" So it is hanging on the dw1.Write(fixedDoc); line
More Information: I am using .Net 4.0 in the printing project / visual studio 2013
public void printLabel(string labelType, string _palletID = null)
{
try
{
ILabelTemplate Label = createLabel(labelType, _palletID);
PrintDialog pd = new PrintDialog();
FixedDocument fixedDoc = new FixedDocument();
PageContent pageContent = new PageContent();
FixedPage fixedPage = getFixedPage();
fixedDoc.DocumentPaginator.PageSize = new System.Windows.Size(fixedPage.Width, fixedPage.Height);
IXamlTemplate vm = CreateViewModel(Label);
ILabelPrintDocument template = CreateTemplate(Label);
template.dockPanel.DataContext = vm;
template.dockPanel.Height = fixedPage.Height;
template.dockPanel.Width = fixedPage.Width;
template.dockPanel.UpdateLayout();
fixedPage.Children.Add(template.dockPanel);
((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
fixedDoc.Pages.Add(pageContent);
XpsDocumentWriter dw1 = PrintQueue.CreateXpsDocumentWriter(new System.Printing.PrintQueue(new System.Printing.PrintServer(), Label.PrinterName));
Library.WriteErrorLog("About to send doc to printer");
dw1.Write(fixedDoc);
Library.WriteErrorLog("Sent doc to printer");
}
catch (Exception ex)
{
Library.WriteErrorLog(ex);
}
SOLVED ... kind of
After several hours of trying different things and reading about this, I found that it was due to my application running as me when I'm debugging but as a LOCAL SYSTEM when I have it deployed. And a local system service does not have access to network resources such as printers. Despite learning this, I then started down the path of how to make a C# service print. Well after seeing many posts (too late in the game to be very helpful)
Like this and also this one I have learned that I was going down the wrong path.
The moral of the story is, if you're reading this post you're probably not at the level of "writing your own printing DLL using the Win32 API (in C/C++ for instance), then use it from your service with P/Invoke"
The solution that did work for me was instead of running this project as a service which was started via my GUI. I have instead turned it into a process which is still started and stopped via my GUI.
The code in question is
if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "\\yourAppNameGoesHere.exe"))
{
Process.Start(AppDomain.CurrentDomain.BaseDirectory + "\\yourAppNameGoesHere.exe");
}
then when the GUI is closed I run the code
if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "\\yourAppNameGoesHere.exe"))
{
Process[] myapps = Process.GetProcesses("yourAppNameGoesHere.exe");
foreach (Process _p in myapps)
{
_p.Kill();
}
}

MongoDB C# driver: connection string for sharding over replica set

I need to setup sharding over replica set as recommended in MongoDB reference for high availability & scalability. I have few questions about connection string and its behavior for C# driver in that scenario (code snippet below):
Is the connection string below looks right for connecting to mongos instances: mongos1, mongos2 & mongos3?
What happens to client if one of the mongos instance crashes? Will the failed call handled gracefully by retrying to second mongos instance? Does the client blacklist the failed mongos instance and try after sometime?
If I want to set readpreference, will the driver be aware of replica set existence and honor setting ReadPreference?
Code snippet:
MongoUrlBuilder bldr = new MongoUrlBuilder();
List<MongoServerAddress> servers = new List<MongoServerAddress>();
servers.Add(new MongoServerAddress("mongos1:27016"));
servers.Add(new MongoServerAddress("mongos2:27016"));
servers.Add(new MongoServerAddress("mongos3:27016"));
bldr.Username = "myuser";
bldr.Password = "mypwd";
bldr.Servers = servers;
bldr.DatabaseName = "mydb";
bldr.ReadPreference = ReadPreference.Primary;
var server = MongoServer.Create(bldr.ToMongoUrl());
1) Yes, this is just fine. Note that all of this could be put in an actual connection string as well. mongodb://myuser:mypwd#mongos1:27016,mongos2:27016,mongos3:27016/mydb/?readPreference=primary
2) The way your connection string is built, you'll be load balancing across the 3 mongos. If one goes down, then the other two will simply begin to receive more traffic. Errors, however, will happen and nothing gets retried automatically. You'll need to handle the errors and make decisions based on each query/write whether it is safe to retry.
3) The driver, when talking to a sharded system, will simply forward the read preference to mongos. Note that mongos version 2.2 had some difficulty with read preferences. I'd advise you to be on the 2.4 line.

C# Visual Studio GPIB Commands

What commands do you use to talk to a GPIB instrument in C#, visual studio?
I need to be able to write commands to the instrument and read the output.
I use Agilent IO Library Suite.
Here is a tutorial to use it on C#: I/O programming examples in C#
Nevertheless, in my company we had stability issues with the VISA-COM implementation, so we wrote our own wrapper around the visa32.dll (also part of the IO Library suite) using P/Invoke.
(Disclosure: I work in a company that make intense use of GPIB instruments)
I'm using National Instruments VISA and NI 488.2.
First make sure that you checked the VisaNS.NET API in the NI-VISA Setup, see the following figure:
Add a reference to NationalInstruments.VisaNS and NationalInstruments.Common to your project.
Create a MessageBasedSession, see the following code:
string resourceName = "GPIB0::20::INSTR"; // GPIB adapter 0, Instrument address 20
var visa = new NationalInstruments.VisaNS.MessageBasedSession(resourceName);
visa.Write("*IDN?"); // write to instrument
string res = visa.ReadString(); // read from instrument
A MessageBasedSession can be used to communicate with your instrument over GPIB, Ethernet or USB.
Update
Ivi.Visa superseded NationalInstruments.VisaNS. So you should add a reference only to Ivi.Visa to your project.
The example would look like that:
string resourceName = "GPIB0::20::INSTR"; // GPIB adapter 0, Instrument address 20
var visa = GlobalResourceManager.Open(resourceName) as IMessageBasedSession;
visa.RawIO.Write("*IDN?\n"); // write to instrument
string res = visa.RawIO.ReadString(); // read from instrument
The benefit of using Ivi.Visa is that it works with one of the following libraries:
National Instruments VISA
Keysight IO Libraries Suite
Rohde & Schwarz VISA
Send commands out the serial port.
See Microsoft's COM Port Example.
You should create an object with LangInt class first. Then use that object with GPIB methods.
Most common and used ones are(assuming you created an object named "dev");
dev.ibwrt(deviceHandle, "*IDN?", "*IDN?".Length);
dev.ibrd(deviceHandle, out Value, Arraysize);
These two can query the device. Or you can use them consecutively for example setting a generator's frequency and then it's amplitude.
Important part is before sending SCPI commands; you MUST initialize devices first. To do this use;
deviceHandle = ibdev(GPIBINDEX, GPIBADDRESS, SECONDARYADDRESS, TIMEOUT, EOTMODE, EOSMODE);
These parameters must declared first within the code. After initialization you can use every GPIB command with that device handles.
And of course you should add NationalInstruments.NI4882 and LangInt.dll to your project.
You can use NI Visa.
If you are using Vb or C# use Visa32.bas or Visa32.cs from the sample programs disk
int DefaultSessionId= 0;
int SessionId= 0;
int LastStatus = 0;
string Address = "GPIB0::6" ; //any address
//Session Open
LastStatus = visa32.viOpenDefaultRM(out DefaultSessionId);
//Connection Open
LastStatus = visa32.viOpen(DefaultSessionId, Address + "::INSTR", 0, 0, out sessionId);
LastStatus = visa32.viSetAttribute(SessionId, visa32.VI_ATTR_TERMCHAR, 13);// Set the termination character to carriage return (i.e., 13);
LastStatus = visa32.viSetAttribute(SessionId, visa32.VI_ATTR_TERMCHAR_EN, 1);// Set the flag to terminate when receiving a termination character
LastStatus = visa32.viSetAttribute(SessionId, visa32.VI_ATTR_TMO_VALUE, 2000);// Set timeout in milliseconds; set the timeout for your requirements
//Communication
LastStatus = visa32.viPrintf(SessionId, command + "\n");//device specific commands to write
StringBuilder message = new StringBuilder(2048);
LastStatus = visa32.viScanf(SessionId, "%2048t", message);//Readback
//Session and Connection Close
visa32.viClose(SessionId);
visa32.viClose(DefaultSessionId);
Reference

Why multiple log files are getting created with GUID using System.Diagnostics c# [duplicate]

I use TextWriterTraceListener (System.Diagnostics) in my application to trace several things like exceptions,...
The application is running on a terminal server and if there are many users using it simultaneously the listener starts to create many tracefiles with random GUIDs in the filename.
Are there possibilities or workarounds to avoid this behaviour ?
I've just taken a look at the documentation for TextWriterTraceListener and there's a note about 1/3 of the way down the page
If an attempt is made to write to a file that is in use or unavailable, the file name is automatically prefixed by a GUID
So, this would appear to be by design. If the file is indeed unavailable then there's nothing that can be done about it with the current implementation. What you could try doing is writing a custom implementation of TextWriterTraceListener that overrides the relevant Write/WriteLine methods so that the output goes to a file, per user, with a name that better suits your needs.
If what you want is for ALL logging from ALL users on the Terminal Server to go to a single file, then you'll almost certainly need to have some kind of "3rd party" process running that "owns" the file and synchronises writes to it, such as a Windows Service that is then called by your custom TextWriterTraceListener
Was the fix calling the Trace.Listeners.Add(xxx listener) multiple times on accident?
Because if you have multiple listeners added they write too all listeners when you call the Trace.writeline();
Also local IIS might be continueing to have the file in use when you shut down the application.
I am currently testing the addition of System.Diagnostics.Trace.Listeners.Clear() in my output method...
// Upon a new day re-create the TextWriterTraceListener to update our file name...
if (_date?.Day != DateTime.Now.Day) { _listener = null; }
if (_listener == null)
{
System.Diagnostics.Trace.Listeners.Clear();
_fileName = $"{DateTime.Now.ToString("yyyy-MM-dd")}_Trace.json";
// Add a writer that appends to the trace.log file:
_listener = new System.Diagnostics.TextWriterTraceListener(_fileName);
_listener.IndentSize = 4;
_listener.TraceOutputOptions = System.Diagnostics.TraceOptions.None; // TraceOptions.DateTime | TraceOptions.ThreadId;
System.Diagnostics.Trace.AutoFlush = true;
System.Diagnostics.Trace.Listeners.Add(_listener);
// Obtain the Console's output stream, then add that as a listener...
System.Diagnostics.Trace.Listeners.Add(new System.Diagnostics.TextWriterTraceListener(Console.Out));
}

Categories