Silverlight5通过P/Invoke调用自定义C/C++ DLL(Lua)

   上一篇《Silverlight5通过P/Invoke调用系统win32的三个示例》展示了silverlight5通过P/Invoke调用系统win32的三个示例,本篇给出自定义win32 dll及其在Silverlight5中调用的代码。

  注1:为了确保silverilght5在浏览器或桌面上成功调用win32 DLL,必须在项目属性中勾选相应的权限:

    勾选Enable running application out of the browser及其Require elevated trust when running in-browser

    勾选Require elevated trust when running in-browser

  注2:win32 dll文件编译后放在\windows\system32或\windows\system目录下,win7 x64的系统放在后者。

  注3:winform/wpf中调用类似

.h

// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the MYDLL_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// MYDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
struct HHFC_SET {  ;char* UID;   int     code;};// This class is exported from the MyDLL.dll
class MYDLL_API CMyDLL {
public:
    CMyDLL(void);
    // TODO: add your methods here.
};
//extern MYDLL_API int nMyDLL;
extern "C" MYDLL_API int nMyDLL;
extern "C" MYDLL_API float fnMyDLL(float x ,float y);// 注意得加上extern  "C",否则无法P/Invoke

.cpp

#include "stdafx.h"
#include "MyDLL.h"
#include <iostream>   #include "LuaPlus.h" #include "LuaPlusHelper.h" #pragma comment(lib,"LuaPlusLib.lib")   using namespace LuaPlus; using namespace std;// This is an example of an exported variable
MYDLL_API int nMyDLL=0;
// This is an example of an exported function.
MYDLL_API float fnMyDLL(float x ,float y)
{
    //调用Lua脚本并计算
    string str;
    str.append("function Add(x, y)\n");
    str.append(" return x*y;\n");
    str.append("end\n");
    int iret = state->DoString(str.c_str());// state->DoFile("a.lua");
    LuaFunction Add = state->GetGlobal("Add");
    float myret = Add(x,y);
    return myret;
}
extern "C" __declspec(dllexport)  int WINAPI add()
{
    return 101;
}
extern "C" __declspec(dllexport)  int WINAPI add2(HHFC_SET* stru ) {    stru->UID="this is a win32 test about struct";   stru->code=3;      return 1; }extern "C" __declspec(dllexport) float* WINAPI add3(){  float* num=(float*)malloc(4);  num[0]=11.2f;  num[1]=21.3f;  num[2]=33.5f;  num[3]=46.2f;  return num;}// This is the constructor of a class that has been exported.
// see MyDLL.h for the class definition
CMyDLL::CMyDLL()
{
    return;
}

.xaml

<Grid x:Name="LayoutRoot" Background="White">
 
    <StackPanel Orientation="Horizontal" VerticalAlignment="Top" Margin="24,24,0,0">
        <TextBlock Name="textBlock1" Text="add       函数结果:" Height="23" />
        <TextBox Name="textBox1" Width="120" Height="23" />
    </StackPanel>
 
    <StackPanel Orientation="Horizontal" VerticalAlignment="Top" Margin="24,64,0,0">
        <TextBlock Name="textBlock2" Text="fnMyDLL函数结果:" Height="23"/>
        <TextBox Name="textBox2" VerticalAlignment="Top" Width="120" Height="23"/>
    </StackPanel>
    
 
    <Button Content="Button" Height="32" Margin="120,101,202,0" Name="button1" VerticalAlignment="Top" Width="78" Click="button1_Click" />
</Grid>

.cs

public partial class MainPage : UserControl
    {
        [DllImportAttribute("user32.dll", EntryPoint = "MessageBoxW")]
        public static extern int MessageBoxW(int hWnd, [In][MarshalAs(UnmanagedType.LPWStr)] string lpText, [In][MarshalAs(UnmanagedType.LPWStr)] string lpCaption, int uType);
 
        [DllImport("MyDll.dll", EntryPoint = "add", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = false)]
        public static extern int add();
 
        [DllImport("MyDll.dll", EntryPoint = "fnMyDLL", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = false)]
        public static extern float fnMyDLL(float x,float y);
 
        [DllImport("MyDLL.dll", EntryPoint = "add2", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = false)]
        public static extern int add2(ref HHFC_SET stru);
        [DllImport("MYDLL.dll", EntryPoint = "add3", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi, SetLastError = false)]        public static extern IntPtr add3();        //EntryPoint: 指定要调用的 DLL 入口点。默认入口点名称是托管方法的名称 。
        //CharSet: 控制名称重整和封送 String 参数的方式 (默认是UNICODE)
        //CallingConvention指示入口点的函数调用约定(默认WINAPI)
        //SetLastError 指示被调用方在从属性化方法返回之前是否调用 SetLastError Win32 API 函数 (C#中默认false )
 
        public MainPage()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            this.textBox1.Text = add().ToString();
            this.textBox2.Text = fnMyDLL(12,2).ToString();
            MessageBoxW(0, "提交成功", "温馨提示", 0);
            HHFC_SET stru = new HHFC_SET();             stru.Uid = "";             Console.WriteLine(stru.Uid);             int a = add2(ref stru);             Console.WriteLine(stru.Uid);             IntPtr d = add3();            float[] bytes2 = new float[Marshal.SizeOf(d)];            Marshal.Copy(d, bytes2, 0, 4);        }    }
    [StructLayout(LayoutKind.Sequential)]     public struct HHFC_SET     {         [MarshalAs(UnmanagedType.LPStr)]         public String Uid;         [MarshalAs(UnmanagedType.I4)]         public int code;     } 

-----------------------------------------------------------------------------------------  

.net调用C DLL 

编写C程序如下:

#include "stdio.h"
__declspec(dllexport) void MyFun() {     printf("this is a dll\n"); }

 

保存,取名为My.C

 

运行 VS 命令提示,Cl /c  路径/My.c

运行以后会生成 My.Obj,默认在vs安装文件夹的VC目录下

再运行 link/dll   路径/My.obj

在同一个目录会生成My.dll

 

在C#中调用:

将dll复制到bin目录,编写如下C#代码:

static void Main(string[] args)
{
   MyFun();
}
[DllImport("My.dll")]
public extern static void MyFun();

-----------------------------------------------------------------------------------------   

C#传委托给C的函数指针调用问题

C代码如下:

#include "stdio.h"
__declspec(dllexport) int Call(int (*qq)(int num),char * str)
{   
    printf(str);
    return qq(123);
}

多次验证发现在C#中传委托给C中的函数指针,如果委托不带参数则都能成功运行,但是委托一带参数不管是int参数还是string参数或者其他参数,都会报“ 尝试读取或写入受保护的内存。这通常指示其他内存已损坏”的错误,找了一天才找到解决方法,既在C#的委托声明上加[UnmanagedFunctionPointer(CallingConvention.Cdecl)],正确调用如下:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
   public delegate int MyDeg(int num);
   class Program
   {
       static void Main(string[] args)
       {
            
           try
           {
               MyDeg myd = new MyDeg(FF);
               Console.WriteLine(Call(myd, "helloworld"));
           }
           catch (Exception ex)
           {
               Console.WriteLine(ex.Message);
           }
 
       }
 
       static int FF(int num)
       {
           Console.WriteLine(num);
           return num + 1;
 
       }
 
       [DllImport("my.dll", EntryPoint = "Call")]
       public extern static int Call(MyDeg mm ,string  str);
   }

  

posted on   chuncn  阅读(1926)  评论(5编辑  收藏  举报

导航

< 2012年1月 >
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 1 2 3 4
5 6 7 8 9 10 11
点击右上角即可分享
微信分享提示