在大概知道流程之后,最重要的第一步。。。。。其实不在这个流程里。 是存在于Program.cs里的主程序入口。。。要防止程序多开!置顶已经打开的程序,弹出提醒。如果有错误,生成日志。
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Diagnostics; using System.Runtime.InteropServices; using System.Reflection; using System.Windows.Forms; using System.IO; namespace WebAAA { public static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { try { //处理未捕获的异常 Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); //处理UI线程异常 Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); //处理非UI线程异常 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); bool fuckingme; Process instance = RunningInstance(); System.Threading.Mutex webaaa = new System.Threading.Mutex(true, "lemonzdemon", out fuckingme); //if (instance == null) //{ if (fuckingme) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); webaaa.ReleaseMutex(); } else { HandleRunningInstance(instance); //MessageBox.Show("我已经运行啦~~", "主人您好:", MessageBoxButtons.OK, MessageBoxIcon.Information); } } catch (Exception ex) { string str = ""; string strDateInfo = "出现应用程序未处理的异常:" + DateTime.Now.ToString() + "\r\n"; if (ex != null) { str = string.Format(strDateInfo + "异常类型:{0}\r\n异常消息:{1}\r\n异常信息:{2}\r\n", ex.GetType().Name, ex.Message, ex.StackTrace); } else { str = string.Format("应用程序线程错误:{0}", ex); } writeLog(str); MessageBox.Show("发生程序错误,请把Errlog目录的文件发送给作者! \n\n Errlog.txt能帮助作者修复程序~\n\n作者邮箱:************@qq.com", "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } #region 确保程序只运行一个实例 private static Process RunningInstance() { Process current = Process.GetCurrentProcess(); Process[] processes = Process.GetProcessesByName(current.ProcessName); //遍历与当前进程名称相同的进程列表 foreach (Process process in processes) { //如果实例已经存在则忽略当前进程 if (process.Id != current.Id) { //保证要打开的进程同已经存在的进程来自同一文件路径 if (Assembly.GetExecutingAssembly().Location.Replace("//", "\\") == current.MainModule.FileName) { //返回已经存在的进程 return process; } } } return null; } private static void HandleRunningInstance(Process instance) { MessageBox.Show("我已经运行啦~~", "主人您好:", MessageBoxButtons.OK, MessageBoxIcon.Information); ShowWindowAsync(instance.MainWindowHandle, 1); //调用api函数,正常显示窗口 SetForegroundWindow(instance.MainWindowHandle); //将窗口放置最前端 } [DllImport("User32.dll")] private static extern bool ShowWindowAsync(System.IntPtr hWnd, int cmdShow); [DllImport("User32.dll")] private static extern bool SetForegroundWindow(System.IntPtr hWnd); #endregion static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { string str = ""; string strDateInfo = "出现应用程序未处理的异常:" + DateTime.Now.ToString() + "\r\n"; Exception error = e.Exception as Exception; if (error != null) { str = string.Format(strDateInfo + "异常类型:{0}\r\n异常消息:{1}\r\n异常信息:{2}\r\n", error.GetType().Name, error.Message, error.StackTrace); } else { str = string.Format("应用程序线程错误:{0}", e); } writeLog(str); MessageBox.Show("发生程序错误,请把Errlog目录的文件发送给作者! \n\n Errlog.txt能帮助作者修复程序~\n\n作者邮箱:**********@qq.com", "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { string str = ""; Exception error = e.ExceptionObject as Exception; string strDateInfo = "出现应用程序未处理的异常:" + DateTime.Now.ToString() + "\r\n"; if (error != null) { str = string.Format(strDateInfo + "Application UnhandledException:{0};\n\r堆栈信息:{1}", error.Message, error.StackTrace); } else { str = string.Format("Application UnhandledError:{0}", e); } writeLog(str); MessageBox.Show("发生程序错误,请把Errlog目录的文件发送给作者! \n\n Errlog.txt能帮助作者修复程序~\n\n作者邮箱:**********@qq.com", "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } /// 写文件 static void writeLog(string str) { if (!Directory.Exists("ErrLog")) { Directory.CreateDirectory("ErrLog"); } using (StreamWriter sw = new StreamWriter(@"ErrLog\ErrLog.txt", true)) { sw.WriteLine(str); sw.WriteLine("---------------------------------------------------------"); sw.Close(); } } } }
0x01-----------------------------主窗体
第一步完成后,我们就可以开始流程了。引用文件头就不说了,主函数开始我们主要做的就是控制窗体和内核浏览器。这里我想说的是,必须控制C#的版本和内核浏览器的版本,不然每台机器呈现的效果都不一样。 主窗口的样式定义,webBrowser控件样式的定义,程序的开始和结束动画,都是很好的氛围。主程序的背景图片主要用webBrowser覆盖,因为我一直选择用网页做程序的背景图片,除了离线模式的静态图,这样不但能随时更换,样式也多。
public Form1() { InitializeComponent(); AnimateWindow(this.Handle, 800, AW_BLEND + AW_CENTER + AW_ACTIVATE); this.MaximizeBox = false; this.AutoSizeMode = AutoSizeMode.GrowAndShrink; // 禁用手动调整大小。 this.SizeGripStyle = SizeGripStyle.Hide; // 隐藏调整大小手柄。 this.StartPosition = FormStartPosition.CenterScreen; // 在桌面居中显示。 webBrowser1.ScriptErrorsSuppressed = true; //禁用错误脚本提示 webBrowser1.IsWebBrowserContextMenuEnabled = false; //禁用右键菜单 webBrowser1.WebBrowserShortcutsEnabled = false; //禁用快捷键 webBrowser1.AllowWebBrowserDrop = false; //禁止拖拽 webBrowser1.ScrollBarsEnabled = false; //禁止滚动条 }
关闭窗口时渐隐效果(开头和结尾先弄好,程序启动可以新建窗体填充图片,新建窗体可见度逐渐为0,然后显示主窗体,可以做成广告):
private void MainForm_FormClosing(object sender, FormClosingEventArgs e) { AnimateWindow(this.Handle, 800, AW_BLEND + AW_SLIDE + AW_CENTER + AW_HIDE); Environment.Exit(Environment.ExitCode); } private void XFormMain_FormClosed(object sender, FormClosedEventArgs e) { //动态关闭窗体 AnimateWindow(this.Handle, 800, AW_SLIDE + AW_HIDE + AW_CENTER); }
0x02-----------------------------初始化
第二部申明各种常量和变量,引用WINAPI的DLL。 为之后使用基本的WINAPI做准备。
private string userAgent = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)";
[DllImport("urlmon.dll", CharSet = CharSet.Unicode)]
private static extern int UrlMkSetSessionOption(int dwOption, string pBuffer, int dwBufferLength, int dwReserved);
private const int UrlmonOptionUseragent = 0x10000001;
[DllImportAttribute("user32.dll")]
private static extern bool AnimateWindow(IntPtr hwnd, int dwTime, int dwFlags);
/*
1. AW_SLIDE : 使用滑动类型, 默认为该类型. 当使用 AW_CENTER 效果时, 此效果被忽略
2. AW_ACTIVE: 激活窗口, 在使用了 AW_HIDE 效果时不可使用此效果
3. AW_BLEND: 使用淡入效果
4. AW_HIDE: 隐藏窗口
5. AW_CENTER: 与 AW_HIDE 效果配合使用则效果为窗口几内重叠, 单独使用窗口向外扩展.
6. AW_HOR_POSITIVE : 自左向右显示窗口
7. AW_HOR_NEGATIVE: 自右向左显示窗口
8. AW_VER_POSITVE: 自顶向下显示窗口
9. AW_VER_NEGATIVE : 自下向上显示窗口
*/
public const Int32 AW_HOR_POSITIVE = 0x00000001;
public const Int32 AW_HOR_NEGATIVE = 0x00000002;
public const Int32 AW_VER_POSITIVE = 0x00000004;
public const Int32 AW_VER_NEGATIVE = 0x00000008;
public const Int32 AW_CENTER = 0x00000010;
public const Int32 AW_HIDE = 0x00010000;
public const Int32 AW_ACTIVATE = 0x00020000;
public const Int32 AW_SLIDE = 0x00040000;
public const Int32 AW_BLEND = 0x00080000;
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int Width, int Height, int flags);
[DllImport("user32.dll", CharSet = CharSet.Auto)] //设置窗体位置和高度
private static extern System.IntPtr GetForegroundWindow();
0x03-----------------------------功能函数
第三部开始写各种功能函数,因为是个人程序,代码不可能很多,没必要封装函数。这样写在一页的函数会让外人看起来很多,很复杂。。。很多年前老师也说太乱。。话没毛病。。但是。。你TM倒是来帮我写啊。。。所以不要管那些,自己清楚自己的函数在哪就行了。 毕竟日后开发的时候,自己知道在哪,改好了就完了。 你开发的时候很难把它开源,一旦开源你就没啥开发的动力了。
查找窗体函数:
class FindWindow { [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] //IMPORTANT : LPARAM must be a pointer (InterPtr) in VS2005, otherwise an exception will be thrown private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i); //the callback function for the EnumChildWindows private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter); //if found return the handle , otherwise return IntPtr.Zero [DllImport("user32.dll", EntryPoint = "FindWindowEx", CharSet = CharSet.Unicode)] private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); private string m_classname; // class name to look for private string m_caption; // caption name to look for private DateTime start; private int m_timeout;//If exceed the time. Indicate no windows found. private IntPtr m_hWnd; // HWND if found public IntPtr FoundHandle { get { return m_hWnd; } } private bool m_IsTimeOut; public bool IsTimeOut { get { return m_IsTimeOut; } set { m_IsTimeOut = value; } } // ctor does the work--just instantiate and go public FindWindow(IntPtr hwndParent, string classname, string caption, int timeout) { m_hWnd = IntPtr.Zero; m_classname = classname; m_caption = caption; m_timeout = timeout; start = DateTime.Now; FindChildClassHwnd(hwndParent, IntPtr.Zero); } private bool FindChildClassHwnd(IntPtr hwndParent, IntPtr lParam) { EnumWindowProc childProc = new EnumWindowProc(FindChildClassHwnd); IntPtr hwnd = FindWindowEx(hwndParent, IntPtr.Zero, m_classname, m_caption); if (hwnd != IntPtr.Zero) { this.m_hWnd = hwnd; // found: save it m_IsTimeOut = false; return false; // stop enumerating } DateTime end = DateTime.Now; if (start.AddSeconds(m_timeout) < end) { m_IsTimeOut = true; return false; } EnumChildWindows(hwndParent, childProc, IntPtr.Zero); // recurse redo FindChildClassHwnd return true;// keep looking } }
执行CMD:
public string executeCmd(string Command) { Process process = new Process { StartInfo = { FileName = " cmd.exe ", UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, CreateNoWindow = true } }; process.Start(); process.StandardInput.WriteLine(Command); process.StandardInput.WriteLine("exit"); process.WaitForExit(); string str = process.StandardOutput.ReadToEnd(); process.Close(); return str; }
防止网页跳转:
private void wB_MainBrowser_NewWindow(object sender, CancelEventArgs e) { e.Cancel = true; try { string url = this.webBrowser1.Document.ActiveElement.GetAttribute("href"); this.webBrowser1.Url = new Uri(url); } catch { } } private void SetAllWebItemblank(HtmlElementCollection items) { try { foreach (HtmlElement item in items) { if (item.TagName.ToLower().Equals("iframe", StringComparison.OrdinalIgnoreCase) == false) { try { item.SetAttribute("target", "_blank"); } catch { } } else { try { HtmlElementCollection fitems = item.Document.Window.Frames[item.Name].Document.All; this.SetAllWebItemblank(fitems); } catch { } } } } catch { } } private void SetAllWebItemSelf(HtmlElementCollection items) { try { foreach (HtmlElement item in items) { if (item.TagName.ToLower().Equals("iframe", StringComparison.OrdinalIgnoreCase) == false) { try { item.SetAttribute("target", "_self"); } catch { } } else { try { HtmlElementCollection fitems = item.Document.Window.Frames[item.Name].Document.All; this.SetAllWebItemSelf(fitems); } catch { } } } } catch { } }
对网页注入JS和CSS
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { if (webBrowser1.DocumentTitle.IndexOf("你网站的标题") > -1) { try { webBrowser1.WebBrowserShortcutsEnabled = true; string fixthat = @"background-color: #6CF; height: 400px; width: 600px; border: 1px solid #666; background-image: url(http://自己要用的网站,也是程序的背景, 此段也是控制主窗口的显示/backpic.aspx); background-repeat: no-repeat; position:absolute; left:50%; top:50%; margin-top:-200px; margin-left: -300px;"; HtmlElementCollection godlike = webBrowser1.Document.Body.All; string suckyou = @"<span id='suckyou' style='position: absolute;left: 6px;top: 6px;color:rgb(0, 0, 0);display: inline-block;width: 160px;white-space: nowrap;font-family:微软雅黑;font-size:16px;font-weight: bold;'>柠檬版Web :D</span>"; //你自己需要对网页注入的代码JS或者CSS foreach (HtmlElement X in godlike) { if (X.Parent.InnerText == "登录" || X.Parent.InnerText == "注销") { X.Parent.Parent.Parent.Style = fixthat; X.Parent.Parent.FirstChild.NextSibling.NextSibling.FirstChild.Style += "display:none"; //对网页子元素进行修改 X.Parent.Parent.FirstChild.NextSibling.NextSibling.FirstChild.OuterHtml += suckyou; } } }
0x04-----------------------------按钮功能
按钮功能根据自己的需求写吧,这里之做一个示范
private void button1_Click(object sender, EventArgs e) { HtmlElementCollection godlike = webBrowser1.Document.Body.All; string webaaaurl = @"http://链接的网址 this.webBrowser1.Navigate(webaaaurl); //导航到此 try // 这个是我当时写的读取配置文件 { string str1; FileStream fs = File.OpenRead(@"bootinfo.txt"); StreamReader sr = new StreamReader(fs); str1 = sr.ReadToEnd(); fs.Close(); string user = *******; string pwd = *******; foreach (HtmlElement X in godlike) { if (X.Parent.InnerText == "用户名:") { HtmlElement tbUserid = X.Parent.FirstChild.NextSibling; //查找元素 HtmlElement tbPasswd = X.Parent.NextSibling.FirstChild.NextSibling.NextSibling; tbUserid.SetAttribute("value", user); //设置用户名和密码 tbPasswd.SetAttribute("value", pwd); } } ListBoxLogs.AddCtrlValue(this, sysLogs, DateTime.Now.ToString("HH:mm:ss") + "-" + "Web客户端刷新完毕"); } catch (Exception) { MessageBox.Show("喵~ 貌似您的bootinfo.txt有问题 或者 网站又升级了喵~╮(╯▽╰)╭ !", "友善提示ing :"); } }
0x05-----------------------------其他
第五部主要是一些鸡肋的东西,比如测试的功能,和一些比较简单的功能写在这里。 能用就用,不用就放着或者注释掉。比如说打开CMD执行参数,POWERSHELL执行参数。
执行CMD
查找和向其他窗口传送按键Process.Start("explorer.exe", @"ftp://ftp.****.cn/");
System.Windows.Forms.Application.DoEvents();
FindWindow AAA = new FindWindow(IntPtr.Zero, null, "A客户端", 5); //查找其他窗口
FindWindow DL = new FindWindow(AAA.FoundHandle, null, "登陆", 800);
FindWindow ts = new FindWindow(IntPtr.Zero, null, "提示", 5);
FindWindow qd = new FindWindow(ts.FoundHandle, null, "确定", 5);
if (AAA.FoundHandle == IntPtr.Zero)
{
MessageBox.Show("客户端没打开", "你妹的:");
this.WindowState = FormWindowState.Minimized;
}
else if (DL.FoundHandle != IntPtr.Zero && ts.FoundHandle != IntPtr.Zero)
{
//关闭提示窗口
ShowWindow(ts.FoundHandle, 1); //显示找到的窗口
SendMessage(ts.FoundHandle, WM_SETFOCUS, 0, 0); //发送按键和消息
SendMessage(ts.FoundHandle, WM_CLOSE, 0, 0);
//链接客户端
ShowWindow(AAA.FoundHandle, 1);
SetWindowPos(AAA.FoundHandle, -1, 0, 0, 0, 0, 1 | 2);
SetForegroundWindow(DL.FoundHandle);
ShowWindowAsync(DL.FoundHandle, SW_RESTORE);
SendMessage(DL.FoundHandle, WM_SETFOCUS, 0, 0);
SendMessage(DL.FoundHandle, WM_LBUTTONDOWN, 0, 0);
}
系统延时:
private void Delay(int Millisecond) //延迟系统时间,但系统又能同时能执行其它任务; { DateTime current = DateTime.Now; while (current.AddMilliseconds(Millisecond) > DateTime.Now) { Application.DoEvents();//转让控制权 } return; }
0x06-----------------------------结尾
这几步写完了,程序就已经能正常使用了,但是C#的尴尬有很多,你写好的软件等于说源码送给别人,你不得不进行加密和混淆。 一般都是网上找的混淆软件,先加基本压缩壳,再进行混淆。 C#对网页的操作很棒,代码可读性很强。你需要知道JAVASCRIPT/CSS,正则匹配,读/提参数。 这样写出来的程序,最小化在窗口干别的就行了。 前期上学和工作期间,肯定有大用处。
[assembly: AssemblyTitle("Windows 服务主进程")] [assembly: AssemblyDescription("Windows 服务主进程")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Microsoft Corporation")] [assembly: AssemblyProduct("Microsoft® Windows® Operating System")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved. ")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] //很多年前连编译注释都给改了,防老师够了,哈哈。
之后网页的操作会渐渐对你没什么帮助,你需要搞数据库和WINAPI相关的东西。那是下一个层次。 比如说写病毒,爬虫,扫描之类的软件。 总而言之,通过这一套永久的复制粘贴,让你的程序迅速进入工作状态,前期打基础,为后面的底层操作打基础吧。
我记得之前有个人,用C#写了一个壳调用WINAPI搞内核软件什么,再也没有看见他发过。不知道软件是什么进度了,前不久AntiSpy开源了,也想看看那人后来怎么样了,反正C#真的好像一个躯壳,就像克隆人一样。希望这篇文章为那些初学者一些启发和指导作用吧。