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#