none
C# 叫用 vc6 dll 一問 RRS feed

  • 一般討論

  • 各位大大安安~
    小弟需要以 C# 引用 VC6 開發的 DLL ,由於沒什麼經驗,過程中遇到了問題,煩請各位大大指點一二,謝謝~~

    在 DLL 中定義了 CertBasicStruct 及 CertInfoStruct 的結構, 且後者中引用了 time.h 中的 tm 結構
    在 DLL 中定義了 DecodeCertificate() 及 GetCertInfo() 方法以取得上述2個結構,GetCertValidity() 取得 tm 結構

    小弟試著在 C# 中宣告引用上述的內容,並開始叫用~~

    一開始可以成功呼叫 DecodeCertificate() 方法,取得了 CertBasicStruct 結構~~
    但是在呼叫 GetCertInfo() 方法時,卻得到了 「嘗試讀取或寫入受保護的記憶體。這通常表示其他記憶體已損毀。」 的例外訊息~~
    猜測~由於前一個方法可以正常叫用,應該不是 DLL 本身不正常的問題~~
    猜測~可能是我的 CertInfoStruct 結構宣告引用寫錯了~~

    於是我又再叫用 GetCertValidity() 方法,想要取得較單純的 tm 結構~~
    但還是得到了 「嘗試讀取或寫入受保護的記憶體。這通常表示其他記憶體已損毀。」 的例外訊息~~
    tm 結構應該是VC++自有的結構,只有9個 int 成員,為什麼也會錯呢!?

    小弟已參考了一些網站,還是不明白錯在那裡~~  @@" 

    下面是宣告引用相關的程式碼~~

    有經驗的大大們,請指點迷津吧~~ @@"


    c++ code
    #define Cert_Serial_Length   20
    #define DN_Length     256
    #define Cert_Extension_Length  1024


    typedef struct CertBasicStruct { unsigned char* pTbsCertificate; int iTbsCertificateLength; unsigned char* pSignatureAlgorithm; int iSignatureAlgorithmLength; unsigned char* pSignature; int iSignatureLength; }CertBasicStruct;




    typedef struct CertInfoStruct
    {
    unsigned char ucSerialnumber[Cert_Serial_Length]; 
    int      iSerialnumberLength;
    char     ucIssuerDN[DN_Length]; 
      int      iIssuerDNLength;
     char     ucSubjectDN[DN_Length]; 
     int      iSubjectDNLength;
     struct tm    BeginDate;
     struct tm    EndDate;    
     unsigned char ucExtension[Cert_Extension_Length];
     int      iExtensionLength;
    }CertInfoStruct;

    extern "C" __declspec(dllexport)
    int __stdcall DecodeCertificate ( unsigned char* pCertificate, int iCertificateLength, CertBasicStruct& SCertificate );
    extern "C" __declspec(dllexport)
    int __stdcall GetCertInfo (CertBasicStruct& SCertificate, CertInfoStruct& SCertInfo);
    extern "C" __declspec(dllexport)
    int __stdcall GetCertValidity ( CertBasicStruct& CertBasicStruct, struct tm& SnotBeforeDate, struct tm& SnotAfterDate );

    c# code (P/Invoke)
    public class CardLib
    {
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct CertBasicStruct
    {
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1)]
        public byte[] pTbsCertificate;
        public int iTbsCertificateLength;
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1)]
        public byte[] pSignatureAlgorithm;
        public int iSignatureAlgorithmLength;
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1)]
        public byte[] pSignature;
        public int iSignatureLength;
    }
    
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct CertInfoStruct
    {
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 20)]
        public byte[] ucSerialnumber;
        public int iSerialnumberLength;
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 256)]
        public byte[] ucIssuerDN;
        public int iIssuerDNLength;
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 256)]
        public byte[] ucSubjectDN;
        public int iSubjectDNLength;
        public tm BeginDate;
        public tm EndDate;
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 1024)]
        public byte[] ucExtension;
        public int iExtensionLength;
    }
    
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct tm
    {
        public int tm_sec;
    public int tm_min; public int tm_hour; public int tm_mday; public int tm_mon; public int tm_year; public int tm_wday; public int tm_yday; public int tm_isdst; }
    [DllImport(sParsingvaPath, CharSet = CharSet.Ansi)]
    public static extern int DecodeCertificate([In] byte[] pCertificate, [In] int iCertificateLength, [In, Out] ref CertBasicStruct SCertificate);
    [DllImport(sParsingvaPath, CharSet = CharSet.Ansi)]
    public static extern int GetCertInfo([In] CertBasicStruct SCertificate, [In, Out] ref CertInfoStruct SCertInfo);
    [DllImport(sParsingvaPath, CharSet = CharSet.Ansi)]
    public static extern int GetCertValidity([In] CertBasicStruct SCertificate, [In, Out] ref tm SnotBeforeDate, [In, Out] ref tm SnotAfterDate); }
    2009年6月3日 下午 05:09

所有回覆

  • ...
    .Net 在結構內使用陣列或字串,均為指標,並不連續在結構內,所以你宣告為 byte[] 也沒用。

    整串宣告為 byte[] 丟出去還比較簡單。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年6月4日 上午 06:10
  • ...
    .Net 在結構內使用陣列或字串,均為指標,並不連續在結構內,所以你宣告為 byte[] 也沒用。

    整串宣告為 byte[] 丟出去還比較簡單。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務

    非常謝謝大大的回應~
    不過 "整串宣告為 byte[] 丟出去" 這句話可不可以再說明一下呀  @@"

    另外,我原文中提到,當我叫用 GetCertValidity() 以取得 tm 結構時,還是出錯~~
    tm結構中並沒有陣列或字串,只有 int ,又是那裡錯呢??

    下列是相關宣告~
    c++
    extern "C" __declspec(dllexport)
    int __stdcall GetCertValidity ( CertBasicStruct& CertBasicStruct, struct tm& SnotBeforeDate, struct tm& SnotAfterDate );

     
    c#
    extern "C" __declspec(dllexport)int __stdcall GetCertValidity ( CertBasicStruct& CertBasicStruct, struct tm& SnotBeforeDate, struct tm& SnotAfterDate );
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct tm
    {
    public int tm_sec;
    public int tm_min;
    public int tm_hour;
    public int tm_mday;
    public int tm_mon;
    public int tm_year;
    public int tm_wday;
    public int tm_yday;
    public int tm_isdst;
    }
    2009年6月4日 上午 08:31
  • .Net 並不直接支援傳統的結構透過 IO 來處理,造成結構處理上的困難,你可以看一下 Marshal 線上手冊的說明,並配合既有討論建立觀念:
    http://social.msdn.microsoft.com/Search/zh-TW/?Refinement=112&query=%e7%b5%90%e6%a7%8b&rq=meta:Search.MSForums.GroupID(1e30b720-20ff-4065-9384-3d71465f785f)&rn=%e6%89%80%e6%9c%89+Visual+Studio+%e8%ab%96%e5%a3%87

    實值型別還有一些是線上手冊沒提的,你可以先看這篇跟最後的 KB :
    http://tlcheng.spaces.live.com/blog/cns!145419920BFD55A7!1012.entry

    請重新編輯你的程式碼。

    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年6月4日 上午 09:00
  • 心冷大大~

    1. 上面的程式碼已整理過,請您再看一下,因為網路上找不到傳入 tm 結構的例子,但有看過內含int 結構的使用,跟小弟應該是相同的~~
    2. 小弟的悟性真的沒那麼高,我將CertBasicStruct 結構的宣告從
       [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 改為
      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 後,
      反而連原本可以取得的 CertBasicStruct 結構,都無法取得,
      例外為 System.ExecutionEngineException
    3. 再者,小弟發現除了 Pack=1 以外,若設為其他可能的值(不設定,0,2,4,8,16,32,64,128) 都可以取得CertBasicStruct 結構
      小弟不知道這是什麼情形~~

     

    ps. 環境是 WinXP, IIS, VS2008, .net framework 3.5

     

    2009年6月4日 下午 06:56
  • 你可以先依那篇用 Marshal.SizeOf 來比較大小。

    用一個簡單的範例來說明 Pack 的作用,假設結構內為一個 byte = 1 , int32 = 2 ,整個結構轉成 byte 如下 (依照windows little endian 排列)
    Pack = 1 : 01 02 00 00 00 (這是要的)
    Pack = 2 : 01 00 02 00 00 00
    Pack = 4 : 01 00 00 00 02 00 00 00
    Pack = 8 : 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 (預設值,也就是不設 pack 的狀況)
    Pack =16 : 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    (下略)

    所以 pack 會反映每個成員在記憶體中所佔的最小長度,若是 pack = 2 ,byte 實際上就會佔 2 byte ,你不用 pack = 1 的話,你的 int 實際上會佔 8 byte ,但是在 VC 則是 2 byte ,所以根本就無法對應。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年6月5日 上午 05:36
  • 但是 Pack = 1 我會取得例外 System.ExecutionEngineException
    ------------------------------------------------------------------------------------
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1 )]
    public struct CertBasicStruct
    {
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1)]
        public byte[] pTbsCertificate;
        public int iTbsCertificateLength;
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1)]
        public byte[] pSignatureAlgorithm;
        public int iSignatureAlgorithmLength;
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1)]
        public byte[] pSignature;
        public int iSignatureLength;
    }

    2009年6月5日 上午 09:06
  • 可能跟你的 byte 陣列相衝吧,我沒特別試過這部分。
    前面說過了,陣列都是參考型別,你這樣宣告沒用的。

    比如說假設只有一個屬性,是你的 pTbsCertificate 且是 8 byte ,我只能確定前 4 bytes 是這 8 bytes 的指標,可能指向陣列結構,在 .Net 中是這樣,經過封裝遞送後就不知道變怎樣了,所以前面才說你還不如自己宣告一個 byte() 陣列,把每個元素逐一填入。

    比如說這篇討論到的:
    http://social.msdn.microsoft.com/forums/zh-TW/232/thread/b06f3a3b-3af7-4b40-a097-9a37d49ec3a6/

    急著解決的話,花錢去問 CSS 也是一個辦法。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    2009年6月5日 下午 02:22
  • GetCertInfo() 方法時,卻得到了 「嘗試讀取或寫入受保護的記憶體。這通常表示其他記憶體已損毀。」 的例外訊息~~

    請問您遇到的問題,後來有解嗎?能否告知解決方式。

    2011年7月30日 上午 04:30