当前位置:编程学习 > C#/ASP.NET >>

C#中调用C++生成的dll问题

现有一C++编译的dll方法:
extern "C" __declspec(dllexport) void __stdcall  decry(void* stream,char filename[]);

而我用的开发工具是C#,传递给第一个参数的值是从数据库的image字段中取出来的,请问C#中如何调用该方法?
在线等待中 --------------------编程问答-------------------- 如果C#允许使用不安全代码的话,输入输出可以直接用 void* 或者byte*,byte数组也是可以的,不过你得保证长度足够 --------------------编程问答-------------------- 说白了,C#调用C++或者C++调用C#,本质上其实就是内存,长度足够,地址正确就行了,你甚至可以自定义一个类型来做参数 --------------------编程问答-------------------- 不明白,我现在是从数据库中的某一image类型字段读取数据,然后要传给dll中的方法 --------------------编程问答--------------------

[DllImport("DLL名称", EntryPoint = "入口点")]
private static extern string 方法名();
--------------------编程问答-------------------- 这一句我知道,但方法里面的二个参数该定义成啥?

定义成这样时:
public extern static void decry(Intptr pt,string filename);

又不知如何将image类型转换成Intptr传给方法 --------------------编程问答-------------------- void* 在托管中对应的类型为IntPtr,根据 stream的参数名来猜测,应该是一个文件流的句柄(流的入口地址)你可以在内存中创建一个流并获取其句柄试试
比如filestream fs=new filestream("",..); fs.handle就是此文件流的句柄 --------------------编程问答-------------------- 可问师是filestream fs=new filestream("",..); 这里的第一个参数也是Intptr类型的啊,这个Intptr如何得到?


不好意思,我是新手 --------------------编程问答-------------------- 以下是我从MSDN复制的如何平台调用void *参数示例,希望对你有用:

该示例说明如何将数据传递给预计将 void 指针作为参数的非托管函数。该示例提供了两种解决方案。

Void 示例使用以下非托管函数(这里同时显示其原始函数声明): 

从 PinvokeLib.dll 导出的 SetData。

  复制代码 
void SetData(DataType typ, void* object)
 

PinvokeLib.dll 是一个自定义非托管库,它包含前面列出的函数的实现。

在该示例中,LibWrap 类包含一个类型枚举和两种托管原型方法:SetData 和 SetData2。这两种方法表示以下用于将数据传递给需要 void* 的非托管函数的方法: 

SetData 声明 DataType 枚举和一个对象。MarshalAsAttribute 属性将 UnmanagedType 枚举设置为 AsAny,这将在运行时确定对象的类型并将该对象作为该类型进行封送处理。

SetData2 重载该方法以声明 DataType 枚举并标识双精度类型或字符串类型。ref(在 Visual Basic 中为 ByRef)关键字通过引用传递此双精度类型。

App 类调用这些方法并初始化枚举元素。第一种方法指定每个枚举元素;第二种方法仅指定最大的值类型和字符串。

下面的代码示例的源代码由 .NET Framework 平台调用技术示例提供。

声明原型
Visual Basic  复制代码 
Public Class LibWrap
   Public Enum DataType
      DT_I2 = 1
      DT_I4
      DT_R4
      DT_R8
      DT_STR
   End Enum 'DataType

   ' Uses AsAny when void* is expected.
   Declare Sub SetData Lib "..\LIB\PinvokeLib.dll" ( _
      ByVal t As DataType, < MarshalAs( UnmanagedType.AsAny )> ByVal o _
        As Object )
   ' Uses overloading when void* is expected.
   Overloads Declare Sub SetData2 Lib "..\LIB\PinvokeLib.dll" Alias _
       "SetData" ( ByVal t As DataType, ByRef d As Double )
   Overloads Declare Sub SetData2 Lib "..\LIB\PinvokeLib.dll" Alias _
       "SetData" ( ByVal t As DataType, ByVal s As String )
End Class 'LibWrap

 
C#  复制代码 
public class LibWrap
{
   public enum DataType 
   {
      DT_I2 = 1,
      DT_I4,
      DT_R4,
      DT_R8,
      DT_STR
   }
   
   // Uses AsAny when void* is expected.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern void SetData( DataType t, 
      [ MarshalAs( UnmanagedType.AsAny )] Object o );
   // Uses overloading when void* is expected.
   [ DllImport( "..\\LIB\\PinvokeLib.dll", EntryPoint="SetData" )]
   public static extern void SetData2( DataType t, ref double i );
   [ DllImport( "..\\LIB\\PinvokeLib.dll", EntryPoint="SetData" )]
   public static extern void SetData2( DataType t, String s );   
}
 

调用函数
Visual Basic  复制代码 
Public Class App
   Public Shared Sub Main()
      Console.WriteLine( "Calling SetData using AsAny..." + _
         ControlChars.CrLf )
      LibWrap.SetData( LibWrap.DataType.DT_I2, CShort(12) )
      LibWrap.SetData( LibWrap.DataType.DT_I4, CLng(12) )
      LibWrap.SetData( LibWrap.DataType.DT_R4, CSng(12) )
      LibWrap.SetData( LibWrap.DataType.DT_R8, CDbl(12) )
      LibWrap.SetData( LibWrap.DataType.DT_STR, "abcd" )
      
      Console.WriteLine( ControlChars.CrLf + "Calling SetData _
         using overloading..." )
      Console.WriteLine( ControlChars.CrLf )   
      Dim d As Double   = 12
      LibWrap.SetData2( LibWrap.DataType.DT_R8, d )
      LibWrap.SetData2( LibWrap.DataType.DT_STR, "abcd" )
   End Sub 'Main
End Class 'App

 
C#  复制代码 
public class App
{
   public static void Main()
   {
      Console.WriteLine( "Calling SetData using AsAny... \n" );
      LibWrap.SetData( LibWrap.DataType.DT_I2, (short)12 );
      LibWrap.SetData( LibWrap.DataType.DT_I4, (long)12 );
      LibWrap.SetData( LibWrap.DataType.DT_R4, (float)12 );
      LibWrap.SetData( LibWrap.DataType.DT_R8, (double)12 );
      LibWrap.SetData( LibWrap.DataType.DT_STR, "abcd" );
      
      Console.WriteLine( "\nCalling SetData using overloading... \n" );   
      double d = 12;
      LibWrap.SetData2( LibWrap.DataType.DT_R8, ref d );
      LibWrap.SetData2( LibWrap.DataType.DT_STR, "abcd" );
   }
}
 
--------------------编程问答-------------------- 上面太杂,看下最关键的几句:
void SetData(DataType typ, void* object)
public static extern void SetData( DataType t, 
      [ MarshalAs( UnmanagedType.AsAny )] Object o );

void* object参数解释:
MarshalAsAttribute 属性将 UnmanagedType 枚举设置为 AsAny,这将在运行时确定对象的类型并将该对象作为该类型进行封送处理。
也说是说,用[ MarshalAs( UnmanagedType.AsAny )] 属性修饰参数后,编译时不确定类型,在运行时根据传入的参数自动确定类型

建议:你可以直接传入一个 byte[] 数组(Image字段转为字节数组方便) --------------------编程问答-------------------- 我的定义:
        [DllImport("Decry.dll", CallingConvention = CallingConvention.Winapi)]
        public extern static void decry(byte[] bs,string filename);

实现函数:
        /// <summary>
        /// 生成临时文件
        /// </summary>
        /// <param name="db"></param>
        /// <param name="id"></param>
        private void GetFileByKey(Database db, string id)
        {
            try
            {
                string query = "select 附件名称+附件格式 as 附件名称,附件内容 from dbo.著录中心附件 a,dbo.著录中心附件内容 b" +
                                "  where a.Fj_ID=b.Fj_ID  and a.附件编号=b.附件编号 and  a.Fj_ID='" + id + "'";
                DbCommand cmd = db.GetSqlStringCommand(query);
                System.Data.IDataReader dr = db.ExecuteReader(System.Data.CommandType.Text, query);
                string filename = string.Empty;
                string path = System.Web.HttpContext.Current.Server.MapPath("../UPLOADTEMP/");
                System.IO.DirectoryInfo d = System.IO.Directory.CreateDirectory(path + "DAGL");
                path = path + "DAGL\\";
                byte[] content;
               // Int32 position = 0;
                while (dr.Read())
                {
                    filename = dr["附件名称"].ToString();
                    content = (byte[])dr["附件内容"];
                    decry(content, path + filename);
                }
                dr.Close();
            }
            catch
            {
                throw;
            }
        }

这样有问题吗?不对的话,该如何实现?

因为现在报
"尝试读取或写入受保护的内存。这通常指示其他内存已损坏" --------------------编程问答-------------------- d --------------------编程问答-------------------- 没有高手来帮我解决下吗? --------------------编程问答--------------------
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,