سؤال

أنا أحاول أن أصل الكلمة إلى إرث dll المترجمة من لغة فورتران.أنا جديدة على إمكانية التشغيل المتداخل ، ولكن قرأت بعض المقالات على ذلك ، يبدو أن القضية يجب أن تكون واضحة إلى حد ما.

طريقة أريد حقا أن ندعو له طريقة معقدة التوقيع, ولكن لا أستطيع حتى هذه الكلمة بسيطة GetVersion طريقة دون الحصول على الذاكرة المحمية انتهاك.

هنا هو بلدي DllImport كود:

[DllImport("GeoConvert.dll", 
            EntryPoint="_get_version@4", 
            CallingConvention=CallingConvention.StdCall)]
public static extern void GetGeoConvertVersion([MarshalAs(UnmanagedType.LPStr, SizeConst=8)]
                                                    ref string version);

هنا لغة فورتران:

SUBROUTINE GetVer( VRSION )
C
!MS$DEFINE  MSDLL 
!MS$IF DEFINED (MSDLL)
        ENTRY Get_Version (VRSION)  
      !MS$ATTRIBUTES DLLEXPORT,STDCALL :: Get_Version
      !MS$ATTRIBUTES REFERENCE :: VRSION
!MS$ENDIF
!MS$UNDEFINE  MSDLL 
C
  CHARACTER*8  VRSION
C
  VRSION = '1.0a_FhC'                                        
C
  RETURN
  END

هنا هو بلدي وحدة اختبار فشل ذلك:

[Test]
public void TestGetVersion()
{
    string version = "";
    LatLonUtils.GetGeoConvertVersion(ref version);
    StringAssert.IsNonEmpty(version);
}

وهنا رسالة الخطأ أحصل على:

System.AccessViolationException
Message: Attempted to read or write protected memory. 
         This is often an indication that other memory is corrupt.

أشياء أخرى حاولت:

  • استخدام الافتراضي التنظيم
  • تمرير char[] بدلا من سلسلة (على طريقة التوقيع الأخطاء بدلا من ذلك)
هل كانت مفيدة؟

المحلول 2

حسنًا، لقد قمت بتشغيله، وكانت المشكلة تمر عبر المرجع.لست متأكدا من السبب، ولكن هذا يعمل:

[DllImport("GeoConvert.dll", 
                EntryPoint="_get_version@4", 
                CallingConvention=CallingConvention.StdCall)]
    public static extern void GetGeoConvertVersion([MarshalAs(UnmanagedType.LPArray)]
                                                    byte[] version);

بهذا الاختبار:

[Test]
    public void TestGetVersion()
    {
        //string version = "";
        byte[] version = new byte[8];
        LatLonUtils.GetGeoConvertVersion(version);
        char[] versionChars = System.Text.Encoding.ASCII.GetChars(version);

        string versionString = new string(versionChars);
    }

نصائح أخرى

...قص...حسنا, لقد حصلت على عمل ، المشكلة كانت تمر من قبل المرجع.لست متأكدا لماذا ولكن هذا يعمل:...قص...

تحتاج إلى تمرير من خلال الإشارة لأن هذا هو الدلالية المستخدمة من قبل لغة فورتران.رمز العميل تمر في منطقة عازلة على أن لغة فورتران سوف أكتب بدلا من استخدام قيمة الإرجاع.

...قص...!MS$سمات المرجعية ::VRSION ...قص...

هذه السمة في لغة فورتران تحدد هذه المعلمة مرت الإشارة.هذا يعني أن لغة فورتران سوف أكتب هذا العنوان.إذا كان DllImport لا تعلن أنها المرجع القيمة أيضا ، سوف تحصل على حدوث انتهاك وصول.

هل حاولت استخدام StringBuilder؟

قم بإنشاء السلسلة الخاصة بك كـ StringBuilder وقم بتمرير ذلك إلى وظيفة dll.

لست متأكدًا من عبارة Marashlling التي يجب استخدامها، ربما قد ينجح الإعداد الافتراضي.

القي نظرة على: فئة Marshal C++ "سلسلة" في C# P/Invoc

إليك مقالة جيدة قد تساعد أيضًا: التنظيم المتداخل

لا أستطيع تجربة هذا الحل لأنه ليس لدي مترجم FORTRAN، ولكن أعتقد أن هذا سوف يناسبك:

    [DllImport("GeoConvert.dll", 
            EntryPoint="_get_version@4", 
            CallingConvention=CallingConvention.StdCall,
            CharSet=CharSet.Ansi)]
    public static extern void GetGeoConvertVersion(StringBuilder version);

شكرًا لكم جميعًا يا رفاق، لقد كنت أحاول تمرير سلسلة من c# إلى روتين فرعي من fortran dll وكانت هذه الطريقة هي الطريقة الوحيدة التي نجحت من بين الكثير من الطرق الأخرى

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top