5ifree.eicp.net

瑞雪年

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  214 随笔 :: 0 文章 :: 343 评论 :: 0 引用

好吧!我承认我是标题党,其实本文主要是想介绍一下如何使用vs.net 2008生成,可供.net程序及c/c++程序同时使用的dll (暂时就叫它perfect dll好了), 起这个蛋痛的标题,纯粹是为了吸引眼球用的。说白了,就是把managed code和unmanaged code通过程序集链接器 (Al.exe)创建在一个程序集中。原理参考: 如何:生成多文件程序集

最佳实践:
1. 创建一个C++ Win32 dll project, 比如就叫asmproject。


2. 在asmproject.cpp中,添加一个add方法,这个方法简单的以至于我都能用asm来写,好吧,那就的叟一下好了。

 

extern "C" __declspec(dllexport) int add(int a, int b)
{
int c;
__asm
{
mov eax, a;
add eax, b;
mov c, eax;
}
return c;
}

 

 

3. 再创建一个C# Class Library的项目,叫asmlibrary吧,添加一个静态类

 

public static class asmlibrary
{
[DllImport(
"asmlibrary.dll")]
public static extern int add(int a, int b);
}

 

 

注意那个DllImport,是引用的自已哦。

4. 下边,关键的步骤来了。用记事本打开asmlibrary.csproj文件,找到<OutputType>项,将它改为Module, 保存。回到vs.net中,生成asmlibrary,这时,去生成目录下看,你会看到生成一个asmlibrary.netmodule文件。


5. 打开那个c++项目asmproject的Property Pages, 找到Configuration Properties -> Linker -> Input -> Addtional Dependencies, 添加上边生成的那个asmlibrary.netmodule文件, 再找到
Configuration Properties -> Linker -> General -> Output File,改成asmlibrary.dll。这是,再编译这个c++项目,就可以得到这个名字叫asmlibrary.dll的"perfect dll"了。

好了,来调用一下试试吧,再建一个C# windows appliction,添加引用asmlibrary.dll,看看是不是可以引用?!

让我们使用两个工具,来查看一下这个“神奇的”dll吧:

示例代码下载:asmlibrary.zip

 

非常感谢您的支持,如果您果真是被标题吸引来的,那么下边两篇文章或许会有所帮助:

http://www.atrevido.net/blog/PermaLink.aspx?guid=ac03f447-d487-45a6-8119-dc4fa1e932e1

http://stackoverflow.com/questions/959087/is-it-possible-to-execute-an-x86-assembly-sequence-from-within-c

posted on 2010-03-23 12:57 瑞雪年 阅读(2129) 评论(28) 编辑 收藏

评论

#1楼 2010-03-23 14:00 疯狂的狐狸      
我承认...我被骗了...
 回复 引用 查看   

#2楼 2010-03-23 14:06 try      
不错,很实用的技巧
 回复 引用 查看   

#3楼 2010-03-23 15:56 AutumnWinter      
return c;
这句没必要,汇编代码默认返回值在EAX中,直接这样既可
MOV, EAX, A
ADD, EAX, B
 回复 引用 查看   

#4楼 2010-03-23 15:59 申飞      
挺不错的。
 回复 引用 查看   

有个狠的!!
http://www.cnblogs.com/zxjay/archive/2008/09/13/1290529.html
最后一种方法
 回复 引用 查看   

#6楼 2010-03-23 17:09 DiggingDeeply      
C++/CLI
 回复 引用 查看   

#7楼 2010-03-23 17:10 萧萧空间      
很好
 回复 引用 查看   

#8楼 2010-03-23 18:05 边城浪      
推荐的第一篇文章中.
http://www.atrevido.net/blog/PermaLink.aspx?guid=ac03f447-d487-45a6-8119-dc4fa1e932e1

在Windows7中运行报错:
尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

难道Windows7中不支持这样的调用?
 回复 引用 查看   

#9楼 2010-03-23 18:07 边城浪      
@飘遥(Zhenxing Zhou)
最后一种方法,在Win7中报错:
尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

什么原因?
 回复 引用 查看   

#10楼[楼主] 2010-03-23 18:17 瑞雪年      
@AutumnWinter
多谢指教!!

@飘遥(Zhenxing Zhou)
本文后面推荐的文章和那个应该是一回事,我感觉那个叫“机器码”更合适。

@边城浪
我也说不好原因,感觉还是系统保护内存方面的问题。
 回复 引用 查看   

lz可以去睡觉了!
 回复 引用 查看   

#12楼[楼主] 2010-03-24 07:54 瑞雪年      
@步碎酒散花醉
多谢关心!!!
 回复 引用 查看   

#13楼 2010-03-24 10:04 zoti      
終於看明白了,謝謝樓主.
 回复 引用 查看   

#14楼 2010-03-25 23:49 DiryBoy      
很好很强大,自己以前捣鼓不出来……收藏了
 回复 引用 查看   

@边城浪
将最有一种方法简单分析修改了一下,应该能正常运行了。
http://www.xianfen.net/Article140.aspx
 回复 引用 查看   

#16楼 2010-06-23 00:38 大石头      
直接使用C++/CLI,更加直接!

BTW,经过测试,C#可以直接把汇编“注入”内存(汇编以二进制格式存在,由C#写入内容),然后创建一个委托,即可直接调用这段汇编代码。当然,这段汇编需要写成一个函数才行,执行完之后一定一定要把执行权交回去!
 回复 引用 查看   

#17楼[楼主] 2010-06-23 16:03 瑞雪年      
@大石头
感谢提醒!!!

试了下c++,果真方便很多!
// perfectdll.h

#pragma once

extern "C" __declspec(dllexport) int add(int a, int b);

using namespace System;


public ref class perfectdll
{
public:
	static int add(int a, int b)
	{
		return ::add(a, b);
	}
};



只需要一个项目,一次编译即可,只是这样写法多了一次转调,生成的文件也相对大了一点。

示例下载:perfectdll.zip
 回复 引用 查看   

#18楼 2010-06-23 16:33 大石头      
引用瑞雪年:
@大石头
感谢提醒!!!

试了下c++,果真方便很多!
// perfectdll.h

#pragma once

extern "C" __declspec(dllexport) int add(int a, int b);

using namespace System;


public ref class perfectdll
{
public:
	static int add(int a, int b)
	{
		return ::add(a, b);
	}
};



只需要一个项目,一次编译即可,只是这样写法多了一次转调,生成的文件也相对大了一点。

示例下载:perfectdll.zip



呵呵,恭喜了!
不过呀,我倒是要告诉你,还有更简单的做法,你慢慢去尝试吧。

说起这个,心里有点不是滋味呀,早几天写了一篇关于语言之争的文章,里面我就提到我擅长混用各种语言,特别是C++/CLI,无奈还有人说我百度出来的名词而已。
我这都不知道是怎么啦,博客园就成了这个样子了,唉!~
 回复 引用 查看   

#19楼[楼主] 2010-06-23 17:20 瑞雪年      
@大石头
还有更简单的???是真的吗??!!
我真的想不出来了,莫非也能加属性,像:
[MethodImpl(MethodImplOptions.Unmanaged, MethodCodeType=MethodCodeType.Native), SuppressUnmanagedCodeSecurity]
public static int add(int, int);


恳请“大石头”赐教!!!拜谢!!!!!!!
 回复 引用 查看   

#20楼 2010-06-23 17:22 大石头      
不不不,不用你加,编译器会自动加的,呵呵

你为什么不试试直接在C++/CLI里面使用嵌入汇编呢?

不知道我所理解的是不是你所想要的


如果你熟知C++/CLI的原理,应该不难理解
 回复 引用 查看   

#21楼[楼主] 2010-06-23 21:33 瑞雪年      
@大石头
尝试managed method中嵌入asm,结果编译不通过
// perfectdll.h

#pragma once


using namespace System;

public ref class perfectdll
{
public:		
	static int add(int a, int b)
	{
		__asm
		{
			mov eax, a;
			add eax, b;
		}
	}
};



尝试取地址,结果生成的dll,给vc++使用没问题,c#引用后,提示"现用语言不支持“perfectdll.add”"
// perfectdll.h

#pragma once

extern "C" __declspec(dllexport) int add(int a, int b);

using namespace System;

public ref class perfectdll
{
	public:		
		static int (__clrcall  *add)(int, int) = &::add;
};



再次恳请大石头不吝赐教!!!
 回复 引用 查看   

#22楼 2010-06-24 08:41 大石头      
什么叫C++/CLI?

CLR无法识别嵌入汇编,编译当然通不过了
 回复 引用 查看   

#23楼 2010-06-24 08:42 大石头      
C++/CLI项目可是可以混写C++和CLI的

你在C++类里面嵌入汇编试试,然后CLI类调用C++类
 回复 引用 查看   

#24楼[楼主] 2010-06-24 10:13 瑞雪年      
@大石头
那不就和17楼说的是一回事儿??!!还是多一次转调。
其实c++也可以像c#那样,使用属性:
// perfectdll.h

#pragma once

extern "C" __declspec(dllexport) int add(int a, int b);

using namespace System;


public ref class perfectdll
{
public:
	 [System::Runtime::InteropServices::DllImport("perfectdll.dll")]
	static int add(int a, int b);
};




只是还不能使用像编译器生成那样的定义:
	[System::Runtime::InteropServices::PreserveSig, System::Runtime::CompilerServices::MethodImpl(System::Runtime::CompilerServices::MethodImplOptions::Unmanaged, MethodCodeType=System::Runtime::CompilerServices::MethodCodeType::Native), System::Security::SuppressUnmanagedCodeSecurity]
	static int add(int a, int b);


不过已经很满意了!再次感谢大石头!!!
 回复 引用 查看   

#25楼 2010-06-24 10:15 大石头      
17楼那里,你的add代码是写在本项目还是另一个项目?另一个DLL?


我的意思是让你写在C++/CLI项目里面,这个项目有托管的,也有非托管的,明白?
 回复 引用 查看   

#26楼[楼主] 2010-06-24 10:35 瑞雪年      
@大石头
17楼的示例是一个项目,比用C#的两个项目是方便很多,再加上使用属性标记,避免方法转调,我自认为很满意了,只是要是能生成像编译器生成的那样,Nativa Call 就完美了!
 回复 引用 查看   

#27楼 2010-06-24 13:47 大石头      
这么说是我理解错你的意思了,我所想表达的就是同一个项目,呵呵!

编译之后,你反编译看看,就发现有那些特性的了
 回复 引用 查看   

#28楼 2011-08-24 11:34 隴上煙雨劍      
万恶的标题党
 回复 引用 查看