none
【求救】關於C# DllImport的問題 RRS feed

  • 問題

  • 大家好:

    小弟目前手上有一台PDA裝置,正在寫讀取RFID tag的功能,廠商有給RFIDAPI.dll,爬文後瞭解使用DllImport的方法可以使用裡面的函式,想先試看看是否能正確的呼叫到Dll檔裡的函式。

    以下是小弟程式碼的片段

    1.using System.Runtime.InteropServices;

    2.[DllImport("RFIDAPI.dll", EntryPoint = "ActivateReader")]
                public static extern long ActivateReader(int iCom);

    3. long ErrCode = ActivateReader(5);

    執行後,跳出MissingMethodException

    找不到 PInvoke DLL 'RFIDAPI.dll'。

    我有檢查過將RFIDAPI.dll放在執行的目錄 bin\Debug\下,也將RFIDAPI.dll放到模擬器Windows目錄下,想請問大家我要如何做才能解決。謝謝
    2008年2月23日 上午 10:46

解答

  • 終於解決了....但是是用笨方法,還是搞不懂為什麼存進StringBuilder會是"?"

     

    以下是我目前的寫法

     

    Code Snippet

    [DllImport("RFIDAPI.dll",CharSet = CharSet.Auto,EntryPoint ="?SelectTag@@YAJHAAPAG@Z")]
            unsafe public static extern Int32 SelectTag(int iTagProtocol,out char* lpBuf);

     

     

    unsafe{

    char* OutputTagID; //存放讀到的Tag位址

    StringBuilder OutputTag = new StringBuilder(); //用來存放Tag字元

    int protocol = 6;

    int ErrCode = SelectTag(protocol,out OutputTagID); //讀取Tag

    while (i < 16)
    {

    char* TagID = &OutputTagID[i];

    OutputTag.Append(*TagID);  //將OutputTagID取出存入StringBuffer
    i++;

    }

    MessageBox.Show(OutputTag.ToString());

    }

     

    目前能顯示出Tag的ID了,謝謝之前大家的幫忙!!3Q~~~

    2008年2月29日 上午 02:25

所有回覆

  • Hi,

    您可以試試看將RFIDAPI.DLL放在跟執行檔同一個目錄下測試看看能不能正常動作;另外可以用ActiveSync把PDA跟開發PC先連線起來,這樣子可以直接部屬到實機上面進行偵錯,應該會比較方便一些。

     

    2008年2月23日 上午 11:13
    版主
  • HI

    我試著照你的方式做,用實機來測試,已經在PDA上將RFIDAPI.dll與執行檔放在同一個目錄下,跳出的錯誤變成找不到進入點。

    找不到 PInvoke DLL 'RFIDAPI.dll' 中的進入點 'ActivateReader'。

    我用Depends.exe檢視dll裡面的function name,的確有這個名稱(
    ?ActivateReader@@YAJH@Z),但為什麼會跳出找不到的錯誤呢?


    2008年2月24日 上午 02:12
  • 你得要確定:

     

    1. 這個 ActivateReader 是 export function。

    2. 是否有依照 ActivateReader 這個名稱來 export,你可以把別名設為 ?ActivateReader@@YAJH@Z 看看能不能存取到。

     

    Code Snippet

    [DllImport("RFID.dll", EntryPoint="?ActivateReader@@YAJH@Z"]

    public static extern void ActivateReader(...);

     

     

     

    2008年2月24日 上午 02:36
  • HI

    1.我用DLL Export Veiwer檢視此dll檔,此function的type為Exported Function
    2.我有將別名設為"?ActivateReader@@YAJH@Z",但是跳出NotSupportedException

    上網查了一下,找到此篇文章
    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=787906&SiteID=1

    似乎是要轉成"C"  style  wrapper ,不是很懂他的意思,但是否要這樣做才行?
    但目前廠商只有給我這個RFIDAPI.dll檔,我要怎麼做才能正確的呼叫裡面的function

    再一次麻煩大家,謝謝!!


    2008年2月24日 上午 03:24


  • 1.[DllImport("RFIDAPI.dll", EntryPoint = "?ActivateReader@@YAJH@Z")]
                public static extern Int32 ActivateReader(int iCom);

    2. Int32 ErrCode = ActivateReader(5);

    我將long改成Int32就可以執行了!!但有一個疑問
    我知道將DllImport進來的function要注意他的名稱和資料型別,但在資料型別這邊是不是要將呼叫的function裡的參數以及回傳值型態都改以Managed寫法來寫?

    另外上面那篇的連結我還是不明瞭他的意思,能麻煩懂的人解釋一下嗎?
    不好意思,麻煩大家了!!再一次感謝大家
    2008年2月24日 上午 04:20
  • 那你直接問廠商比較快,通常只要是有 extern "C" 的 API 都是可以被呼叫的。

    而廠商寫在 API 文件中的函數規格如果有誤,是廠商要負責 ...。

    2008年2月24日 上午 04:21
  •  zack9433 寫信:


    1.[DllImport("RFIDAPI.dll", EntryPoint = "?ActivateReader@@YAJH@Z")]
                public static extern Int32 ActivateReader(int iCom);

    2. Int32 ErrCode = ActivateReader(5);

    我將long改成Int32就可以執行了!!但有一個疑問
    我知道將DllImport進來的function要注意他的名稱和資料型別,但在資料型別這邊是不是要將呼叫的function裡的參數以及回傳值型態都改以Managed寫法來寫?

     

    通常 Win32 API 所使用的資料型別都可以對應到 .NET Framework 型別,你可以看:

    http://msdn2.microsoft.com/zh-tw/library/ac7ay120(VS.80).aspx

     

     zack9433 寫信:


    另外上面那篇的連結我還是不明瞭他的意思,能麻煩懂的人解釋一下嗎?
    不好意思,麻煩大家了!!再一次感謝大家

     

    上面哪來的連結 = =....

    2008年2月24日 上午 04:26
  • HI

    謝謝小朱大哥的幫忙!!

    現在我又遇到一個問題,我想要呼叫Dll裡面的SelectTag函式
    以下是廠商說明文件對SelectTag函式說明的內容:

    Select Tag ID
    Function Description:
    Reader will automatically select one available tag from field and then read tag ID

    Function call:
    long SelectTag(int iTagProtocol,LPTSTR &lpBuf)

    Parameter(Input)
    iTagProtocol : refer to TagProtocol Property

    Parameter(output)
    lpBuf : tag id string

    Return code:
    Refer to Error Code Property

    Example code:

    Code Snippet

    LPTSTR strTAG;
    int protocol = 6;
    long ErrCode = SelectTag(protocol,strTAG);
    if (ErrCode == 0) {
    }



    以下是我叫用函式的程式碼片段:

    Code Snippet

    [DllImport("RFIDAPI.dll", EntryPoint = "?SelectTag@@YAJHAAPAG@Z")]

    public static extern Int32 SelectTag(int iTagProtocol, [MarshalAs(UnmanagedType.LPTStr)]String lpBuf);

    .

    .

    .

    String OutputTagID = "";
    int protocol = 6;

    Int32 ErrCode = SelectTag(protocol, OutputTagID);


    執行後跳出NotSupportedException

    我在想是在叫用函式時,第二個參數不對。
    看廠商的說明第二個參數是用來接收Output結果。該怎麼寫才會正確呢?
    謝謝大家的幫忙
    2008年2月24日 上午 07:12
  • Hi,

    TagID是Output的,你可以加上ref關鍵字測試看看。

     

    2008年2月24日 上午 07:37
    版主
  • HI

    Code Snippet

    [DllImport("RFIDAPI.dll", EntryPoint = "?SelectTag@@YAJHAAPAG@Z")]
                public static extern Int32 SelectTag(int iTagProtocol,[MarshalAs(UnmanagedType.LPTStr)]ref String lpBuf);

    .

    .

    .

    String OutputTagID = "";
    int protocol = 6;

    Int32 ErrCode = SelectTag(protocol, ref OutputTagID);


    是這個樣子嗎?
    執行結果出來還是在呼叫SelectTag的地方
    Int32 ErrCode = SelectTag(protocol, ref OutputTagID);
    跳出NotSupportedException

    是我用的不對嗎?
    2008年2月24日 上午 08:32
  • 找了好久~~原來是在函數參數封送時的問題。

    我用undname去查看?SelectTag@@YAJHAAPAG@Z的參數型態

    在VS2005 命令提是字元下以下指令

    undname
    ?SelectTag@@YAJHAAPAG@Z

    以下為輸出結果:

    Undecoration of :- "?SelectTag@@YAJHAAPAG@Z"
    is :- "long __cdecl SelectTag(int,unsigned short * &)"

    現在我將我的參數改成

    Code Snippet

    [DllImport("RFIDAPI.dll", EntryPoint = "?SelectTag@@YAJHAAPAG@Z")]

    public static extern Int32 SelectTag(int iTagProtocol,ref ushort lpBuf);



    ushort OutputTagID = 0;

    int protocol= 6;

    Int32 ErrCode = SelectTag(protocol,ref OutputTagID);


    改成這樣子的確可以使用讀取的功能,但是它回傳的並非是字串值,好像是回傳位址值的樣子,
    所以我要怎麼在C#中去取這位址的字串?
    請各位幫個忙一下!! 感激不盡
    2008年2月26日 上午 05:12
  • Hi,

    如果說用下面這樣的方式可行嗎

    public static extern Int32 SelectTag(int iTagProtocol,ref String lpBuf);

     

    2008年2月27日 上午 09:19
    版主
  • 我試過了,是可以執行應用程式,但是按下讀取的功能時,讀到Tag在PDA上跳出錯誤視窗,

    錯誤
    原生例外狀況發生在,connectSQL.exe。

    [按下詳細資料]
    錯誤
    例外狀況程式碼:0xc0000005
    例外狀況位址:0x03f8cbd4
    正在讀取:0x00000020

    應該是要用StringBuilder來做,所以改成
    Code Snippet

    [DllImport("RFIDAPI.dll", CharSet = CharSet.Auto, EntryPoint = "?SelectTag@@YAJHAAPAG@Z")]
            public static extern Int32 SelectTag(int iTagProtocol,StringBuilder lpBuf);


    StringBuilder OutputTagID = new StringBuilder();

    int protocol = 6;

    Int32 ErrCode = SelectTag(protocol, OutputTagID);

    MessageBox.Show(OutputTagID.ToString());


    執行讀取時PDA沒有跳出錯誤視窗,但是Message不是顯示我讀到的Tag名稱,而是"?"..........

    可能是沒有加上[MarshalAs(UnmanagedType.LPTStr)],但一加上這個就跳出NotSupportException.....
    若改成[MarshalAs(UnmanagedType.LPWStr)],很意外的可以執行,也能讀取,但Message顯示的還是"?"........

    已經有點不知道要怎麼去解決了,不過還是很感謝你熱心的回應。


    2008年2月27日 上午 10:39
  • 終於解決了....但是是用笨方法,還是搞不懂為什麼存進StringBuilder會是"?"

     

    以下是我目前的寫法

     

    Code Snippet

    [DllImport("RFIDAPI.dll",CharSet = CharSet.Auto,EntryPoint ="?SelectTag@@YAJHAAPAG@Z")]
            unsafe public static extern Int32 SelectTag(int iTagProtocol,out char* lpBuf);

     

     

    unsafe{

    char* OutputTagID; //存放讀到的Tag位址

    StringBuilder OutputTag = new StringBuilder(); //用來存放Tag字元

    int protocol = 6;

    int ErrCode = SelectTag(protocol,out OutputTagID); //讀取Tag

    while (i < 16)
    {

    char* TagID = &OutputTagID[i];

    OutputTag.Append(*TagID);  //將OutputTagID取出存入StringBuffer
    i++;

    }

    MessageBox.Show(OutputTag.ToString());

    }

     

    目前能顯示出Tag的ID了,謝謝之前大家的幫忙!!3Q~~~

    2008年2月29日 上午 02:25