如果我的术语有点偏离,请原谅我.我对托管C++/CLI的了解非常有限.
我有一个MFC应用程序使用启用了/ clr选项的DLL.这个dll使用几个C#dll与使用WCF的服务器通信.在大多数情况下,这工作正常.
在C#的DLL中的一个,我已经添加扩展方法的System.Net.IPAddress类,将检索的对象的IPAddress子网掩码(使用UnicastIPAddressInformation类及其IPv4Mask).扩展方法在C#方面运行良好,但我无法弄清楚如何在托管C++/CLI代码中使用它.
首先,这甚至可能吗?如果是这样,托管C++/CLI端的语法是什么样的?我必须使用/ clr:pure选项才能使用吗?
以下是扩展方法的示例:
using System.Net;
using System.Net.NetworkInformation;
public static class IPAddressExtensions
{
public static IPAddress GetSubnetMask(this IPAddress address)
{
UnicastIPAddressInformation addressInfo = address.GetAddressInformation(); // elided
return ((addressInfo != null) ? addressInfo.IPv4Mask : null);
}
}
Run Code Online (Sandbox Code Playgroud)
在我的托管C++代码中,如果可能的话,我将如何使用此扩展方法?
unsigned long bytes= 0x010000FF; // example address - 127.0.0.1
IPAddress^ address = gcnew IPAddress(BitConverter::GetBytes(bytes));
IPAddress^ subnet = address->GetSubnetMask(); // how do I do this???
Run Code Online (Sandbox Code Playgroud) 我有VS2008解决方案包含一个项目,该项目生成一个C#可执行文件,该项目引用了一个生成包含C++/CLI和非托管C++的DLL的项目.
我想将这些合并到一个可执行文件中,因为C++ DLL包含我想要嵌入主可执行文件的安全代码.
我不能使用ILMerge,因为dll包含托管代码和非托管代码.建议的解决方案似乎是使用link.exe将C#程序集与C++目标文件链接起来.这就是我想要做的.
我手动编辑了c#可执行文件的项目文件以生成netmodule.我在可执行项目中添加了一个构建后步骤,以运行link.exe将c#netmodule和已编译的C++目标文件链接在一起,然后运行mt.exe来合并两个项目创建的程序集清单.这运行成功,但是exe仍然包含对C++项目的正常构建过程生成的dll中定义的c ++类型的引用和使用.
然后我在C++ dll的项目设置中指定了/ NOASSEMBLY,因此它还生成了一个netmodule.在C#项目中,我删除了对C++项目的引用,但在解决方案中添加了项目依赖性.我手动编辑了C#项目文件,包括类似于:
<ItemGroup>
<AddModules Include="..\Debug\librarycode.netmodule" />
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)
即引用现在由C++项目生成的C++ netmodule.
但是,现在我的post build事件中的链接器步骤失败了:
error LNK2027: unresolved module reference 'librarycode.netmodule'
fatal error LNK1311: 1 unresolved module references:
Run Code Online (Sandbox Code Playgroud)
这完全可以理解,因为我没有链接到librarycode netmodule; 我链接在用于生成netmodule的C++目标文件中.
简而言之,如何将ac#executable和C++目标文件合并到一个程序集中?我错过了什么?
到目前为止我的引用源(来自MSDN上的link.exe命令链接引用等)是以下两篇文章:
非常感谢你提前.
我在Steve Teixeira的博客中完全遵循了这个例子,并证实它有效.使用反射器,我可以看到生成的可执行文件包含两个netmodule.c#netmodule包含对另一个netmodule的引用但没有名称?!如果将程序集移动到新目录,则第二个netmodule变为未引用(显然),但可执行文件仍然运行,因为c#netmodule中存在具有正确定义的类型.
请注意,原始c#netmodule确实包含对c ++ netmodule的命名引用,因此它必须是删除名称的链接器步骤.
试图在我的示例项目中遵循此示例,我已将/ ASSEMBLYMODULE参数添加到我的后期构建链接器步骤中.链接器现在失败了
LNK2022: metadata operation failed (80040427) : Public type 'MixedLanguageLibrary.Class1' is defined in multiple places in this assembly: 'MixedLanguageDemo.exe' and 'mixedlanguagelibrary.netmodule'
LINK : fatal error LNK1255: link failed because of metadata errors
Run Code Online (Sandbox Code Playgroud)
我猜这是链接器魔术删除我缺少的模块引用名称. …
对于使用Visual Studio 6用C++编写的大型应用程序,进入现代时代的最佳方式是什么?
我想采取渐进的方法,我们慢慢移动部分代码并将新功能编写到C#中,并将其编译成可以从遗留应用程序引用的库或DLL.
这是可能的,最好的方法是什么?
编辑:此时我们仅限于Express版本,我认为不允许使用我们当前应用程序中大量使用的MFC库.它也是一个相当大的应用程序,具有很多硬件依赖性,所以我不认为批量迁移是在卡片中.
Edit2:我们已经研究过在C#中编写COM包装的组件但是没有COM经验,这是可怕和复杂的.是否有可能生成一个带有直接C接口的C#dll,其中隐藏了所有托管优势?或者COM是必要的邪恶?
使用Visual Studio 2008和Boost库1.46.1我想用/ CLR标志编译和链接以下内容:
#include <boost/thread/thread.hpp>
void run() {}
int main(int argc, char *argv[])
{
boost::thread t(run);
}
Run Code Online (Sandbox Code Playgroud)
第一个错误是关于boost :: thread中的前向声明的伪结构.这篇文章 通过声明:
namespace boost {
struct thread::dummy {};
}
Run Code Online (Sandbox Code Playgroud)
当然,我现在可以编译,但后来我得到链接器警告
警告1警告LNK4248:'boost.detail.win32._SECURITY_ATTRIBUTES'的未解析的typeref标记(0100001F); 图像可能无法运行
运行应用程序导致
应用程序无法正确启动(0xc000007b).
前面提到的论坛帖子中的所有建议都不适合我.我已经构建了Boost Threads lib的静态版本,它运行正常,没有/ CLR标志.调试/发布没有区别.我在Win7 32位下运行.
任何提示?
将std :: vector转换为.NET List的最有效方法是什么?
为了给出一些上下文,我用C++/CLI包装一个非托管的C++类.C++/CLI类包含一个指向C++类的指针,我有一个每个公共方法的包装器.
一个方法返回一个std :: vector,所以在我的包装器中我将返回.NET类List.即
// unmanaged class
class A
{
public:
std::vector<int> runList();
}
// managed class
public ref class A
{
public:
// the below is obviously extremely inefficient
List<UInt32> MethodA()
{
std::vector<unsigned int> runList = mpChannelNode->runList();
std::vector<unsigned int>::iterator itr;
List<UInt32> list = gcnew List<UInt32>();
for (itr = runList.begin(); itr != runList.end(); itr++)
{
list.Add(*itr);
}
return list;
}
private:
A* mpChannelNode;
}
Run Code Online (Sandbox Code Playgroud)
我怎样才能提高效率呢?随意为.NET类推荐不同的返回类型.让我们假设我只需要以任何形式或形式有效地将该向量导入托管世界.
使用PInvoke时,我注意到我们需要使用它IntPtr来引用Windows句柄.我想知道为什么不只是int用于手柄?我对句柄的理解是它只是一个整数值.
我有这个正则表达式"^[0-9]+\.?[0-9]*$")来匹配visual c ++中的双数或整数,但它似乎不起作用.有任何想法吗.这就是我应用代码的方式:
if ( System::Text::RegularExpressions::Regex::IsMatch(e0, "^[0-9]+\.?[0-9]*$"))
{
e0_val = System::Convert::ToDouble(e0);
}
Run Code Online (Sandbox Code Playgroud) 我有一个带有重载方法的C#类库,一个方法有一个ref参数,另一个方法有一个value参数.我可以在C#中调用这些方法,但我无法在C++/CLI中使用它.似乎编译器无法区分这两种方法.
这是我的C#代码
namespace test {
public class test {
public static void foo(int i)
{
i++;
}
public static void foo(ref int i)
{
i++;
}
}
}
Run Code Online (Sandbox Code Playgroud)
和我的C++/CLI代码
int main(array<System::String ^> ^args)
{
int i=0;
test::test::foo(i); //error C2668: ambiguous call to overloaded function
test::test::foo(%i); //error C3071: operator '%' can only be applied to an instance of a ref class or a value-type
int %r=i;
test::test::foo(r); //error C2668: ambiguous call to overloaded function
Console::WriteLine(i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我知道在C++中我不能声明重载函数,其中函数签名的唯一区别是一个接受一个对象而另一个接受一个对象,但在C#中我可以.
这是C#支持的功能,但不支持C++/CLI吗?有没有解决方法?
以下代码编译警告和intellisense错误:
ref class Test {
initonly static TimeSpan Delay = TimeSpan(1,1,1);
Test() {
long long ticks = Delay.Ticks; // << problem
}
};
Run Code Online (Sandbox Code Playgroud)
问题是:
如何正确访问Ticks?
我的C#应用程序使用包装的C++代码进行计算.
C++标题:
__declspec(dllexport) void SetVolume(BYTE* data, unsigned int width);
Run Code Online (Sandbox Code Playgroud)
C++/CLI包装器:
void SetVolume(array<Byte>^ data, UInt32 width)
{
cli::pin_ptr<BYTE> pdata = &data[0];
pal->SetVolume(pdata, width);
}
Run Code Online (Sandbox Code Playgroud)
C# :
public startCalc()
{
byte[] voxelArr = File.ReadAllBytes("Filtered.rec");
palw.SetVolume(voxelArr, 490);
//GC.KeepAlive(voxelArr); makes no sense
}
Run Code Online (Sandbox Code Playgroud)
C++ SetVolume函数启动异步计算.voxelArr不再从受管方引用,并且是垃圾回收.
在非托管代码完成它的工作而不声明voxelArr为全局变量之前,如何防止此引用的垃圾收集?创建数组副本不是一个选项,因为实际上有很多数据.内部的积极等待startCalc()也不好.