WPF: 把引用的dll移动到自定义路径

需求:

有A.exe和B.exe, 都引用了 C.dll, output路径都是 W:\Debug. 
A和B都添加了对C的引用,正常情况下C会被复制到 output 里面。 
C这样子的dll很多,不想把它们和exe放在同一级的目录,移动到子目录,如W:\Debug\3rdDll

 

办法:

1. 首先设置C.dll 

打开Project A的References,选中C.dll, 右键Properties,Copy Local 设为False,这个dll就不会拷贝了。

2. 设置PostBuild,

打开B的Build Events,  PostBuild 输入

mkdir  $(OutputPath)\3rdDll 
move $(OutputPath)\c.dll  $(OutputPath)\3rdDll\c.dll

A和B可以互换。

3. A和B 加入Config文件,

Config:  Build Action=None, Copy to Output Directory=Do not copy

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
  <runtime> 
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
      <probing privatePath="3rdDll;"/> 
    </assemblyBinding> 
  </runtime> 
</configuration>


类似于:

<configuration>

    <runtime>

        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

            <dependentAssembly>

                <!-- 不是强命名程序集,不用设置version,publicKeyToken…… -->

                <assemblyIdentity name="ClassLibrary1"/>

                <!-- 不是强命名程序集,不用设置version, 设置href指定文件位置 -->

                <codeBase href="file:///E:/Visual Studio 2010/Projects/Mgen/bin/Debug/dlls/ClassLibrary1.dll" />

            </dependentAssembly>

        </assemblyBinding>

    </runtime>

</configuration>



或者 app.xaml.cs里面加入:

public App() 
       { 
           this.Startup += new StartupEventHandler(App_Startup); 
       }

       void App_Startup(object sender, StartupEventArgs e) 
       { 
           var name = Assembly.GetExecutingAssembly().Location; 
           var path = Path.GetDirectoryName(name); 
           AppDomain.CurrentDomain.AppendPrivatePath(path+ @"\3rdDll"); 
       }

 

AppDomain.CurrentDomain.AppendPrivatePath 貌似过时了,AppDomainSetup 的使用方法没找到。

注意:3rdDll这个文件夹必须在 W:\Debug 的子目录或者更深一级的目录。

 

特殊需求:

F.dll 不在 W:\Debug 的子目录或者更深一级的目录,例如上一级目录;

或者exe的目录级别比dll的低一些,

用这个办法:

public App() 
       { 
           AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); 
       }

       System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
       { 
           var name = Assembly.GetExecutingAssembly().Location; 
           var path = Path.GetDirectoryName(Path.GetDirectoryName(name)); 
           var dllPath = path + @"\3rdDll\F.dll"; 
           return Assembly.LoadFrom(dllPath); 
       }


其它:

  要从程序集的元数据中获取程序集的信息,首先需要加载程序集。.Net中加载程序集方法有几种,本人结合自己的实践和认识简单介绍一下。描述不一定很准确,请提出来一起进步。

一、隐式加载
        没有被显式加载但被引用的程序集,CLR会按照全局程序集缓存(GAC)、工作目录(应用程序所在目录)以及私有路径目录的顺序来寻找并加载。

二、AppDomain.Load 方法
    将一个程序集加载到一个特定的程序域中,主要用来供非托管代码调用

三、Assembly.Load方法
    通过接受一个程序集标识来加载程序集。如果是强命名程序集,则标识包括程序集名称、版本、语言文化、以及公有密钥标记,Load方法将导致CLR按照隐式加载的策略寻找并加载程序集。弱命名程序集则只是一个不带文件扩展名的程序集的名称,CLR不会到GAC中查找,如果没有指定私有目录,则在工作目录查找,如Assembly.Load("Math")。其中私有目录的定义可以在配置文件中指定。如应用程序MyApp.exe的配置文件可以定义为MyApp.exe.config。内容:
    

  1.  <?xml version="1.0" encoding="utf-8" ?>
  2.     <configuration>
  3.        <runtime>
  4.           <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  5.              <probing privatePath="App;App1;" />
  6.           </assemblyBinding>
  7.        </runtime>
  8.     </configuration>

  

     其中App和App1是两个在工作目录下的目录,用probing定义,存放需要在这个目录下被加载的程序集。如果使用工作目录以外的目录下的程序集,则可以使用codeBase元素来定义,可以在MSDN上查找其属性内容。

四、Assembly.LoadFrom方法
    参数是包括程序集清单的文件的名称或路径,包括文件扩展名。如需要加载D:/App/math.dll,可以使用语句:
    Assembly a = Assembly.LoadFrom(@"D:/App/math.dll");
    a即是加载的程序集。
    但这种方法有缺点,在MSDN上有详细的描述,我自己遇到的一个问题是加载一个在非工作目录下的程序集后,在另一个程序集中使用这个程序集中的对象进行反序列化时失败。使用Assembly.Load方法或者将该程序集放在工作目录下后问题得以解决。

五、Assembly.LoadFile方法
    用来加载指定路径上的程序集文件的内容。使用 LoadFile 方法来加载和检查具有相同标识但位于不同路径中的程序集。与 LoadFrom 不同,LoadFile 不会将文件加载到 LoadFrom 上下文中,也不会使用加载路径解析依赖项。LoadFile 在这个受限制的方案中很有用,因为 LoadFrom 不能用于加载标识相同但路径不同的程序集;它只加载第一个这样的程序集。

六、Assembly.LoadWithPartialName方法
    使用部分名称从应用程序目录或从全局程序集缓存加载程序集。参数为程序集标识,其中包含程序集的名称(不带文件扩展名)。程序集的版本、语言文化及公用密钥标记为可选。该方法执行时CLR首先检查应用程序的XML配置文件来搜索qualifyAssembly元素,若存在则该元素应能告诉CLR如何将一个部分的程序集标识映射为完全限定的标识,CRL将根据通常规则来查找程序集。若该元素不存在,CRL将使用指定名称在应用程序的工作目录和私有路径目录中搜索。若仍未找到,则到GAC中查找。

七、传统VC动态库的调用
    通过 P/Invoke 调用Win32 DLL

    using System.Runtime.InteropServices;//这是用到DllImport时候要引入的程序集

    [DllImport("DBAccess.dll",CharSet=CharSet.Auto)]
    static extern ulong FindApp( bool bIsTrue );
    //声明外部的标准动态库,跟Win32API是一样的.



Over!

<think>好的,用户问的是在UG中如何实现鼠标移动到某个位置时显示图片。首先,我需要回忆一下UG(Unified Graphics,可能指Siemens NX)的功能和API。UG/NX主要使用C/C++和NX Open API进行二次开发,可能还需要用到.NET或Java API,具体取决于用户使用的版本和偏好。 首先,确定用户的需求是当鼠标悬停在特定位置时显示图片。这通常涉及到UI元素的动态显示,可能需要捕捉鼠标事件,比如鼠标移动事件,然后根据鼠标的位置触发显示图片的操作。 接下来,考虑UG/NX是否支持这样的交互。UG/NX的界面定制主要通过Menus、Toolbars、UI Styler等工具,但这些可能不足以直接实现动态的图片显示。可能需要使用更底层的API,比如利用.NET的Windows Forms或WPF集成,或者使用NX Open的UI组件。 然后,可能的步骤包括: 1. 创建自定义对话框或UI组件,用于显示图片。 2. 监听鼠标移动事件,获取当前鼠标位置。 3. 判断鼠标位置是否在目标区域内,如果是,则显示图片;否则隐藏。 需要注意的是,UG/NX的API可能没有直接提供鼠标移动事件的监听,因此可能需要通过回调函数或定时器轮询鼠标位置,但这可能会影响性能。另外,使用.NET的互操作性,在UG中嵌入Windows Forms控件可能是一种方法。 还要考虑图片的显示方式,比如使用透明窗口、浮动面板,或者直接在UG工作区中绘制。每种方法的实现难度不同,可能需要不同的API支持。 此外,需要检查是否有现成的NX Open函数可以获取鼠标位置或注册事件监听器。查阅NX Open文档,特别是UI相关的部,可能会有帮助。例如,NXOpen.UIStyler.Dialog和相关的控件类可能提供一些事件处理的方法。 最后,可能需要编写示例代码,演示如何创建对话框、注册事件和处理鼠标位置,然后将图片控件动态显示或隐藏。同时,需要处理可能的异常和性能问题,确保不影响UG的正常运行。 总结下来,可能的解决方案是结合NX Open API和.NET的UI功能,创建自定义对话框,监听鼠标事件,并在满足条件时更新图片显示。这需要一定的编程知识和对NX Open API的熟悉。</think>在UG/NX中实现鼠标悬停显示图片的功能,需要结合NX Open API进行二次开发。以下是步实现思路: 一、开发环境准备 1. 安装Visual Studio(建议2017+) 2. 配置NX Open开发环境 3. 引用必要的DLL: - NXOpen.dll - NXOpen.UF.dll - NXOpenUI.dll 二、核心代码实现(C#示例): ```csharp using NXOpen; using NXOpenUI; using System.Windows.Forms; public class HoverImage { private static PictureBox picBox; private static System.Windows.Forms.Timer timer; public static void Main() { Session theSession = Session.GetSession(); UI theUI = UI.GetUI(); // 创建透明窗体 Form overlayForm = new Form { FormBorderStyle = FormBorderStyle.None, BackColor = Color.Magenta, TransparencyKey = Color.Magenta, ShowInTaskbar = false, TopMost = true }; // 添加图片控件 picBox = new PictureBox { SizeMode = PictureBoxSizeMode.Zoom, Visible = false }; overlayForm.Controls.Add(picBox); // 设置定时器检测鼠标位置 timer = new System.Windows.Forms.Timer { Interval = 100 }; timer.Tick += (s, e) => CheckMousePosition(theSession, overlayForm); timer.Start(); theUI.NXMessageBox.Show("提示", MessageBoxButtons.OK, "悬停功能已激活"); } private static void CheckMousePosition(Session session, Form form) { try { Point mousePos = Control.MousePosition; form.Location = new Point(mousePos.X + 20, mousePos.Y + 20); // 坐标转换 Point3d modelPos = session.Preferences.View.ScreenToWorld( new Point3d(mousePos.X, mousePos.Y, 0)); // 碰撞检测逻辑 if (IsInTargetArea(modelPos)) { picBox.Image = Image.FromFile("preview.png"); picBox.Size = new Size(200, 150); picBox.Visible = true; } else { picBox.Visible = false; } } catch (Exception ex) { // 异常处理 } } private static bool IsInTargetArea(Point3d point) { // 实现您的区域检测逻辑 return (point.X > 50 && point.X < 100 && point.Y > 50 && point.Y < 100); } } ``` 三、关键技术要点 1. 坐标转换: $$ \text{屏幕坐标} \rightarrow \text{世界坐标} $$ 使用`ScreenToWorld()`方法实现坐标系转换 2. 碰撞检测算法: 建议使用R-Tree空间索引加速查询 $$ \text{查询时间复杂度} = O(\log n) $$ 3. 性能优化: - 设置合理的检测频率(建议50-100ms) - 使用空间区技术减少计算量 - 缓存常用图片资源 四、部署流程 1. 编译为.dll文件 2. 创建.men菜单文件 3. 修改ugii_env.dat添加路径 4. 重启UG生效 五、注意事项 1. 不同NX版本API可能有差异(测试时使用NX 12+) 2. 需要开启.NET Framework 4.6.1+支持 3. 高辨率屏幕需设置DPI感知 4. 建议添加异常处理防止程序崩溃 实际开发中,需要根据具体需求调整: - 图片显示位置偏移量 - 触发区域检测算法 - 图片加载策略 - 用户交互反馈机制 可通过NX Journal录制功能辅助调试,建议先在小范围测试后再全功能实施。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值