VB.NET嵌入式DLL在另一个DLL中作为嵌入式资源? [英] VB.NET embedded DLL in another DLL as embedded resource?

查看:178
本文介绍了VB.NET嵌入式DLL在另一个DLL中作为嵌入式资源?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在C#中看到这样做,例如虽然,我似乎无法弄清楚如何在VB.NET中这样做。对于某些背景,我已经创建了一个自定义ComboBox控件作为.dll,我需要在另一个.dll(ArcMap组件)中实现。



不幸的是,ArcMap不允许与组件一起加载第三方DLL,因为没有选项可以引用加载项的任何第三方程序集。



如果有人可以指向正确的方向,那将不胜感激。

解决方案

我们在VB.NET中使用这种技术在Visual Studio 2008 ...



首先,项目需要知道将其他dll作为嵌入式资源。在解决方案资源管理器中,将dll作为文件添加到项目中(而不是参考)。然后,打开文件的属性,并将构建操作设置为嵌入式资源。建议您在项目结构中创建dll文件的本地副本,而不是链接到其他位置。一旦项目包含dll文件,您可以添加该dll副本的引用,以便您可以在设计时使用其内容。



确保其他dll包含在您的编译DLL中,但不会在需要时自动加载。这就是以下代码:

 公共模块核心

私有_initialized为布尔

public Sub EnsureInitialized()
如果不是_initialized然后
AddHandler AppDomain.CurrentDomain.AssemblyResolve,AddressOf AssemblyResolve
_initialized = True
End If
End Sub

私有函数AssemblyResolve(ByVal sender As Object,ByVal e As ResolveEventArgs)As Assembly
Dim resourceFullName As String = String.Format([CONTAINER ASSEMBLY]。{0} .dll e.Name.Split(,c)(0))
Dim thisAssembly As Assembly = Assembly.GetExecutingAssembly()
使用资源As Stream = thisAssembly.GetManifestResourceStream(resourceFullName)
如果资源IsNot Nothing然后返回Assembly.Load(ToBytes(resource))
返回没有
结束使用
结束函数

私有函数ToBytes(ByVal实例作为流)作为字节()
Dim capacity As Integer = If(instance.CanSeek,Conv ert.ToInt32(instance.Length),0)

使用结果As New MemoryStream(capacity)
Dim readLength As Integer
Dim buffer(4096)As Byte

Do
readLength = instance.Read(buffer,0,buffer.Length)
result.Write(buffer,0,readLength)
循环while readLength> 0

返回result.ToArray()
结束使用
结束函数

结束模块
pre>

将此模块放置在项目的某处,并确保调用 EnsureInitialized 方法附加 AssemblyResolve 处理程序之前调用dll中的任何其他代码。



注意:将[CONTAINER ASSEMBLY]替换为您的dll名称。



另请注意,上述代码是我们实际使用的一个精简版本,因为我们包括log4net日志记录在战略地点。日志消息对于真正的功能不是必需的,所以我删除了它们,以简洁和清晰。



这种方法的主要注意事项是 AssemblyResolve 处理程序必须手动附加。即使您无法设置内容,因此在消费代码初始化期间仅调用 EnsureInitialized 只能调用一次,您可以调用 EnsureInitialized 在您自己的任何模块中,需要其他dll执行。这使得代码更加细腻,因为您必须记住进行初始化调用,但它允许您在晚上睡觉时,知道dll将在您需要时可用。



根据我的经验,一些其他的DLL在作为嵌入式资源提供时不会很好,所以你可能需要玩一点才能使事情发挥作用。



最后注意:我从来没有使用过ArcMap Component,所以你的里程可能会改变!


I have seen this done in C#, such as here although, I cannot seem to figure out how to do this in VB.NET. For some background, I have created a custom ComboBox control as a .dll, and I need to implement it in another .dll(ArcMap Component).

Unfortunately, ArcMap does not allow for "third-party" DLL's to be loaded along with the component, because there is no option to reference any third-party assemblies for your add-in.

If someone could point me in the right direction, it would be more than appreciated.

解决方案

We use this technique in VB.NET in Visual Studio 2008...

First, the project needs to know to include the "other" dll as an Embedded Resource. In the Solution Explorer, add the dll as a file to your project (not as a Reference). Then, open the Properties for the file and set the Build Action to "Embedded Resource." It is recommended that you create a local copy of the dll file in the structure of your project rather than linking to some other location. Once the project includes the dll file, you can then add the reference to that copy of the dll so that you can use its contents at design-time.

That ensures that the "other" dll is included in your compiled dll, but it doesn't make it automatically load when needed. That's where the following code comes in:

Public Module Core

Private _initialized As Boolean

Public Sub EnsureInitialized()
  If Not _initialized Then
    AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf AssemblyResolve
    _initialized = True
  End If
End Sub

Private Function AssemblyResolve(ByVal sender As Object, ByVal e As ResolveEventArgs) As Assembly
  Dim resourceFullName As String = String.Format("[CONTAINER ASSEMBLY].{0}.dll", e.Name.Split(","c)(0))
  Dim thisAssembly As Assembly = Assembly.GetExecutingAssembly()
  Using resource As Stream = thisAssembly.GetManifestResourceStream(resourceFullName)
    If resource IsNot Nothing Then Return Assembly.Load(ToBytes(resource))
    Return Nothing
  End Using
End Function

Private Function ToBytes(ByVal instance As Stream) As Byte()
    Dim capacity As Integer = If(instance.CanSeek, Convert.ToInt32(instance.Length), 0)

    Using result As New MemoryStream(capacity)
        Dim readLength As Integer
        Dim buffer(4096) As Byte

        Do
            readLength = instance.Read(buffer, 0, buffer.Length)
            result.Write(buffer, 0, readLength)
        Loop While readLength > 0

        Return result.ToArray()
    End Using
End Function

End Module

Place this Module somewhere in your project and be sure to call the EnsureInitialized method to attach the AssemblyResolve handler before calling any other code in your dll.

NOTE: You'll need to replace [CONTAINER ASSEMBLY] with the name of your dll.

Also note that the above code is a stripped-down version of what we actually use because ours includes log4net logging messages at strategic places. The logging messages aren't necessary for the true functionality, so I removed them for brevity and clarity.

The major caveat to this approach is that the AssemblyResolve handler has to be attached manually. Even if you can't set things up so that EnsureInitialized is called only once during the initialization of the consuming code, you can call EnsureInitialized within any of your own modules that require the "other" dll for execution. This makes the code a little more delicate because you have to remember to make that initialization call, but it does allow you to sleep at night knowing that the dll will be available when you need it.

In my experience, some "other" dlls don't play well when they are provided as embedded resources, so you might need to play around a bit to get things working.

Final Note: I've never used ArcMap Component, so Your Mileage May Vary!

这篇关于VB.NET嵌入式DLL在另一个DLL中作为嵌入式资源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆