//获取dll的绝对路径,请根据不同情况自己选用 MessageBox.Show(System.Reflection.Assembly.GetExecutingAssembly().Location); MessageBox.Show(System.Reflection.Assembly.GetEntryAssembly().Location); MessageBox.Show(System.Windows.Forms.Application.ExecutablePath); MessageBox.Show(System.Windows.Forms.Application.StartupPath); MessageBox.Show(System.Environment.CurrentDirectory); MessageBox.Show(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
Tag Archives: CSharp
C#枚举窗口句柄
在CS程序中启动其他应用后,要获取进程的主窗体其实很简单:
Process p = Process.Start(exePath); //p.WaitForInputIdle(); p.Refresh(); IntPtr mainWnd = p.MainWindowHandle;
但是,总有很多特殊的情况,上面的方法根本无法用,所以,要用Windows API来搞定了
1、如果窗口信息很固定而且没有重名的话,可以用Findwindow搞定
[DllImport("User32.dll", EntryPoint = "FindWindow")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); IntPtr clientWnd = FindWindow(null,"FormClient");
2、根据标题枚举窗口句柄
//枚举窗体 [DllImport("User32.dll", EntryPoint = "EnumWindows", SetLastError = true)] public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, uint lParam); //获取窗体标题 [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern int GetWindowText(IntPtr hWnd, StringBuilder lpText, int nCount); //设置错误状态 [DllImport("kernel32.dll", EntryPoint = "SetLastError")] public static extern void SetLastError(uint dwErrCode); //线程主窗口句柄 private static IntPtr processMainWnd = IntPtr.Zero; //要查找的窗口名称 private static String winTitle = "__Web__Form__Main__"; //声明委托函数 public delegate bool WNDENUMPROC(IntPtr hwnd, uint lParam); //枚举进程句柄,非线程安全 [SecuritySafeCritical] public static IntPtr GetCurrentWindowHandle() { IntPtr ptrWnd = IntPtr.Zero; bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), (uint)0); if (!bResult && Marshal.GetLastWin32Error() == 0) { ptrWnd = processMainWnd; } return ptrWnd; } //枚举函数,获取主窗口句柄然后退出 [SecuritySafeCritical] private static bool EnumWindowsProc(IntPtr hwnd, uint lParam) { //根据标题获取窗体 var sb = new StringBuilder(50); GetWindowText(hwnd, sb, sb.Capacity); if (winTitle.Equals(sb.ToString())) { processMainWnd = hwnd; SetLastError(0); return false; } return true; }
3、跟进进程id枚举获取主窗体句柄
//枚举窗体 [DllImport("User32.dll", EntryPoint = "EnumWindows", SetLastError = true)] //获取父窗体 [DllImport("user32.dll", EntryPoint = "GetParent", SetLastError = true)] //根据窗口获取线程句柄 [DllImport("User32.dll", CharSet = CharSet.Auto)] public static extern int GetWindowThreadProcessId(IntPtr hwnd, out uint pid); //设置错误状态 [DllImport("kernel32.dll", EntryPoint = "SetLastError")] public static extern void SetLastError(uint dwErrCode); //线程主窗口句柄 private static IntPtr processMainWnd = IntPtr.Zero; //枚举进程句柄 [SecuritySafeCritical] public static IntPtr GetCurrentWindowHandle(int processId) { IntPtr ptrWnd = IntPtr.Zero; bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), (uint)processId); if (!bResult && Marshal.GetLastWin32Error() == 0) { ptrWnd = processMainWnd; } return ptrWnd; } //枚举函数,获取主窗口句柄然后退出 [SecuritySafeCritical] private static bool EnumWindowsProc(IntPtr hwnd, uint lParam) { uint uiPid = 0; //根据启动方式不同,这里要有相应修改 if (GetParent(hwnd) == IntPtr.Zero) { GetWindowThreadProcessId(hwnd, out uiPid); if (uiPid == lParam) { processMainWnd = hwnd; SetLastError(0); return false; } } }
4、跟进窗口WindowsClassName举获取主窗体句柄
//查找桌面 [DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)] public static extern IntPtr GetDesktopWindow(); //获取窗体句柄 [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] public static extern IntPtr GetWindow(IntPtr hwnd, int wFlag); //获取窗体类 [DllImport("User32.dll", CharSet = CharSet.Auto)] public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); public const int GW_CHILD = 5; public const int GW_HWNDNEXT = 2; //枚举桌面窗口,根据WindowsClassName获取句柄 [SecuritySafeCritical] public static IntPtr GetWinHandleByClasName(String windowClassNmae) { //取得桌面窗口,再获取第一个子窗口 IntPtr hwnd = GetDesktopWindow(); hwnd = GetWindow((IntPtr)hwnd, System.Convert.ToInt32(GW_CHILD)); //通过循环来枚举所有的子窗口 while ((long)hwnd != 0) { System.Text.StringBuilder ClassName = new System.Text.StringBuilder(256); GetClassName((IntPtr)hwnd, ClassName, ClassName.Capacity); String tmpClassName= ClassName.ToString().Trim(); if (tmpClassName.Length > 0) { if (tmpClassName.Equals(windowClassNmae)) { break; } } hwnd = GetWindow((IntPtr)hwnd, System.Convert.ToInt32(GW_HWNDNEXT)); } return hwnd; }
使用WebBrower修改网页iFrame中的内容
由于很变态的中国式需求,我们需要在自己的网站中,嵌入第三方厂商的网站。
而这个第三方的网站中,使用了几层的iFrame,同时使用了基于IE的Activex控件。
由于双方的控件风格差距太大,所以需要替换CSS样式,同时要删掉部分与我们网站冲突的内容。
想了几种方法:
1、说服对方进行调整,但经过接触,了解到其超级不靠谱,只能靠自己了。
2、直接通过iFrame嵌入对方网站,用JS进行修改。可是跨站修改,浏览器不同意啊。
3、自己写个控件,嵌入到自己网页中,在控件中调用对方URL,并通过WebBrowser控件修改CSS及HTML。问题是,IE中,不能再直接嵌入一个WebBrowser控件,主要出于安全考虑。(如果IE允许这样操作的话,我只需要在WebBrowser中指向同一个URL,就可以无限调用,耗光资源,其他的事情,有太多可以做了)自己用很挫的方法实现了这个功能,后来考虑到稳定性,放弃了。
4、使用非基于IE的Web插件,在控件中调用对方URL,并通过控件修改CSS及HTML。比如Flash或者CefSharp,但问题是,非IE核心如何调用Activex控件啊。
5、限制入口,基于WebBrowser定制IE浏览器
最后使用了方法5,说实话,真烦。
这里把通过WebBrowser修改CSS及HTML的方法说一下,下面是我写的一段测试用代码,请按自己的实际情况修改:
//替换样式 //webMain是WebBrowser控件的名称 //NewStyle.css中是要替换的样式 private void modifyStyle() { int frameNum = webMain.Document.Window.Frames.Count; if (frameNum == 2) { IHTMLDocument2 leftIFrame = webMain.Document.Window.Frames[0].Document.DomDocument as IHTMLDocument2; int length = leftIFrame.styleSheets.length; IHTMLStyleSheet styleSheet = leftIFrame.createStyleSheet(@"", length + 1); TextReader reader = new StreamReader(Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "NewStyle.css")); string style = reader.ReadToEnd(); styleSheet.cssText = style; } } //删除tree节点下的div,只保留特定的一个节点 private void delDiv(String flowid) { int frameNum = webMain.Document.Window.Frames.Count; if (frameNum == 2) { IHTMLDocument3 leftIFrame = webMain.Document.Window.Frames[0].Document.DomDocument as IHTMLDocument3; foreach (dynamic e in leftIFrame.getElementById("tree").children) { String ret = e.InnerText; if (!ret.Contains(flowid)) { e.parentNode.removeChild(e); } } } }
如何在WinForm程序中测试C#写的COM控件
在网上查了一下,应该是不能直接在WinForm中使用C#写的COM控件。
但可以用变通的方法测试COM控件中的方法,比如,下面的例子中,就可以测试addTest方法:
Type comType = null; object comObject = null; //这个无效,不知道为什么 //comType = Type.GetTypeFromProgID("XX.CSControl.TestControl"); if (comType == null) { Guid guid = new Guid("4B4D1D4C-16CA-48E0-87A4-AFF3C6CB6E26"); comType = Type.GetTypeFromCLSID(guid); } try { comObject = Activator.CreateInstance(comType); } catch(Exception e) { MessageBox.Show(e.Message); return; } object[] args = new object[2]; args[0] = 1; args[1] = 2; int ret = (int)comType.InvokeMember("addTest", BindingFlags.InvokeMethod, null, comObject, args); if(ret==3) { MessageBox.Show("TestOK"); }
C#开发COM组件(Web)
这两天由于一个很挫的需求,准备开发一个COM组件,由于所有用户的客户端都安装有.Net Framework 4.0,加上工期紧的很,就准备用C#上了。
1、首先,建立一个Windows Forms Control Library项目
2、项目属性,Build,选中,Register for COM interop
3、项目属性,Signing,选中,Sign the assembly,并生成一个签名文件
4、编辑AssemblyInfo.cs,查看是否有下面两行,没有要添加
using System.Security; [assembly: AllowPartiallyTrustedCallers()] [assembly: ComVisible(true)]
5、添加接口文件IObjectSafety.cs
using System; using System.Runtime.InteropServices; namespace CSControl { //不要修改GUID [ComImport] [Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IObjectSafety { [PreserveSig] int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions); [PreserveSig()] int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions); } }
6、控件类要同时实现UserControl, IObjectSafety两个接口
using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Reflection; using System.IO; using System.Diagnostics; using System.Threading; using System.Security; namespace CSControl { //更改为你自己的UUID [ComVisible(true)] [Guid("4B4D1D4C-16CA-48E0-87A4-AFF3C6CB6E26")] [ProgId("XX.CSControl.TestControl")] public partial class TestControl : UserControl, IObjectSafety { //=================================================== //实现IObjectSafety接口 //不要修改下面的GUID private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}"; private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}"; private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}"; private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}"; private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}"; private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001; private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002; private const int S_OK = 0; private const int E_FAIL = unchecked((int)0x80004005); private const int E_NOINTERFACE = unchecked((int)0x80004002); private bool _fSafeForScripting = true; private bool _fSafeForInitializing = true; public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions) { int Rslt = E_FAIL; string strGUID = riid.ToString("B"); pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA; switch (strGUID) { case _IID_IDispatch: case _IID_IDispatchEx: Rslt = S_OK; pdwEnabledOptions = 0; if (_fSafeForScripting == true) pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER; break; case _IID_IPersistStorage: case _IID_IPersistStream: case _IID_IPersistPropertyBag: Rslt = S_OK; pdwEnabledOptions = 0; if (_fSafeForInitializing == true) pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA; break; default: Rslt = E_NOINTERFACE; break; } return Rslt; } public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions) { int Rslt = E_FAIL; string strGUID = riid.ToString("B"); switch (strGUID) { case _IID_IDispatch: case _IID_IDispatchEx: if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true)) Rslt = S_OK; break; case _IID_IPersistStorage: case _IID_IPersistStream: case _IID_IPersistPropertyBag: if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true)) Rslt = S_OK; break; default: Rslt = E_NOINTERFACE; break; } return Rslt; } //=================================================== //实现UserControl接口 ...... } }
7、编译,控件会自动注册
8、写个网页,测试一下
<!--CSControl--> <object id="testControl" width="500" height="500" classid ="clsid:4B4D1D4C-16CA-48E0-87A4-AFF3C6CB6E26"]</object>
9、打CAB包,发布到网站
由于是自己生产的签名文件,所以会有安全提示。最简单的方法是从靠谱的CA那里买一个证书,还有办法就是将证书导入到IE的信任列表中,再就是将IE的安全级别降为最低。
10、当然也可以通过命令行本地注册
rem 注册 regtlibv12 %PATH_TO_DLL_AND_TLB_FOLDER%\CSControl.tlb rem 反注册 regtlibv12 -u %PATH_TO_DLL_AND_TLB_FOLDER%\CSControl.tlb
C#开发COM组件(本地)
本篇文章介绍了如何用C#写一个简单的COM组件(Dll)。
1、新建一个C# Class Library项目“CSCOMTest”
2、项目中,新增一个接口文件IJustATestCOM.cs,Guid要自己生成
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; namespace CSCOMTest { [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsDual)] [Guid("A5377871-3334-4679-A3CD-84312B1DCD3E")] public interface IJustATestCOM { int Add(int a, int b); String SayHiTo(String someOne); } }
3、项目中,新增一个类文件JustATestCOM.cs,Guid要自己生成
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; namespace CSCOMTest { [ComVisible(true)] [Guid("A6E4F456-32C1-4C8E-9171-D616B5DA1E20")] [ProgId("CSCOMTest.JustATestCOM")] public class JustATestCOM : IJustATestCOM { public int Add(int a, int b) { return a + b; } public String SayHiTo(String someOne) { return "Hi " + someOne + "!"; } } }
4、项目属性->Application->Assembly Infomation->Make Assembly COM-Visible->打勾
5、项目属性->Signing->Sign the assembly->打勾
项目属性->Signing->Choose a strong name key file->New
6、编译
7、注册
#这里一定要用正确版本的gacutil及RegAsm C:\VBS\DNFW4\gacutil.exe /i CSCOMTest.dll C:\VBS\DNFW4\RegAsm.exe CSCOMTest.dll
8、反注册
#这里一定要用正确版本的gacutil及RegAsm C:\VBS\DNFW4\gacutil.exe /u CSCOMTest C:\VBS\DNFW4\RegAsm.exe /u CSCOMTest.dll
9、调用测试
'发生错误时,继续运行 On Error Resume Next '清除错误状态 Err.Clear Set Obj=CreateObject("CSCOMTest.JustATestCOM") '输出错误信息 If Err.Number <> 0 Then WScript.Echo "Error: " & Err.Number WScript.Echo "Error (Hex): " & Hex(Err.Number) WScript.Echo "Source: " & Err.Source WScript.Echo "Description: " & Err.Description 'Err.Clear '退出程序 WScript.Quit(Err.Number) End If 'On Error Goto 0 WScript.Echo obj.Add(1,2) WScript.Echo obj.SayHiTo("dcom") set obj=Nothing
10、生成tlb文件
regasm CSCOMTest.dll /tlb:CSCOMTest.tlb
IIS7.5不支持.Net4.0
由于先安装了.Net 4.0,然后才启用IIS7.5,导致IIS只支持.NET 2.0。
这时,需要手工向IIS注册一下.Net 4.0。
"%WINDIR%\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe" -iru -enable
如何手工下载VS2013的NuGet插件包
其实很简单啦,用包的id和包的版本,拼装出下面的URL,即可
https://www.nuget.org/api/v2/package/{packageID}/{packageVersion}
如:cef.sdk.3.1650.1562-pre2.nupkg,就可以这样下载:
https://www.nuget.org/api/v2/package/cef.sdk/3.1650.1562-pre2
那如何浏览呢,就是个Zip啦,随便找个压缩文件搞定
WSDL生成代码
1、axis2 java
rem axis2 生成client代码 wsdl2java -uri file:///C:/Users/Hansen/Desktop/test.wsdl
rem axis2 生成server代码 wsdl2java -ss -uri file:///C:/Users/Hansen/Desktop/test.wsdl
2、cxf java
rem jaxws2.2 生成代码 wsdl2java -p com.neohope -d src -all PATH_TO_WSDL
rem jaxws2.1 生成代码 wsdl2java -frontend jaxws21 -p com.neohope -d src -all PATH_TO_WSDL
3、wsdl soap csharp
rem cs生成client代码 wsdl C:/Users/Hansen/Desktop/test.wsdl
rem cs生成server代码 wsdl /serverInterface C:/Users/Hansen/Desktop/test.wsdl
4、svcutil wcf csharp
svcutil.exe http://localhost:1168/Service1.xamlx?wsdl /out:MyService.cs /config:app.config
使用时,WCF服务端直接实现服务接口即可。
WCF客户端,将app.config文件拷贝到项目中,然后直接调用代理类中的方法即可。
.Net4的WinForm程序使用.Net2控件
在.Net4的WinForm程序中,混用.Net2控件会报下面的问题
Mixed mode assembly is built against version 'v2.0.50727' of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.
解决方法为在App.config文件中,增加以下配置
<configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> </configuration>