C#编写上位机通过OPC DA读取西门子PLC数据
Sync_RW
引用:Quick.OpcComRcw
文档中原程序会报错:
原因:需要在安装有Simatic NET V14的电脑上运行这个程序。
需要注释掉下面程序,否则读取时会无故障提示退出。
//finally里的程序要注释掉,否则一点击read按钮,程序会直接无故障提示退出
//finally
//{
// // Free the unmanaged memory
// if (pItemValues != IntPtr.Zero)
// {
// Marshal.FreeCoTaskMem(pItemValues);
// pItemValues = IntPtr.Zero;
// }
// if (pErrors != IntPtr.Zero)
// {
// Marshal.FreeCoTaskMem(pErrors);
// pErrors = IntPtr.Zero;
// }
//}
可能的原因:
- 访问违规(Access Violation):如果Marshal.PtrToStructure在尝试转换指针时指向了无效的内存地址,可能会导致访问违规。
- 内存泄漏/损坏:在调用Marshal.PtrToStructure之前,如果指针已经被释放或者被错误地使用,可能会引发问题。
- 线程问题:如果UI操作在非UI线程上执行,可能会导致未预期的行为。
- 资源释放问题:在finally块中,如果Marshal.FreeCoTaskMem被调用两次,可能会引发问题。
其他解决方案:(未测试)
1.增强异常处理:您可以在按钮点击事件处理程序的外围添加额外的异常处理,以确保任何未捕获的异常都能被捕获并记录下来。
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// 在窗体关闭之前检查是否有未处理的异常
if (Environment.HasShutdownStarted == false)
{
e.Cancel = true;
MessageBox.Show("An unexpected error has occurred. The application will now close.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// 在Main方法中注册全局异常处理
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
try
{
Application.Run(new Form1());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show((e.ExceptionObject as Exception).Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
- 检查内存操作:确保在调用Marshal.PtrToStructure之前,指针是有效的,并且不要在释放内存之后再次使用指针。
- 线程同步:确保UI更新在UI线程上执行。
- 调试:使用调试器运行程序,并设置断点以检查Marshal.PtrToStructure调用之前和之后的指针状态。检查是否有任何访问违规或其他异常。
- 日志记录:在代码的关键部分添加日志记录,以便在程序崩溃时能够更好地理解发生了什么。
请注意,由于Marshal.PtrToStructure和内存管理涉及非托管代码,错误可能很难追踪。如果您不确定如何处理,请确保遵循正确的内存管理实践,并考虑使用更高级别的库来处理OPC通信,这样可以减少直接与内存和指针打交道的风险。