c# 调用Fortran编写的dll时如何捕捉到fortran内部的异常

zaaserz 2020-06-01 05:09:27
在项目中需要调用算法的一个类库,这个类库是用fortran写的,在调用过程中有时因为数据问题会出现fortran数组越界异常。每次出现这个异常后软件就直接死啦。
这是数组越界时出现的错误。


我尝试了网上说的捕捉非托管类库的方法
1. 调用方法上添加:[HandleProcessCorruptedStateExceptions]
2. app.config 中添加 <legacyCorruptedStateExceptionsPolicy enabled="true" />

但都无法通过try ... catch..捕捉到。有没有办法捕捉到异常呢
...全文
501 22 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
OrdinaryCoder 2020-06-03
  • 打赏
  • 举报
回复
可不可以这样 主程序使用反射调用 类库A 类库A里将你用到的Fortran算法封装 如果主程序调用类库A的算法发生错误 应该不会导致主程序崩溃吧 下次需要用重新反射加载类库A就好了
zaaserz 2020-06-03
  • 打赏
  • 举报
回复
我会去尝试下子进程的方式。不过没有用过进程通讯,估计要捣鼓一会。谢谢各位提的建议
ying1234 2020-06-03
  • 打赏
  • 举报
回复
看来只能按10楼说的来了,处理不了,就想办法绕过去。
OrdinaryCoder 2020-06-03
  • 打赏
  • 举报
回复
那只能进程间通讯了
zaaserz 2020-06-03
  • 打赏
  • 举报
回复
引用 21 楼 OrdinaryCoder 的回复:
把你这段代码封成一个类库 然后再给主程序调用 而不是在主程序写这段代码
是封装的类库,第一段代码就是单独的一个类库,第二段是在主程序中使用反射调用的。
OrdinaryCoder 2020-06-03
  • 打赏
  • 举报
回复
引用 20 楼 zaaserz 的回复:
[quote=引用 19 楼 OrdinaryCoder 的回复:] 你怎么反射的 加try 然后每调一次反射加载一次 用完卸载
类库:
 public class FortranClass
    {
        [DllImport("OVERLEN.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
        private static extern void OVERLEN(ref float vlaue);

 
        [HandleProcessCorruptedStateExceptions()]
        [SecurityCritical]
        public static void overLenTest()
        {
            try
            {
                float[] value = new[] { 1f, 2f, 9f, 8f, 2f };
                 OVERLEN(ref value[0]);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

        }

    }
调用:
 private void Test()
        {
            try
            {

                Assembly t = Assembly.Load("FortranLib");
                Type a = t.GetType("FortranLib.FortranClass");
                object obj = Activator.CreateInstance(a);
                MethodInfo mi = a.GetMethod("overLenTest");
                mi.Invoke(obj,null); 
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
结果还是会弹出那个错误弹框,关闭弹框后主程序就死啦[/quote] 把你这段代码封成一个类库 然后再给主程序调用 而不是在主程序写这段代码
zaaserz 2020-06-03
  • 打赏
  • 举报
回复
引用 19 楼 OrdinaryCoder 的回复:
你怎么反射的 加try 然后每调一次反射加载一次 用完卸载
类库:
 public class FortranClass
    {
        [DllImport("OVERLEN.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
        private static extern void OVERLEN(ref float vlaue);

 
        [HandleProcessCorruptedStateExceptions()]
        [SecurityCritical]
        public static void overLenTest()
        {
            try
            {
                float[] value = new[] { 1f, 2f, 9f, 8f, 2f };
                 OVERLEN(ref value[0]);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

        }

    }
调用:
 private void Test()
        {
            try
            {

                Assembly t = Assembly.Load("FortranLib");
                Type a = t.GetType("FortranLib.FortranClass");
                object obj = Activator.CreateInstance(a);
                MethodInfo mi = a.GetMethod("overLenTest");
                mi.Invoke(obj,null); 
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
结果还是会弹出那个错误弹框,关闭弹框后主程序就死啦
OrdinaryCoder 2020-06-03
  • 打赏
  • 举报
回复
引用 17 楼 zaaserz 的回复:
[quote=引用 15 楼 OrdinaryCoder 的回复:] 可不可以这样 主程序使用反射调用 类库A 类库A里将你用到的Fortran算法封装 如果主程序调用类库A的算法发生错误 应该不会导致主程序崩溃吧 下次需要用重新反射加载类库A就好了
不行,使用反射主程序也会死,刚试啦下 只有使用子进程啦[/quote] 你怎么反射的 加try 然后每调一次反射加载一次 用完卸载
zaaserz 2020-06-03
  • 打赏
  • 举报
回复
引用 16 楼 qq_45897252 的回复:
管用哎
你试了么?我这边因为手头任务还没有实验子进程方式
zaaserz 2020-06-03
  • 打赏
  • 举报
回复
引用 15 楼 OrdinaryCoder 的回复:
可不可以这样 主程序使用反射调用 类库A 类库A里将你用到的Fortran算法封装 如果主程序调用类库A的算法发生错误 应该不会导致主程序崩溃吧 下次需要用重新反射加载类库A就好了
不行,使用反射主程序也会死,刚试啦下 只有使用子进程啦
qq_45897252 2020-06-03
  • 打赏
  • 举报
回复
引用 10 楼 新风new 的回复:
你把你调用的部份,写成一个EXE子进程来调用,可以用文件或进程通信那些返回给主程序,这样就算崩溃了,主程序也不会退出,然后加上日志,积累起来就可以分析数据了。
管用哎
xian_wwq 2020-06-02
  • 打赏
  • 举报
回复
有个简易方法可以一试: 把输入的数据以日志方式打印, 出现异常后,分析输入数据的特点, 对输入数据进行合理性校验, 避免越界异常发生 但是就怕这种数据合理性规则覆盖不到全部异常情况 上线后还是会发生挂死
引用 2 楼 zaaserz 的回复:
[quote=引用 1 楼 xian_wwq 的回复:] 如果对于输入数据的合法性无法验证, 有个思路可以借鉴: 主程序启动个子进程,在子进程中完成fortran调用,如果子进程无响应或长时间未返回结果 则强制结束子进程 确保主进程不要挂死或无响应
我尝试过开启子线程是依旧会照成主程序死的,子进程没有实验过,主要是我主程序还需要这个算法库的返回值,使用子进程会比较麻烦。是否有比较简单点的实现。这个错误在调用层面无法进行捕捉么?[/quote]
zaaserz 2020-06-02
  • 打赏
  • 举报
回复
引用 1 楼 xian_wwq 的回复:
如果对于输入数据的合法性无法验证, 有个思路可以借鉴: 主程序启动个子进程,在子进程中完成fortran调用,如果子进程无响应或长时间未返回结果 则强制结束子进程 确保主进程不要挂死或无响应
我尝试过开启子线程是依旧会照成主程序死的,子进程没有实验过,主要是我主程序还需要这个算法库的返回值,使用子进程会比较麻烦。是否有比较简单点的实现。这个错误在调用层面无法进行捕捉么?
xian_wwq 2020-06-02
  • 打赏
  • 举报
回复
如果对于输入数据的合法性无法验证, 有个思路可以借鉴: 主程序启动个子进程,在子进程中完成fortran调用,如果子进程无响应或长时间未返回结果 则强制结束子进程 确保主进程不要挂死或无响应
新风new 2020-06-02
  • 打赏
  • 举报
回复
引用 11 楼 zaaserz 的回复:
[quote=引用 10 楼 新风new 的回复:] 你把你调用的部份,写成一个EXE子进程来调用,可以用文件或进程通信那些返回给主程序,这样就算崩溃了,主程序也不会退出,然后加上日志,积累起来就可以分析数据了。
我从来没有这样使用过,我想知道这样对于程序来说是否稳定。因为我这个算法库调用情况比较频繁,10秒就会调用一次(采集数据10秒一次),并且调用后我要拿这个结果进行一个展示,在主程序内再开一个exe子进程如此频繁的通讯有没有问题?[/quote] 有两种方式,一个是子进程开启后不退出,一直与主程序通信,主程序来检测有没有崩溃。另一个是调用量小每次启动执行后关闭。通信弄好应没有问题的。
zaaserz 2020-06-02
  • 打赏
  • 举报
回复
引用 10 楼 新风new 的回复:
你把你调用的部份,写成一个EXE子进程来调用,可以用文件或进程通信那些返回给主程序,这样就算崩溃了,主程序也不会退出,然后加上日志,积累起来就可以分析数据了。
我从来没有这样使用过,我想知道这样对于程序来说是否稳定。因为我这个算法库调用情况比较频繁,10秒就会调用一次(采集数据10秒一次),并且调用后我要拿这个结果进行一个展示,在主程序内再开一个exe子进程如此频繁的通讯有没有问题?
新风new 2020-06-02
  • 打赏
  • 举报
回复
你把你调用的部份,写成一个EXE子进程来调用,可以用文件或进程通信那些返回给主程序,这样就算崩溃了,主程序也不会退出,然后加上日志,积累起来就可以分析数据了。
zaaserz 2020-06-02
  • 打赏
  • 举报
回复
引用 7 楼 ying1234 的回复:
https://www.it1352.com/743370.html 我无法复现你的情况,只能让你自已试试看了。
之前我让我同事帮忙写啦个异常类库,每次调用必定会出现数组越界: 下面这个是百度云盘的链接, 链接: https://pan.baidu.com/s/1ENYO-Gxs7xvyvpfZ26JDgQ 提取码: q989 我使用你说的方法进行测试并不能捕捉到异常。程序还是直接退出了,能否帮忙看下。对了若是要进行类库调用的话,需要将项目生成平台调至x86 这是我调用的方法
 [System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribute()]
        static void Main(string[] args)
        {
            try
            {
                float[] s = new[] {1f, 3f, 4f, 2f, 3f};
                OVERLEN(ref s[0]);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            } 
            Console.WriteLine("OK"); 
            Console.ReadLine();
        }

        [DllImport("OVERLEN.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
        private static extern void OVERLEN(ref float vlaue);
ying1234 2020-06-02
  • 打赏
  • 举报
回复
https://www.it1352.com/743370.html 我无法复现你的情况,只能让你自已试试看了。
zaaserz 2020-06-02
  • 打赏
  • 举报
回复
引用 5 楼 ying1234 的回复:
大学里学过fortran,隐约记得,fortran本身的是没法处理异常的,我只记得22/0 这样的,一样会接着运行,但是真的就没法处理了吗?而且,我怀疑,你的主程序无响应,根本就不是你这的事,而是fortran异常时引起的。如果可以在fortran里作异常处理,那就应该在那做,而不是你这来做,至少也得能抛出异常吧。 http://streda.blog.sohu.com/167426290.html,看看这个,有没有用 [HandleProcessCorruptedStateExceptions]这个只能控制一个方法,你要在所有调用fortran的方法,子方法,都加个这个标签。试试吧。
主程序直接退出就是因为fortran算法库出现的数组越界异常导致的,因为这个算法库是我们公司算法人员编写的,我这边负责调用。跟对方沟通过对方说因为数据的原因(可能某条数据有异常)这个错误他那边无法解决。因为这个异常我这边无法捕捉到,他那边也无法解决,现在出现的问题就是一有数据异常问题,我的主程序就挂啦,导致很不好的用户体验。[HandleProcessCorruptedStateExceptions]这个标签我从头加到尾但是并不能解决.
加载更多回复(2)

111,097

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧